how to use nix::mount::mount() replace with libc::mount() in Rust - rust

I want to use the 'nix' library to replace with 'libc' in Rust FFI .
I want to use nix::mount::mount() to replace with libc::mount(). Now I have the followed code :
libc::mount(ptr::null(), path.as_ptr(), ptr::null(), libc:: MS_SLAVE, ptr::null())
I just want to know how to replace the ptr::null() in nix library, I try to use 'None' to do it, but failed. Please help me, thanks.
Show the error:
39 | nix::mount::mount(
| ^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `P1` declared on the function `mount`
|
::: /root/.cargo/registry/src/mirrors.ustc.edu.cn-15f9db60536bad60/nix-0.19.0/src/mount.rs:57:27
|
57 | pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?Sized + NixPath>(
| ------- required by this bound in `nix::mount::mount`
|
= note: cannot satisfy `_: nix::NixPath`

nix::mount::mount has the function signature:
pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?Sized + NixPath>(
source: Option<&P1>,
target: &P2,
fstype: Option<&P3>,
flags: MsFlags,
data: Option<&P4>
) -> Result<()>
As you can see, the arguments source, fstype and data take options of generic type parameter. If you pass in Some(value), these type parameters can be inferred based on the type of value, but if you pass in None, the compiler doesn't have enough information to infer a type for these parameters.
You can explicitly specify the type of the parameters to be some type that implements NixPath, such as Path:
nix::mount::mount<Path, Path, Path, Path>(None, path, None, MsFlags::MS_SLAVE, None)
Or you can specify a type parameter directly on None:
nix::mount::mount(None::<Path>, path, None::<Path>, MsFlags::MS_SLAVE, None::<Path>)

Related

Why does &i32 sometimes implement Unpin and sometimes not?

use std::pin::Pin;
fn main() {
let val: i32 = 3;
let val_pin = Pin::new(&val);
f(val_pin);
f(Pin::new(&val));
}
fn f(_val: Pin<&dyn TestTrait>) {}
trait TestTrait {}
impl TestTrait for i32 {}
Line 9 f(Pin::new(&val)); throws a compiler error, but line 6 let val_pin = Pin::new(&val); does not. The compiler error is:
error[E0277]: `dyn TestTrait` cannot be unpinned
--> src/main.rs:9:7
|
9 | f(Pin::new(&val));
| ^^^^^^^^ the trait `Unpin` is not implemented for `dyn TestTrait`
|
= note: consider using `Box::pin`
note: required by a bound in `Pin::<P>::new`
--> /usr/lib/rustlib/src/rust/library/core/src/pin.rs:482:23
|
482 | impl<P: Deref<Target: Unpin>> Pin<P> {
| ^^^^^ required by this bound in `Pin::<P>::new`
So it seems that the trait Unpin is implemented for &val in line 6, but not in line 9. Why is that?
This has to do with some subtleties of type inference.
The variable on line 6 is inferred to be Pin<&i32> which later gets automatically upcast to Pin<&dyn TestTrait> on line 7. You can check this by inserting the following assignment after line 6, which forces a compile-time error that shows you the type of my_val:
let _: () = my_val;
= note: expected unit type `()`
found struct `Pin<&i32>`
(Side note: this won't work if my_val has type () -- then the assignment will succeed!)
In contrast, when you create the Pin as a temporary on line 9, it is inferred to be Pin<&dyn TestTrait> instead of Pin<&i32>, and &dyn TestTrait doesn't implement Unpin by default.
You can fix this by explicitly specifying the type argument T of Pin<T> to be &i32 on line 9:
f(Pin::<&i32>::new(&val));
You could also fix this by specifying a bound on TypeTrait of Unpin, which will cause &dyn TestTrait to implement Unpin as well:
trait TestTrait: Unpin {}
Finally, you could also fix the issue by changing f to accept Pin<&impl TestTrait> instead of Pin<&dyn TestTrait>:
fn f(_val: Pin<&impl TestTrait>) {}
As pointed out by #KevinReid, you can also indicate that the trait object must implement Unpin, which is allowed because Unpin has no methods:
fn f(_val: Pin<&(dyn TestTrait + Unpin)>) {}

Understanding &type + 'a syntax

I have started to learn Rust. Currently I'm trying to learn how to properly use lifetime annotations and think I have understood the basics quite well. However, I have on several occasions encountered the following structure:
fn<'a> foo(a: &'a str, ...) -> &str + 'a
The str is not relevant it can be any type really, my question is specifically what &str + 'a mean (I might not be using it correctly, which is why I'm asking about it) as opposed to &'a str. As a real world example I have encountered it in this tutorial for async rust where they write:
fn foo_expanded<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a
I'm speculating that it might have to do with that Future is a trait and not a type, but I have been unable to verify it in any official documentation and have not found any source on what the syntax mean.
First of all, the syntax shown in your post is not allowed.
fn<'a> foo(a: &'a str, ...) -> &str + 'a
There are two reasons:
lifetime generics must be specified after the function name.
the displayed way of specifying return lifetimes is allowed only for traits, not complete types.
Otherwise you would get one of the two following errors:
error[E0178]: expected a path on the left-hand side of `+`, not `&str`
--> ./ex_056.rs:11:43
|
11 | fn _get<'a>(ms: &'a MyStruct, s: &str) -> &str + 'a {
| ^^^^^^^^^ help: try adding parentheses: `&(str + 'a)`
or
error[E0404]: expected trait, found builtin type `str`
--> ./ex_056.rs:15:31
|
15 | fn _get2<'a>(s: &'a str) -> &(str + 'a) {
| ^^^ not a trait
Thus it's not valid.
As a crude guess, I imagine that you have been misled by not a complete type but just a trait object. Since such a notation was allowed in 2015 but now it is deprecated, as you can see in the following warning:
warning: trait objects without an explicit `dyn` are deprecated
--> ./ex_056.rs:15:31
|
15 | fn _get2<'a>(s: &'a str) -> &(str + 'a) {
| ^^^^^^^^ help: use `dyn`: `dyn str + 'a`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
Your first example (&str + 'a) is not valid. The + 'a notation can only be applied to a trait.
Your second example: impl Future<Output = u8> + 'a means that foo_expanded returns some unknown type that implements the trait Future<Output = u8> and that this unknown type may contain references with the 'a lifetime. Therefore you won't be able to use the returned value once the 'a lifetime expires.

How to create a lazy_static HashMap with function references as value?

I tried to create a HashMap with functions as the values:
#[macro_use]
extern crate lazy_static;
use std::collections::HashMap;
lazy_static! {
static ref HASHES: HashMap<&'static str, &'static Fn([u8])> = {
let mut m = HashMap::new();
m.insert("md5", &md5);
m
};
}
fn md5(bytes: &[u8]) -> String {
String::default()
}
The compiler gives me an error:
error[E0277]: the trait bound `std::ops::Fn([u8]) + 'static: std::marker::Sync` is not satisfied in `&'static std::ops::Fn([u8]) + 'static`
--> src/main.rs:6:1
|
6 | lazy_static! {
| _^ starting here...
7 | | static ref HASHES: HashMap<&'static str, &'static Fn([u8])> = {
8 | | let mut m = HashMap::new();
9 | | m.insert("md5", &md5);
10 | | m
11 | | };
12 | | }
| |_^ ...ending here: within `&'static std::ops::Fn([u8]) + 'static`, the trait `std::marker::Sync` is not implemented for `std::ops::Fn([u8]) + 'static`
|
= note: `std::ops::Fn([u8]) + 'static` cannot be shared between threads safely
= note: required because it appears within the type `&'static std::ops::Fn([u8]) + 'static`
= note: required because of the requirements on the impl of `std::marker::Sync` for `std::collections::hash::table::RawTable<&'static str, &'static std::ops::Fn([u8]) + 'static>`
= note: required because it appears within the type `std::collections::HashMap<&'static str, &'static std::ops::Fn([u8]) + 'static>`
= note: required by `lazy_static::lazy::Lazy`
= note: this error originates in a macro outside of the current crate
I don't understand what should I do to fix this error and I don't know any other way of creating such a HashMap.
Your code has multiple issues. The error presented by the compiler is telling you that your code, will allow memory unsafety:
`std::ops::Fn([u8]) + 'static` cannot be shared between threads safely
The type you are storing in your HashMap has no guarantee that it can be shared.
You can "fix" that by specifying such a bound by changing your value type to &'static (Fn([u8]) + Sync). This unlocks the next error, due to the fact that your function signatures don't match up:
expected type `std::collections::HashMap<&'static str, &'static std::ops::Fn([u8]) + std::marker::Sync + 'static>`
found type `std::collections::HashMap<&str, &fn(&[u8]) -> std::string::String {md5}>`
"Fixing" that with &'static (Fn(&[u8]) -> String + Sync) leads to esoteric higher-kinded lifetime errors:
expected type `std::collections::HashMap<&'static str, &'static for<'r> std::ops::Fn(&'r [u8]) -> std::string::String + std::marker::Sync + 'static>`
found type `std::collections::HashMap<&str, &fn(&[u8]) -> std::string::String {md5}>`
Which can be "fixed" by casting the function with &md5 as &'static (Fn(&[u8]) -> String + Sync)), which leads to
note: borrowed value must be valid for the static lifetime...
note: consider using a `let` binding to increase its lifetime
This bottoms out because the reference you've made is to a temporary value that doesn't live outside of the scope.
I put fix in scare quotes because this isn't really the right solution. The right thing is to just use a function pointer:
lazy_static! {
static ref HASHES: HashMap<&'static str, fn(&[u8]) -> String> = {
let mut m = HashMap::new();
m.insert("md5", md5 as fn(&[u8]) -> std::string::String);
m
};
}
Honestly, I'd say that a HashMap is probably overkill; I'd use an array. A small array is probably faster than a small HashMap:
type HashFn = fn(&[u8]) -> String;
static HASHES: &'static [(&'static str, HashFn)] = &[
("md5", md5),
];
You can start by just iterating through the list, or maybe be fancy and alphabetize it and then use binary_search when it gets a bit bigger.

