I am struggling with Rust Rc/RefCell. Essentially, I would like to mutate the state of T inside the struct which owns this data (Rc<Ref>). However I would also want to share this data (with immutability such as Rc) to external struct.
How do I achieve that?
pub struct A
pub struct B
{
a : Rc<RefCell<A>>
}
pub struct C
{
a : Rc<A>
}
Basically I am trying to store a reference of A in C but as you know in Rust you need to do 'a life time annotation which i cannot make it work in general.
And i do not want to pass the mutability of A into C.
Let me put similar code as of C++,
struct A;
struct B
{
std::unique_ptr<A> a;
}
struct C
{
const A & a;
}
It's self-contradictory to say that C::a is immutable while B::a is not, since C can be used to observe the mutations. I'm going to assume that you want C to provide read-only access to A. In that case, you must still specify RefCell in the type of C::a for storage purposes, but then you don't expose the mutation part of the RefCell. Just avoid having any public methods of C that expose the RefCell or the ability to get a RefMut from it, and you're done.
use std::rc::Rc;
use std::cell::{RefCell, Ref};
pub struct A;
pub struct B {
a: Rc<RefCell<A>>,
}
pub struct C {
a: Rc<RefCell<A>>,
}
impl B {
// These are just simple examples; create whatever methods make sense for your situation
pub fn replace(&self, a: A) {
*self.a.borrow_mut() = a;
}
pub fn read(&self) -> Ref<'_, A> {
self.a.borrow()
}
pub fn as_read_only(&self) -> C {
C { a: self.a.clone() }
}
}
impl C {
// There are no mutation methods here so A cannot be mutated through C
pub fn read(&self) -> Ref<'_, A> {
self.a.borrow()
}
}
Related
I have some code which needs to modify a field of a struct during a clone. I want to avoid unnecessarily cloning that field before modifying it. The original struct is wrapped in an Rc so I can only access it via a reference. Here is a simplified example with a naive attempt to use the struct update syntax:
use std::rc::Rc;
#[derive(Clone, Debug)]
struct B {
value: i32,
}
#[derive(Clone, Debug)]
struct A {
b: B,
c: i32,
}
impl A {
fn update_c(&self, c: i32) -> Self {
A {
c,
..*self
}
}
fn update_b(&self, b: B) -> Self {
A {
b,
..*self
}
}
}
fn main() {
let a = Rc::new(A {
b: B { value: 0 },
c: 0,
});
let a = Rc::new(a.update_c(-1));
}
rust playground link
Unfortunately this doesn't compile because my type does not implement Copy, and I don't really want it to implement Copy. I'm also guessing that in this case, the copy while performing the dereference in ..*a would be just as expensive as cloning the entire struct before modification.
The only way I've found so far to make this work is to manually clone each field:
fn update_c(&self, c: i32) -> Self {
Self {
c,
b: self.b.clone()
}
}
rust playground link
But this would not be convenient for a struct with many fields. Is there a different solution or crate out there with a custom derive to have this functionality available for every field without having to exponentially increase the amount of code you write to add a new field?
I have two structs and a trait:
struct A {
x: u32,
}
struct B {
x: u32,
}
trait T {
fn double(&self) -> u32;
}
I would like to implement T for both structs using x.
Is there a way to write something like
impl T for A, B {
fn double(&self) -> u32 {
/* ... */
}
}
I would like to not use macros if possible.
The only way to implement a trait once for many concrete types is to implement a trait for all types already implementing another trait.
For example, you can implement a marker trait Xed and then:
impl<T> Double for T
where
T: Xed,
{
fn double(&self) {
/* ... */
}
}
However, Rust has principled generics. The only thing that you know about T in the previous implementation is that T implements the Xed trait, and therefore the only associated types/functions you can use are those coming from Xed.
A trait cannot expose a field/attribute, only associated types, constants and functions, so Xed would need a getter for x (which need not be called x).
If you wish to rely on syntactic (and not semantic) properties of the code, then use macros.
Creating a macro also solves your problem:
struct A {
x: u32,
}
struct B {
x: u32,
}
trait T {
fn double(&self) -> u32;
}
macro_rules! impl_T {
(for $($t:ty),+) => {
$(impl T for $t {
fn double(&self) -> u32 {
self.x * 2
}
})*
}
}
impl_T!(for A, B);
fn main() {}
Using the duplicate_item attribute macro you can do the following:
use duplicate::duplicate_item;
#[duplicate_item(name; [A]; [B])]
impl T for name {
fn double(&self) -> u32 {
self.x * 2
}
}
This will expand to two identical implementations for the two structs.
I know you said you didn't want to use macros, but I interpret that as meaning you don't want to roll your own macro, so I think this is a good compromise.
You could also use duplicate_item to avoid repeating your struct definitions:
use duplicate::duplicate_item;
#[duplicate_item(name; [A]; [B])]
struct name {
x: u32,
}
Or go all-out if you for some reason need two identical structs with identical implements (at this point we should begin questioning why we need 2 structs at all :D):
use duplicate::duplicate;
duplicate!{
[ name; [A]; [B] ]
pub struct name {
x: u32,
}
impl T for name {
fn double(&self) -> u32 {
self.x * 2
}
}
}
Notice the use of the duplicate function-like macro this time to duplicate struct and implement at the same time.
Since the internals of your structs are the same / share common components, you should extract them into a common struct and embed the common part back into the parent structs. The common struct would have the "complicated" implementation of the trait and then the parent struct's trait implementations would delegate to the common implementation:
trait T {
fn double(&self) -> u32;
}
struct A {
common: Common,
}
impl T for A {
fn double(&self) -> u32 {
self.common.double()
}
}
struct B {
common: Common,
}
impl T for B {
fn double(&self) -> u32 {
self.common.double()
}
}
struct Common {
x: u32,
}
impl T for Common {
fn double(&self) -> u32 {
self.x * 2
}
}
Any nicer code will require changes to the language. Two possible paths:
Fields in traits
Delegation
I'm attempting to generalize/decouple an API, so that alternative structs that satisfy a Trait can be used. Struggling on Syntax regarding nested traits. This is a stripped down example of what I'm attempting to do. Note that in the real one, there are multiple sub-traits, which potentially makes a follow-on question of "how to reduce verbosity, if I'm on the right track".
pub mod general {
/// A trait to make the API generic
pub trait MyTrait<A: PartialEq> {
// type A: Partial
fn val(self) -> A;
}
/// Part of the generic API
pub struct Data<A: PartialEq, T: MyTrait<A>> {
mys: T
}
/// Another part of the generic API
fn doit<A: PartialEq>(s: impl MyTrait<A>) -> impl MyTrait {
s
}
}
pub mod specific {
/// Api-specific substruct
#[derive(PartialEq)]
pub struct Aval {
val: u32
}
/// My top-level custom struct
pub struct MyS {
val: Aval
}
}
impl<A: PartialEq> crate::general::MyTrait<A> for crate::specific::MyS {
fn val(self) -> crate::specific::Aval {
self.val
}
}
/// Example of how we'd use this
fn main() {
let mys = crate::specific::MyS{ val: crate::specific::Aval{ val: 0 } };
let S = crate::general::Data{mys};
crate::general::doit(mys); // Eg pretend we cloned or didn't create S.
}
Playground
In this specific example, we have a chicken+egg: Error on the Data struct of error[E0392]: parameter `A` is never used. Where if we remove A: error[E0412]: cannot find type `A` in this scope
I suspect this is a syntax problem related to associated types.
Just remove the trait bound from your struct.
struct Data<T> {
mys: T
}
You can still add methods and trait implementations for Data<T> requiring more specific bounds on T, but you don’t need them to define the layout of Data<T>, so you shouldn’t specify them there (and in this case, you can’t, unless you add a PhantomData member referring to A).
Your code has a number of other errors, but I trust you’ll figure them out. Feel free to comment if you get stuck again.
I have a C library with an interface similar to this: (I have represented the C API within Rust, so that all of the code in this question can be concatenated in a single .rs file and easily tested)
// Opaque handles to C structs
struct c_A {}
struct c_B {}
// These 2 `create` functions allocate some heap memory and other
// resources, so I have represented this using Boxes.
extern "C" fn create_a() -> *mut c_A {
let a = Box::new(c_A {});
Box::into_raw(a)
}
// This C FFI function frees some memory and other resources,
// so I have emulated that here.
extern "C" fn destroy_a(a: *mut c_A) {
let _a: Box<c_A> = unsafe { Box::from_raw(a) };
}
extern "C" fn create_b(_a: *mut c_A) -> *mut c_B {
let b = Box::new(c_B {});
Box::into_raw(b)
}
// Note: While unused here, the argument `_a` is actually used in
// the C library, so I cannot remove it. (Also, I don't control
// the C interface)
extern "C" fn destroy_b(_a: *mut c_A, b: *mut c_B) {
let _b = unsafe { Box::from_raw(b) };
}
I have created the following Rusty abstraction over the C functions:
struct A {
a_ptr: *mut c_A,
}
impl A {
fn new() -> A {
A { a_ptr: create_a() }
}
}
impl Drop for A {
fn drop(&mut self) {
destroy_a(self.a_ptr);
}
}
struct B<'a> {
b_ptr: *mut c_B,
a: &'a A,
}
impl<'a> B<'a> {
fn new(a: &'a A) -> B {
B {
b_ptr: create_b(a.a_ptr),
a,
}
}
}
impl<'a> Drop for B<'a> {
fn drop(&mut self) {
destroy_b(self.a.a_ptr, self.b_ptr);
}
}
The B struct contains a reference to A for the sole reason that the a_ptr is necessary when calling the destroy_b function for memory cleanup. This reference is not needed by me for any of my Rust code.
I would now like to create the following struct which references both A and B:
struct C<'b> {
a: A,
b: B<'b>,
}
impl<'b> C<'b> {
fn new() -> C<'b> {
let a = A::new();
let b = B::new(&a);
C { a, b }
}
}
// Main function just so it compiles
fn main() {
let c = C::new();
}
However, this will not compile:
error[E0597]: `a` does not live long enough
--> src/main.rs:76:25
|
76 | let b = B::new(&a);
| ^ borrowed value does not live long enough
77 | C { a, b }
78 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'b as defined on the impl at 73:1...
--> src/main.rs:73:1
|
73 | impl<'b> C<'b> {
| ^^^^^^^^^^^^^^
I understand why this fails: When returning the C struct from C::new(), it moves the C. This means that the A contained within is moved, which renders all references to it invalid. Therefore, there's no way I could create that C struct. (Explained in much more detail here)
How can I refactor this code in such a way that I can store a B in a struct along with its "parent" A? There's a few options I've thought of, that won't work:
Change the C interface: I don't control the C interface, so I can't change it.
Have B store a *mut c_A instead of &A: If A is dropped, then that raw pointer becomes invalid, and will result in undefined behavior when B is dropped.
Have B store an owned A rather than a reference &A: For my use case, I need to be able to create multiple Bs for each A. If B owns A, then each A can only be used to create one B.
Have A own all instances of B, and only return references to B when creating a new B: This has the problem that Bs will accumulate over time until the A is dropped, using up more memory than necessary. However, if this is indeed the best way to go about it, I can deal with the slight inconvenience.
Use the rental crate: I would rather take the slight memory usage hit than add the complexity of a new macro to my code. (That is, the complexity of anyone reading my code needing to learn how this macro works)
I suspect that the best solution somehow involves storing at least A on the heap so it doesn't need to move around, but I can't figure out how to make this work. Also, I wonder if there is something clever that I can do using raw pointers.
This sounds like an ideal case for reference counting. Use Rc or Arc, depending on your multithreading needs:
use std::rc::Rc;
struct B {
b_ptr: *mut c_B,
a: Rc<A>,
}
impl B {
fn new(a: Rc<A>) -> B {
B {
b_ptr: create_b(a.a_ptr),
a,
}
}
}
impl Drop for B {
fn drop(&mut self) {
destroy_b(self.a.a_ptr, self.b_ptr);
}
}
fn main() {
let a = Rc::new(A::new());
let x = B::new(a.clone());
let y = B::new(a);
}
Does not change the C interface.
A cannot be dropped while there are still Bs referencing it.
Can create multiple Bs for each A.
A's memory usage will not increase forever.
Creates a single heap allocation to store A and its reference count.
Rc is in the standard library, no new crate to learn.
In the future, you'll be able to use arbitrary self types to write this in a nicer manner:
#![feature(arbitrary_self_types)]
use std::rc::Rc;
struct A {
a_ptr: *mut c_A,
}
impl A {
fn new() -> A {
A { a_ptr: create_a() }
}
fn make_b(self: &Rc<Self>) -> B {
B {
b_ptr: create_b(self.a_ptr),
a: self.clone(),
}
}
}
impl Drop for A {
fn drop(&mut self) {
destroy_a(self.a_ptr);
}
}
struct B {
b_ptr: *mut c_B,
a: Rc<A>,
}
impl Drop for B {
fn drop(&mut self) {
destroy_b(self.a.a_ptr, self.b_ptr);
}
}
fn main() {
let a = Rc::new(A::new());
let x = a.make_b();
let y = a.make_b();
}
I have two structs and a trait:
struct A {
x: u32,
}
struct B {
x: u32,
}
trait T {
fn double(&self) -> u32;
}
I would like to implement T for both structs using x.
Is there a way to write something like
impl T for A, B {
fn double(&self) -> u32 {
/* ... */
}
}
I would like to not use macros if possible.
The only way to implement a trait once for many concrete types is to implement a trait for all types already implementing another trait.
For example, you can implement a marker trait Xed and then:
impl<T> Double for T
where
T: Xed,
{
fn double(&self) {
/* ... */
}
}
However, Rust has principled generics. The only thing that you know about T in the previous implementation is that T implements the Xed trait, and therefore the only associated types/functions you can use are those coming from Xed.
A trait cannot expose a field/attribute, only associated types, constants and functions, so Xed would need a getter for x (which need not be called x).
If you wish to rely on syntactic (and not semantic) properties of the code, then use macros.
Creating a macro also solves your problem:
struct A {
x: u32,
}
struct B {
x: u32,
}
trait T {
fn double(&self) -> u32;
}
macro_rules! impl_T {
(for $($t:ty),+) => {
$(impl T for $t {
fn double(&self) -> u32 {
self.x * 2
}
})*
}
}
impl_T!(for A, B);
fn main() {}
Using the duplicate_item attribute macro you can do the following:
use duplicate::duplicate_item;
#[duplicate_item(name; [A]; [B])]
impl T for name {
fn double(&self) -> u32 {
self.x * 2
}
}
This will expand to two identical implementations for the two structs.
I know you said you didn't want to use macros, but I interpret that as meaning you don't want to roll your own macro, so I think this is a good compromise.
You could also use duplicate_item to avoid repeating your struct definitions:
use duplicate::duplicate_item;
#[duplicate_item(name; [A]; [B])]
struct name {
x: u32,
}
Or go all-out if you for some reason need two identical structs with identical implements (at this point we should begin questioning why we need 2 structs at all :D):
use duplicate::duplicate;
duplicate!{
[ name; [A]; [B] ]
pub struct name {
x: u32,
}
impl T for name {
fn double(&self) -> u32 {
self.x * 2
}
}
}
Notice the use of the duplicate function-like macro this time to duplicate struct and implement at the same time.
Since the internals of your structs are the same / share common components, you should extract them into a common struct and embed the common part back into the parent structs. The common struct would have the "complicated" implementation of the trait and then the parent struct's trait implementations would delegate to the common implementation:
trait T {
fn double(&self) -> u32;
}
struct A {
common: Common,
}
impl T for A {
fn double(&self) -> u32 {
self.common.double()
}
}
struct B {
common: Common,
}
impl T for B {
fn double(&self) -> u32 {
self.common.double()
}
}
struct Common {
x: u32,
}
impl T for Common {
fn double(&self) -> u32 {
self.x * 2
}
}
Any nicer code will require changes to the language. Two possible paths:
Fields in traits
Delegation