What are the solutions for wrapping a C-style `static const` global constant in Rust using Bindgen? - c

I am creating Rust bindings for a C library that defines lists of standard constant default values:
// C
typedef struct RMW_PUBLIC_TYPE rmw_qos_profile_t
{
size_t depth;
enum rmw_qos_reliability_policy_t reliability;
// ...
} rmw_qos_profile_t;
enum RMW_PUBLIC_TYPE rmw_qos_reliability_policy_t
{
RMW_QOS_POLICY_RELIABILITY_RELIABLE,
RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
// ...
};
// Global value that needs wrapping
static const rmw_qos_profile_t rmw_qos_profile_sensor_data =
{
5,
RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
// ...
};
Using Bindgen, static Rust variables are generated:
// Rust
extern "C" {
#[link_name = "\u{1}rmw_qos_profile_sensor_data"]
pub static rmw_qos_profile_sensor_data: rmw_qos_profile_t;
}
but static global variables are highly inconvenient to work with in Rust, having to encase every access in an unsafe {} block. Especially when you do not need mutability.
I already wrapped the struct and enums in Rust:
// Rust
pub enum QoSReliabilityPolicy {
Reliable = 0,
BestEffort = 1,
}
impl From<rmw_qos_reliability_policy_t> for QoSReliabilityPolicy {
fn from(raw: rmw_qos_reliability_policy_t) -> Self {
match raw {
rmw_qos_reliability_policy_t::RMW_QOS_POLICY_RELIABILITY_RELIABLE => QoSReliabilityPolicy::Reliable,
rmw_qos_reliability_policy_t::RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT => QoSReliabilityPolicy::BestEffort,
}
}
}
pub struct QoSProfile {
pub depth: usize,
pub reliability: QoSReliabilityPolicy,
// ...
}
impl From<rmw_qos_profile_t> for QoSProfile {
fn from(qos_profile: rmw_qos_profile_t) -> Self {
QoSProfile {
depth: qos_profile.depth,
reliability: qos_profile.reliability.into(),
// ...
}
}
}
impl From<rmw_qos_profile_t> for QoSProfile {
fn from(qos_profile: rmw_qos_profile_t) -> Self {
QoSProfile {
depth: qos_profile.depth,
reliability: qos_profile.reliability.into(),
// ...
}
}
}
Now, I am looking for a solution to expose the same pre-defined profiles, such as rmw_qos_profile_sensor_data, to my Rust users without having to duplicate the C values manually in Rust.
Currently I am duplicating the C code in Rust:
// Rust
// Works but unsatisfying
pub const QOS_PROFILE_SENSOR_DATA: QoSProfile = QoSProfile {
depth: 5,
reliability: QoSReliabilityPolicy::BestEffort,
// ...
};
But this is not satisfying. When the upstream C library updates these values, users will experience inconsistent behaviour and bugs.
What are the possible solutions for conveniently wrapping these global constants ?
The ideal solution would:
Automatically update the values when the upstream C library changed
Expose global consts so that these values can be inlined by the compiler
If not possible, expose global immutable variables
If still not possible, at least not require unsafe
The problem that I have been facing is that, since static const C structures are stored in memory, they can't ben translated into a const so easily and this is probably why Bindgen translates it using the static keyword.
So, the possibilities that I can imagine, but don't know how to execute, are:
Have smarter parsing of the C code to generate Rust code ?
Use some form of macro ?
Initialize from the C lib's static memory in the prelude ?
Initialize from the C lib's static memory explicitly ?
Other solutions ?

Related

Pass an initialized Rust struct to C and call a rust function from C with the struct as input

I have built a library in Rust and my goal is to run it parallel with a Sat Solver (built in C) and make these two exchange information. The database (where information is received, stored and sent) is in Rust.
My problem is that I need to pass the Receiver from crossbeam channel from Rust to C and from the C program call the function receive (which takes as input the Receiver struct). The function receive is then executed in my Rust code.
I have programmed the structs and function in Rust:
use crossbeam_channel::Receiver;
use std::boxed::Box;
#[repr(C)]
pub struct CReceiver(Receiver<Vec<i32>>);
impl CReceiver {
fn new(receiver: Receiver<Vec<i32>>) -> CReceiver {
CReceiver(receiver)
}
}
#[no_mangle]
pub extern "C" fn data_new(creceiver: CReceiver) -> *mut CReceiver {
Box::into_raw(Box::new(creceiver))
}
#[no_mangle]
pub extern "C" fn data_free(ptr: *mut CReceiver) {
if ptr.is_null() {
return;
}
unsafe {
Box::from_raw(ptr);
}
}
#[no_mangle]
pub extern "C" fn receive(ptr: *mut CReceiver) -> Vec<i32> {
unsafe {
let creceiver = Box::from_raw(ptr);
match creceiver.0.try_recv() {
Ok(received) => received,
Err(_) => Vec::new() // glucose can handle empty clauses
}
}
}
I am trying to wrap the Receiver in a CReceiver struct to be able to pass it over to C. When I try to generate the header with cbindgen I get:
WARN: Cannot find a mangling for generic path GenericPath { path: Path { name: "Receiver" }, export_name: "Receiver", generics: [Type(Path(GenericPath { path: Path { name: "Vec" }, export_name: "Vec", generics: [Type(Primitive(Integer { zeroable: true, signed: true, kind: B32 }))], ctype: None }))], ctype: None }. This usually means that a type referenced by this generic was incompatible or not found.
WARN: Can't find Vec. This usually means that this type was incompatible or not found.
WARN: Can't find Receiver. This usually means that this type was incompatible or not found.
IMPORTANT: I need to initialise the receiver in Rust and then pass it to C as the whole channel (together with the sender) is initialised and needed.

