I'm currently trying to translate a C program to Rust.
The C programm has following structures (boiled down to MRE):
typedef struct {
bool isActive;
uint32_t value;
} tMyInnerStruct;
typedef struct {
tMyInnerStruct inner1;
tMyInnerStruct inner2;
} tMyStruct;
and in a function I would do the following pointer magic:
void myFunction()
{
tMyStruct myStruct = initMyStuct();
tMyInnerStruct *pActiveInner = &myStruct.inner1;
// Do something with pActiveInner (pointing to inner1), like setting value...
changeActiveStruct(&myStruct, &pActiveInner);
// Do something with pActiveInner (pointing to inner2), like setting value...
}
void changeActiveStruct( tMyStruct *pMyStruct, tMyInnerStruct **ppActiveInner )
{
if ( &pMyStruct->inner1 == *ppActiveInner ) {
*ppActiveInner = &pMyStruct->inner2;
} else {
*ppActiveInner = &pMyStruct->inner1;
}
}
No my question is: How would I achieve the same in Rust?
What I've tried so far in Rust:
#[derive(Default)]
struct MyInnerStruct {
is_active: bool,
value: u32,
}
#[derive(Default)]
struct MyStruct {
inner1: MyInnerStruct,
inner2: MyInnerStruct,
}
impl MyStruct {
fn change_active(&mut self, active: &MyInnerStruct) -> &mut MyInnerStruct {
if &self.inner1 as *const _ == active as *const _ {
&mut self.inner2
} else {
&mut self.inner1
}
}
}
fn main() {
let mut my_struct: MyStruct = Default::default();
let mut active = &mut my_struct.inner1;
active = my_struct.change_active(active);
// The above complains, that my_struct cannot be borrowed mutable more than once...
}
You can accompilsh the same thing by using a pointer as argument instead of a reference. Because of the order that arguments and the receiver are evaluated in, you have to convert to a pointer ahead of the call and can't do it in the parameter list but this works:
impl MyStruct {
fn change_active(&mut self, active: *const MyInnerStruct) -> &mut MyInnerStruct {
if &self.inner1 as *const _ == active {
&mut self.inner2
} else {
&mut self.inner1
}
}
}
fn main() {
let mut my_struct: MyStruct = Default::default();
let mut active = &mut my_struct.inner1;
active = {
let active = active as *const _;
my_struct.change_active(active)
};
}
Minor detail, change_active
does no longer seem like an apropriate name since the Rust version doesn't actually change active
maybe new_active
or something else still is a better name for the method