Rust compiler does not see structure as Sized

I am trying to define a trait as follows:
pub struct Parameter<A: Parameterisable>(&'static str, Box<A>);
pub trait Parameterisable {
// Some functions
}
impl Parameterisable for i32 {}
impl Parameterisable for f64 {}
pub struct ParameterCollection(Vec<Parameter<Parameterisable>>);
That is, the parameter collection is a mixture of parameters of different types. However compiling gives the following error:
error[E0277]: the trait bound `Parameterisable + 'static: std::marker::Sized` is not satisfied
--> src/main.rs:10:32
|
10 | pub struct ParameterCollection(Vec<Parameter<Parameterisable>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `Parameterisable + 'static: std::marker::Sized` not satisfied
|
= note: `Parameterisable + 'static` does not have a constant size known at compile-time
= note: required by `Parameter`
I am aware from this post that Vec must be Sized, but it seems that Parameter should be sized (because of the Box) so how do I convince the Rust compiler that Parameter is a Sized type?
Type parameters in Rust have an implicit Sized bound unless otherwise specified (by adding a ?Sized bound).
So the Parameter struct declaration is effectively:
pub struct Parameter<A: Parameterisable+Sized>(&'static str, Box<A>);
Note that Parameter<T> is always itself sized, since &'static str and Box<A> are always sized; the bound just says that T must also be sized.
The error message backs this up; it's saying that Parameterisable is not Sized, not that Parameter<Parametrerisable> is not Sized.
So the correct change is to add the ?Sized bound:
pub struct Parameter<A: Parameterisable+?Sized>(&'static str, Box<A>);

Cannot create a generic function that uses a literal zero

I am trying to write a Rust function that is similar to the built-in Range, but I want something that will return only X numbers, and return it as a list, which is why I'm trying to make this function:
extern crate num;
use num::Integer;
fn positions<T: Integer>(start: T, step: T, len: T) -> Vec<T> {
(0..len).map(|i| start + step * i).collect()
}
fn main() {
println!("{:?}", positions(10, 2, 10));
}
Except I am getting a compiler error:
error[E0308]: mismatched types
--> src/main.rs:6:9
|
6 | (0..len).map(|i| start + step * i).collect()
| ^^^ expected integral variable, found type parameter
|
= note: expected type `{integer}`
found type `T`
= help: here are some functions which might fulfill your needs:
- .div_floor(...)
- .gcd(...)
- .lcm(...)
- .mod_floor(...)
error[E0308]: mismatched types
--> src/main.rs:6:37
|
6 | (0..len).map(|i| start + step * i).collect()
| ^ expected type parameter, found integral variable
|
= note: expected type `T`
found type `{integer}`
The problem is 0. I'm unclear on the exact rules right now, but let's be general: 0 is of some specific integer type, which may or may not be the same thing as whatever T is. Thus, the compiler can't work out what the type parameter to range is supposed to be.
You can resolve this by using Zero::zero:
fn positions<T: Integer>(start: T, step: T, len: T) -> Vec<T> {
(T::zero()..len).map(|i| start + step * i).collect()
}
This gives the compiler enough leeway to infer that the two arguments to range are of the same type. However, that's still not enough to use Range as an iterator:
error: no method named `map` found for type `std::ops::Range<T>` in the current scope
--> src/main.rs:8:22
|
8 | (T::zero()..len).map(|i| start + step * i).collect()
| ^^^
|
= note: the method `map` exists but the following trait bounds were not satisfied: `T : std::iter::Step`, `&'a T : std::ops::Add`, `std::ops::Range<T> : std::iter::Iterator`
Unfortunately, as of Rust 1.17, the Step trait is unstable, so there's currently no good way to solve this problem using stable Rust.
Using unstable Rust, you can require implementations of Step:
#![feature(step_trait)]
extern crate num;
use num::Integer;
fn positions<T>(start: T, step: T, len: T) -> Vec<T>
where T: Integer + std::iter::Step + Copy,
for<'a> &'a T: std::ops::Add<Output = T>
{
(T::zero()..len).map(|i| start + step * i).collect()
}
fn main() {
println!("{:?}", positions(10, 2, 10));
}
You also need to require that T can be copied (or cloned, if you like) because the implementation of Add and Mul consumes the operands by value, which would mean that start + step * i could only be called once, except it needs to be called multiple times.

Resources