How can I get the largest element from array, using generics and traits?

I just started learning rust and I'm creatively trying somethings as I read "the Rust Book".
I know it is possible to create a generic method to get the largest element from an array, like the following:
fn largest<T: PartialOrd + Copy> (nums: &[T]) -> T {
let mut largest = nums[0];
for &el in nums {
if el > largest {
largest = el;
}
}
return largest;
}
And calling the main function like this:
fn main() {
let list: Vec<u32> = vec![1,7,4];
println!("{}", largest(&list)); // 7
}
How would I go doing the same thing but "extending" the array, like this:
fn main() {
let list: Vec<u32> = vec![1,7,4];
println!("{}", list.largest()); // 7
}
I guess the final question is: if it is possible, would it be a bad practice? Why?
I tried something like this, but didn't manage to figure out how to implement the "Largeble" trait returning the T:
pub trait Largeble {
fn largest(&self);
}
impl<T: Copy + PartialOrd + Display> Largeble for Vec<T> {
fn largest(&self) {
let mut largest = match self.get(0) {
Some(&el) => el,
None => panic!("Non Empty array expected")
};
for &el in self {
if el > largest {
largest = el;
}
}
println!("{}", largest);
// return largest;
}
}
You need to make the Largeable trait return a T from the Vec<T>, which you can do with an associated type:
use std::fmt;
pub trait Largeble {
type Output;
fn largest(&self) -> Self::Output;
}
impl<T: Copy + PartialOrd + fmt::Display> Largeble for Vec<T> {
type Output = T;
fn largest(&self) -> T {
let mut largest = match self.get(0) {
Some(&el) => el,
None => panic!("Non Empty array expected")
};
for &el in self {
if el > largest {
largest = el;
}
}
largest
}
}
println!("{}", vec![1, 2, 3, 2].largest()); // prints "3"
Traits like Largeable are usually called extension traits, since they extend existing items with new features. Using extension traits to extend items in existing libraries is common in the Rust ecosystem. It's common to suffix the names of extensions with Ext (so a collection of additional methods for Vec would be called VecExt). A popular use of extension traits is the itertools library, which provides a trait that adds additional useful methods to Iterator in the standard library.
How would I go doing the same thing but "extending" the array
Sure, your code snippet was close, you can create a trait and implement it on types.
pub trait Largeble<T>
where
T: Ord,
{
fn largest(&self) -> Option<&T>;
}
impl<T> Largeble<T> for Vec<T>
where
T: Ord,
{
fn largest(&self) -> Option<&T> {
// Iterator already has a method for getting max which simplifies things
self.iter().max()
}
}
Alternatively, you can make T an associated type which may be better suited to this example.
You can run this code in the Rust Playground.
Would it be a bad practice? Why?
Nope, it's definitely not bad practise. It is a very common way to developing in Rust and can be very powerful. Your trait needs to be in scope for you to be able to call .largest(), so it does not pollute anything.
Additionally, if you have multiple methods with the same name from different traits, you can provide a longer syntax to specify the exact trait you want to use: Largest::<u32>::largest(&list).
I tried something like this, but didn't manage to figure out how to implement the "Largeble" trait returning the T.
Your code was mostly correct, but your largest method didn't return anything. That's why the trait needs a generic T, to specify that you will return T.

How to create a static array of objects that implement a common trait?

