Given is a struct with a u32 field. It has exactly one overloaded method that can be used as both setter and getter for the field.
pub struct Struct {
value: u32
}
pub trait Trait<T> {
fn method(&mut self, arg: T);
}
impl Trait<u32> for Struct {
fn method(&mut self, arg: u32) {
self.value = arg;
}
}
impl Trait<&mut u32> for Struct {
fn method(&mut self, arg: &mut u32) {
*arg = self.value;
}
}
A possible use of this structure could be as follows
fn main() {
let mut s = Struct { value: 0 };
let mut v = 0;
s.method(&mut v);
println!("The value of s is: {}", v);
s.method(3);
s.method(&mut v);
println!("The value of s is: {}", v);
}
The advantage of calling an overloaded method instead of accessing the field directly serves two reasons when the struct is used in a ffi interface. On the one hand, the method can still make modifications to the value, such as first converting a &str to a CString and then storing the *const u8 as the value, which makes the string usable for C. On the other hand, overloading the method also makes it possible to use the names given for it in C instead of writing setValue and getValue, for example. However, as you can see here, one of the two methods does not need a mutable reference to self because it does not change the value field, but because the trait requires it, it is used in both cases anyway. The struct is not only configured and then used as argument in a ffi method, but can also occur as return value of such a method, in which case it will be returned as a immutable reference and should only be read from. The customized trait implementations would look like this
impl Trait<u32> for Struct {
fn method(&mut self, arg: u32) {
self.value = arg;
}
}
impl Trait<&mut u32> for Struct {
fn method(&self, arg: &mut u32) {
*arg = self.value;
}
}
Obviously this won't work here because the second impl block doesn't have the same method signature as the trait. I already tried to define the self paramter as another generic parameter in the trait using the arbitrary_self_types features but unfortunately that didn't work.
You cannot parameterize over mutability.
See:
internals.rust-lang.org - Parameterisation over mutability.
internals.rust-lang.org - Generic mutability parameters.
How to implement a trait for any mutability?
How to avoid writing duplicate accessor functions for mutable and immutable references in Rust?
You can parameterize on self, but it will not be a method anymore, only an associated function:
pub trait Trait<This, T> {
fn method(this: This, arg: T);
}
impl Trait<&mut Self, u32> for Struct {
fn method(this: &mut Self, arg: u32) {
this.value = arg;
}
}
impl Trait<&Self, &mut u32> for Struct {
fn method(this: &Self, arg: &mut u32) {
*arg = this.value;
}
}
fn main() {
let mut s = Struct { value: 0 };
let mut v = 0;
Struct::method(&s, &mut v);
println!("The value of s is: {}", v);
Struct::method(&mut s, 3);
Struct::method(&s, &mut v);
println!("The value of s is: {}", v);
}
Given the draft RFC Refined trait implementations that poses the possibility to refine a trait in its implementation, i.e. to write a less generic impl (e.g. safe method in the impl that is unsafe in the trait), it may be possible that you will be able to refine mutability in the future too (although I haven't seen discussions about that), but that will only relax the restriction when you work with a concrete instance, not with generics.
One way or the other, I don't think this design is correct. Just use normal value() and set_value() methods, it is simple and obvious.
Related
Is my understanding correct that in Rust it is not possible to protect reference members of a struct from modification while having the reference target values mutable? (Without runtime borrow checking that is.) For example:
struct MyData<'a> {
pub some_ref: &'a mut i32,
}
fn doit<'a>(data: &mut MyData<'a>, other_ref: &'a mut i32) {
// I want to be able to do the following here:
*data.some_ref = 22;
// but make it impossible to do the following:
data.some_ref = other_ref;
}
Not being able to change the reference value may be useful in certain FFI situations. FFI and the performance requirements reasons prevent the use of runtime borrow checking here.
In C++ it can be expressed like this:
struct MyData {
int* const some_ref;
};
void doit(const MyData &data, int* other_ref) {
// this is allowed:
*data.some_ref = 22;
// this is not:
data.some_ref = other_ref; // compile error
}
You can create a wrapper type around the reference. If the constructor is private, and so is the wrapped reference field, you cannot replace the reference itself. You can then implement DerefMut to allow changing the referent.
pub struct ImmRef<'a> {
inner: &'a mut i32,
}
impl<'a> ImmRef<'a> {
fn new(inner: &'a mut i32) -> Self { Self { inner } }
}
impl std::ops::Deref for ImmRef<'_> {
type Target = i32;
fn deref(&self) -> &Self::Target { &*self.inner }
}
impl std::ops::DerefMut for ImmRef<'_> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut *self.inner }
}
struct MyData<'a> {
pub some_ref: ImmRef<'a>,
}
fn doit<'a>(data: &mut MyData<'a>, other_ref: &'a mut i32) {
// I want to be able to do the following here:
*data.some_ref = 22;
// but make it impossible to do the following:
// data.some_ref = other_ref;
}
You can mark the newtype #[repr(transparent)] for FFI purposes.
But do note that if the code has some ImmRef<'a> available it can use tools such as std::mem::replace() to replace the reference.
Rust does not allow you to specify the mutability of individual fields like you can via const in C++. Instead, you should simply encapsulate the data by making it private and only allow modification through methods that you dictate:
struct MyData<'a> {
some_ref: &'a mut i32,
}
impl MyData<'_> {
pub fn set_ref(&mut self, other: i32) {
*self.some_ref = other;
}
}
That way, the field some_ref cannot be modified directly (outside of the module) and must use the available method.
The task is to filter out the supertrait objects for base trait object vector:
use std::rc::Rc;
use std::any::Any;
pub trait TraitA {
fn get_title(&self) -> &str;
fn as_any(&self) -> Any;
}
pub trait TraitB: TraitA {
fn get_something(&self) -> &str;
}
pub fn filter_b(input: Vec<Rc<dyn TraitA>>) -> Vec<Rc<dyn TraitB>> {
// bs.filter(|it| /* How to do it? */).collect();
}
Is it even possible? Any clue or advice?
I know as_any() can be used to downcast but as i'm not sure how it's meant to work with Rc as it takes ownership (and thus requires the instance).
I was first expecting the answer to be "absolutely not!", Any doesn't help if you don't know the concrete type. But it turns out you can... with caveats, and I'm not 100% sure its totally safe.
To go from Rc<T> to Rc<U>, you can use the escape hatches into_raw and from_raw. The docs of the former read:
Constructs an Rc from a raw pointer.
The raw pointer must have been previously returned by a call to Rc<U>::into_raw where U must have the same size and alignment as T. This is trivially true if U is T. Note that if U is not T but has the same size and alignment, this is basically like transmuting references of different types. See mem::transmute for more information on what restrictions apply in this case.
The user of from_raw has to make sure a specific value of T is only dropped once.
This function is unsafe because improper use may lead to memory unsafety, even if the returned Rc<T> is never accessed.
With that in mind, since we only have access to TraitA, it'll need an as_b() function to get itself as a TraitB. The fact that the target is a super trait doesn't really help. Then we can write a crosscast function like so:
use std::rc::Rc;
trait TraitA {
fn print_a(&self);
// SAFETY: the resulting `dyn TraitB` must have the *exact* same address,
// size, alignment, and drop implementation for `crosscast` to work safely.
// Basically it must be `self` or maybe a transparently wrapped object.
unsafe fn as_b(&self) -> Option<&(dyn TraitB + 'static)>;
}
trait TraitB {
fn print_b(&self);
}
fn crosscast(a: Rc<dyn TraitA>) -> Option<Rc<dyn TraitB>> {
unsafe {
let b_ptr = a.as_b()? as *const dyn TraitB;
let a_ptr = Rc::into_raw(a);
// sanity check
assert!(a_ptr as *const () == b_ptr as *const ());
Some(Rc::from_raw(b_ptr))
}
}
With this function at our disposal, your problem becomes trivial by using .filter_map():
struct Both {
data: String,
}
impl TraitA for Both {
fn print_a(&self) { println!("A: {}", self.data); }
unsafe fn as_b(&self) -> Option<&(dyn TraitB + 'static)> { Some(self) }
}
impl TraitB for Both {
fn print_b(&self) { println!("B: {}", self.data); }
}
struct OnlyA {
data: String,
}
impl TraitA for OnlyA {
fn print_a(&self) { println!("A: {}", self.data); }
unsafe fn as_b(&self) -> Option<&(dyn TraitB + 'static)> { None }
}
fn main() {
let vec_a = vec![
Rc::new(Both{ data: "both".to_owned() }) as Rc<dyn TraitA>,
Rc::new(OnlyA{ data: "only a".to_owned() })
];
for a in &vec_a {
a.print_a();
}
println!();
let vec_b = vec_a
.into_iter()
.filter_map(crosscast)
.collect::<Vec<_>>();
for b in &vec_b {
b.print_b();
}
}
See it all together on the playground.
I would still recommend not doing this if at all possible. It would be perfectly safe for example to go from &Rc<dyn TraitA> to Option<&dyn TraitB> using the above method without all the restrictions. Something like this wouldn't have the restrictions and unsafety:
for b in vec_a.iter().filter_map(|a| a.as_b()) {
// ...
}
I have a situation where I have to move a struct from one object to another through a &mut self. Take a look:
pub struct MyStruct {
//no copy trait
device: Device
}
impl MyStruct {
pub fn finalize(&mut self) {
//error: cannot move since I borrowed
let interface = InterfaceBuilder::new(self.device)
}
}
First of all, why I cannot move something out of a borrowed mutable reference? Borrowed mutables are exclusive, there's no chance another code is looking into it.
Well, to address this problem I changed to
pub struct MyStruct {
//no copy trait
device: RefCell<Device>
}
impl MyStruct {
pub fn finalize(&mut self) {
//error on `self.device`: cannot move out of `self.device` which is behind a mutable reference
let interface = InterfaceBuilder::new(self.device.into_inner())
}
}
I know why the error occurs:
pub fn into_inner(self) -> T
calling into_inner makes self.device move. Why RefCell simply does not have an implementation pub fn into_inner(&mut self) -> T? I don't see a problem.
You cannot move out of a mutable reference because that would leave the original object incomplete.
Consider this code:
struct MyStruct {
s: String
}
fn finalize(f: &mut MyStruct) {
let _x = f.s; //error E0507!
}
fn main() {
let mut my = MyStruct {
s: "hi".into()
};
finalize(&mut my);
println!("{}", my.s); //what should this do?
}
Then, RefCell::into_inner(&mut self) -> T has the same problem. You could call it twice in a row and you would get two T values where before there was only one. And that, for a non Copy type is impossible.
If you want this function to consume the inner value, probably it should consume the outer value too:
fn finalize(f: MyStruct) {
let _x = f.s;
}
If you really want to move a value out of a mutable reference, you must leave something valid in its place. The easiest way is to declare an Option and use take() to steal and replace it with a None:
struct MyStruct {
s: Option<String>
}
fn finalize(f: &mut MyStruct) {
let _x = f.s.take();
}
Naturally, Option::take returns an Option so that if you call it twice, the second time you get None. If you are positive you have a value you can do take().uwnrap().
Alternatively, if your field type is Default you can use std::mem::take that replaces it with a default-created value:
struct MyStruct {
s: Vec<i32>
}
fn finalize(f: &mut MyStruct) {
let _x = std::mem::take(&mut f.s);
}
PS #1: there is Cell::take(&self) -> T, but only if T implements Default. It works just like std::mem::take but with a non-mutable reference.
PS #2: there is also unsafe fn ManuallyDrop::take(slot: &mut ManuallyDrop<T>) -> T, that is intented to be used in advanced drop implementations. But it is unsafe so it should never be your first option: if you call it twice you will get undefined behavior.
When writing code with traits you can put the trait in a trait bound:
use std::fmt::Debug;
fn myfunction1<T: Debug>(v: Box<T>) {
println!("{:?}", v);
}
fn myfunction2<T: Debug>(v: &T) {
println!("{:?}", v);
}
fn main() {
myfunction1(Box::new(5));
myfunction2(&5);
}
Or directly in a Box or reference type:
use std::fmt::Debug;
fn myfunction3(v: Box<Debug>) {
println!("{:?}", v);
}
fn myfunction4(v: &Debug) {
println!("{:?}", v);
}
fn main() {
myfunction3(Box::new(5));
myfunction4(&5);
}
These give the same output. So what is the difference?
(This question was inspired by another question where this was just one of several intermingled concepts)
With <T: Trait> Box<T> you are using a trait bound to tell the compiler that you want a Box with an instance of some type T which implements Trait, and you will specify T when you use it. The Rust compiler will likely create different, efficient, code for each different T in your code (monomorphization).
With Box<Trait> you are telling the compiler that you want a Box with a trait object, a pointer to an unknown type which implements Trait, which means that the compiler will use dynamic dispatch.
I've included two examples which makes the difference a bit clearer:
<T: Trait> Box<T>, i.e. trait bound:
use std::fmt::Debug;
struct Wrapper<T> {
contents: Option<Box<T>>,
}
impl<T: Debug> Wrapper<T> {
fn new() -> Wrapper<T> {
Wrapper { contents: None }
}
fn insert(&mut self, val: Box<T>) {
}
}
fn main() {
let mut w = Wrapper::new();
// makes T for w be an integer type, e.g. Box<i64>
w.insert(Box::new(5));
// type error, &str is not an integer type
// w.insert(Box::new("hello"));
}
Box<Trait>, i.e. trait object:
use std::fmt::Debug;
struct Wrapper {
contents: Option<Box<Debug>>,
}
impl Wrapper {
fn new() -> Wrapper {
Wrapper { contents: None }
}
fn insert(&mut self, val: Box<Debug>) {
}
}
fn main() {
let mut w = Wrapper::new();
w.insert(Box::new(5));
w.insert(Box::new("hello"));
}
For further details on the difference between trait bounds and trait objects I recommend the section on trait objects in the first edition of the Rust book.
Importantly, you don't have to put the generic type behind a reference (like & or Box), you can accept it directly:
fn myfunction3<T: Debug>(v: T) {
println!("{:?}", v);
}
fn main() {
myfunction3(5);
}
This has the same benefits of monomorphization without the downside of additional memory allocation (Box) or needing to keep ownership of the value somewhere (&).
I would say that generics should often be the default choice — you only require a trait object when there is dynamic dispatch / heterogeneity.
pub struct Notifier<'a, T> {
callbacks: Vec<Box<'a + FnMut(&T)>>
}
impl<'a, T> Notifier<'a, T>{
fn add_callback<F: 'a + FnMut(&T)>(&mut self, callback: F) {
self.callbacks.push(Box::new(callback));
}
fn trigger(&mut self, payload: T) {
for callback in &mut self.callbacks {
callback(&payload);
}
}
}
struct A {
x: i64
}
impl A {
fn foo(&mut self, x: &i64) {
self.x = x + 1;
}
}
fn test() {
let mut bar = A {x: 3};
let mut notifier = Notifier{callbacks: Vec::new()};
notifier.add_callback(|x| bar.foo(x));
}
Playground
This is a simple observer pattern implemented using callbacks. It works.
However, the fact that trigger(&mut self... causes much trouble in my later coding (How to update self based on reference of value from hashmap from self). Is it possible to make trigger(&self ... instead?
I'm using rustc 1.19.0-nightly.
If you want to change the interior of a struct without having the struct mutable, you should use a Cell:
Values of the Cell<T> and RefCell<T> types may be mutated through shared references (i.e. the common &T type), whereas most Rust types can only be mutated through unique (&mut T) references. We say that Cell<T> and RefCell<T> provide 'interior mutability', in contrast with typical Rust types that exhibit 'inherited mutability'.
Playground