I am trying to create a static array of objects that implement a common trait. All these structs and their sizes are known at compile time. But when accessing a field defined on the struct the compiler tells me that the field is not on the type.
fn main() {
for &thing in ALL_THINGS {
println!("{}", thing.name)
}
}
trait Thing: Sync { }
struct SpecificThing {
name: &'static str
}
impl Thing for SpecificThing { }
static ALL_THINGS: &'static [&dyn Thing] = &[&SpecificThing {name: "test"}];
error[E0609]: no field `name` on type `&dyn Thing`
--> src/main.rs:3:30
|
3 | println!("{}", thing.name)
| ^^^^
Example:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=28a29e98cadf97edb8d4ec61703e8959
The questions static array of trait objects, Create vector of objects implementing a trait in Rust, Can I have a static borrowed reference to a trait object? or Vector of objects belonging to a trait doesn't help with explaining why this happens or how to resolve it.
Please what am I doing wrong here? Is there a better method to solve this task that I have not found yet?
When you define &dyn Thing, you erase all the information about specific data type. That means you can't access fields of dinamically dispatched objects.
Just imagine that you have two different structs in ALL_THINGS:
struct SpecificThing {
name: &'static str
}
struct SpecificAnotherThing {
no_name: &'static str
}
static ALL_THINGS: &'static [&dyn Thing] = &[&SpecificThing {name: "test"}, &SpecificAnotherThing { no_name: "" }];
You can't access name field because trait Thing know nothing about concrete types it implemented for. Therefore you can't access it's fields directly.
If you really need it, you should define a method in Thing trait which will return value you need:
trait Thing: Sync {
fn name(&self) -> &str;
}
// ...
// ...
impl Thing for SpecificThing {
fn name(&self) -> &str {
self.name
}
}
Or you can use static dispatching and algebraic data types (enum).
You can't access SpecificThing.name from a &dyn Thing since not all Things have a name field (ignoring the fact that traits don't have fields).
Your use of dyn Thing suggests you have a set of objects (structs/enums) that have some things in common. All these commonalities must be present in Thing for you to access them. For example, if a name is a common thing, you could add a function that gets the name:
fn main() {
for &thing in ALL_THINGS {
println!("{}", thing.get_name())
}
}
trait Thing: Sync {
fn get_name(&self) -> &'static str;
}
struct SpecificThing {
name: &'static str
}
impl Thing for SpecificThing {
fn get_name(&self) -> &'static str {
self.name
}
}
static ALL_THINGS: &'static [&dyn Thing] = &[&SpecificThing {name: "test"}];

How can I return a Chain iterator with data added from a temporary array?

I'm writing a MQTT5 library. To send a packet, I need to know the size of the payload before writing the payload. My solution for determining the size has the following constraints order by importance:
be easy to maintain
should not create copies of the data
should be fairly performant (avoid double calculations)
To determine the size I can do any of the following solutions:
do the calculations by hand, which is fairly annoying
hold a copy of the data to send in memory, which I want to avoid
Build an std::iter::ExactSizeIterator for the payload which consists of std::iter::Chains itself, which leads to ugly typings fast, if you don't create wrapper types
I decided to go with version 3.
The example below shows my try on writing a MQTT String iterator. A MQTT String consists of two bytes which are the length of the string followed by the data as utf8.
use std::iter::*;
use std::slice::Iter;
pub struct MQTTString<'a> {
chain: Chain<Iter<'a, u8>, Iter<'a, u8>>,
}
impl<'a> MQTTString<'a> {
pub fn new(s: &'a str) -> Self {
let u16_len = s.len() as u16;
let len_bytes = u16_len.to_be_bytes();
let len_iter = len_bytes.iter(); // len_bytes is borrowed here
let s_bytes = s.as_bytes();
let s_iter = s_bytes.iter();
let chain = len_iter.chain(s_iter);
MQTTString { chain }
}
}
impl<'a> Iterator for MQTTString<'a> {
type Item = &'a u8;
fn next(&mut self) -> Option<&'a u8> {
self.chain.next()
}
}
impl<'a> ExactSizeIterator for MQTTString<'a> {}
pub struct MQTTStringPait<'a> {
chain: Chain<std::slice::Iter<'a, u8>, std::slice::Iter<'a, u8>>,
}
This implementation doesn't compile because I borrow len_bytes instead of moving it, so it'd get dropped before the Chain can consume it:
error[E0515]: cannot return value referencing local variable `len_bytes`
--> src/lib.rs:19:9
|
12 | let len_iter = len_bytes.iter(); // len_bytes is borrowed here
| --------- `len_bytes` is borrowed here
...
19 | MQTTString { chain }
| ^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
Is there a nice way to do this? Adding len_bytes to the MQTTString struct doesn't help. Is there a better fourth option of solving the problem?
The root problem is that iter borrows the array. In nightly Rust, you can use array::IntoIter, but it does require that you change your iterator to return u8 instead of &u8:
#![feature(array_value_iter)]
use std::array::IntoIter;
use std::iter::*;
use std::slice::Iter;
pub struct MQTTString<'a> {
chain: Chain<IntoIter<u8, 2_usize>, Copied<Iter<'a, u8>>>,
}
impl<'a> MQTTString<'a> {
pub fn new(s: &'a str) -> Self {
let u16_len = s.len() as u16;
let len_bytes = u16_len.to_be_bytes();
let len_iter = std::array::IntoIter::new(len_bytes);
let s_bytes = s.as_bytes();
let s_iter = s_bytes.iter().copied();
let chain = len_iter.chain(s_iter);
MQTTString { chain }
}
}
impl<'a> Iterator for MQTTString<'a> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
self.chain.next()
}
}
impl<'a> ExactSizeIterator for MQTTString<'a> {}
You could do the same thing in stable Rust by using a Vec, but that'd be a bit of overkill. Instead, since you know the exact size of the array, you could get the values and chain more:
use std::iter::{self, *};
use std::slice;
pub struct MQTTString<'a> {
chain: Chain<Chain<Once<u8>, Once<u8>>, Copied<slice::Iter<'a, u8>>>,
}
impl<'a> MQTTString<'a> {
pub fn new(s: &'a str) -> Self {
let u16_len = s.len() as u16;
let [a, b] = u16_len.to_be_bytes();
let s_bytes = s.as_bytes();
let s_iter = s_bytes.iter().copied();
let chain = iter::once(a).chain(iter::once(b)).chain(s_iter);
MQTTString { chain }
}
}
impl<'a> Iterator for MQTTString<'a> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
self.chain.next()
}
}
impl<'a> ExactSizeIterator for MQTTString<'a> {}
See also:
How to implement Iterator and IntoIterator for a simple struct?
An iterator of &u8 is not a good idea from the point of view of pure efficiency. On a 64-bit system, &u8 takes up 64 bits, as opposed to the 8 bits that the u8 itself would take. Additionally, dealing with this data on a byte-by-byte basis will likely impede common optimizations around copying memory around.
Instead, I'd recommend creating something that can write itself to something implementing Write. One possible implementation:
use std::{
convert::TryFrom,
io::{self, Write},
};
pub struct MQTTString<'a>(&'a str);
impl MQTTString<'_> {
pub fn write_to(&self, mut w: impl Write) -> io::Result<()> {
let len = u16::try_from(self.0.len()).expect("length exceeded 16-bit");
let len = len.to_be_bytes();
w.write_all(&len)?;
w.write_all(self.0.as_bytes())?;
Ok(())
}
}
See also:
How do I convert between numeric types safely and idiomatically?
Converting number primitives (i32, f64, etc) to byte representations

Prevent 'static lifetime requirement in Rc<Trait>

Where is the 'static lifetime requirement coming from when using a trait type in std::rc::Rc and how can I prevent it? E.g. when trying to compile this code
trait Handler{}
fn add(a: std::rc::Rc<Handler>) {
}
fn main() {
add(0);
}
rust reports
error[E0308]: mismatched types
--> test.rs:7:9
...
= note: expected type `std::rc::Rc<Handler + 'static>`
found type `{integer}`
NOTE: the error itself is expected; I am just interested in the Handler + 'static diagnostic output. The Real program creates instances of a trait type, stores them into a HashMap and runs a type specific function on it. It fails to compile with
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
at this place.
Second example
The following code is more real-world and demonstrates the issue perhaps better:
trait Handler {
}
struct SomeHandler<'a>(&'a u32);
impl <'a> SomeHandler<'a> {
fn new(a: &'a u32) -> std::rc::Rc<Handler> {
std::rc::Rc::new(SomeHandler(a))
}
}
impl <'a> Handler for SomeHandler<'a> {
}
fn main() {
let a: u32;
SomeHandler::new(&a);
}
It fails with
8 | std::rc::Rc::new(SomeHandler(a))
| ^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::rc::Rc<Handler + 'static>
found std::rc::Rc<Handler>
Why explicit lifetimes do not work
The simple demo might be fixed by adding an explicit lifetime (e.g. Rc<Handler + 'a>). Unfortunately, this is not an option (nor trying to make anything 'static) because real code is intended to look like
struct PollRegistry {
...
handlers: std::collections::HashMap<mio::Token, std::rc::Weak<PollHandler>>,
}
impl PollRegistry {
fn register<'a>(&mut self, handler: &std::rc::Rc<PollHandler>,
interest: mio::Ready, opts: mio::PollOpt)
-> std::io::Result<()> {
....
self.handlers.insert(token, std::rc::Rc::downgrade(handler));
}
}
and methods in PollHandler specializations create and own other PollHandler specializations which are registered in the registry by these methods.
rustc 1.27.1

Resources