Copy identical fields of different struct in rust [duplicate] - rust

This question already has answers here:
How can I use serde to serialize a struct to another Rust data structure?
(1 answer)
How can I convert a struct to another struct with exactly the same field names and types?
(1 answer)
Closed 9 months ago.
Let's suppose we have two structs with identical fields (and types).
struct A {
pub data1: i32;
pub data2: string;
}
struct B {
pub data1: i32;
pub data2: string;
}
To copy the struct A and B, I have to do
fn convert_A_to_B(a: A) -> B {
B {
data1: a.data1,
data2: a.data2
}
}
I wish I can do something like
B {
..a
}
but it's not possible since types are different. Is there any macro or syntax that do the simple move of all identical fields?

If you are sure of the struct memory layout is the same you can use std::mem::transmute:
#[repr(C)]
#[derive(Debug)]
struct A {
pub data1: i32,
pub data2: String
}
#[repr(C)]
struct B {
pub data1: i32,
pub data2: String
}
impl From<B> for A {
fn from(b: B) -> A {
unsafe { std::mem::transmute(b) }
}
}
fn main() {
let b = B {data1: 10, data2: "Foo".to_string()};
let a: A = b.into();
println!("{a:?}");
}
Playground

Related

How to use traits implemented for some of the types embedded in an enum's variants?

I have an enum with around 20 variants. As traits cannot be implemented for enum's variants (see Can traits be used on enum types? and How do I implement a trait for an enum and its respective variants?) I have implemented my trait for some of the types embedded in the variants.
Given a variable typed as the enum, what is the idiomatic/best way to access the trait? As I need to use this in different places, I tried to move the code in a function and my following attempt returns a Option<Box<&dyn Trait>>.
pub struct X { pub name: String, pub weight: u32 }
pub struct Y { pub name: String }
pub struct Z {}
pub enum Node {
X(X),
Y(Y),
Z(Z),
}
pub trait Weighted {
fn weight(&self) -> u32;
}
impl Weighted for X {
fn weight(&self) -> u32 { return self.weight; }
}
impl Weighted for Z {
fn weight(&self) -> u32 { return 3; }
}
pub fn as_weighted_node(node: &Node) -> Option<Box<&dyn Weighted>> {
match node {
Node::X(x) => Some(Box::new(x)),
Node::Z(z) => Some(Box::new(z)),
_ => None
}
}
let node: Node = Node::X(X { name: "x1".to_string(), weight: 1 });
println!("{}", as_weighted_node(&node).unwrap().weight());
It seems Box is not needed and as_weighted_node can be written as:
pub fn as_weighted_node(node: &Node) -> Option<&dyn Weighted> {
match node {
Node::X(x) => Some(x),
Node::Z(z) => Some(z),
_ => None
}
}
I am still not sure this is the best way to handle this issue though.

Simplest way to match multiple fields of a struct against `None`

I have a Rust struct like this:
pub struct SomeMapping {
pub id: String,
pub other_id: Option<String>,
pub yet_another_id: Option<String>,
pub very_different_id: Option<String>
}
What is the simplest way to check if all optional ids are not set? I know the syntax like
if let Some(x) = option_value {...}
to extract a value from an Option, but I don't get how to use this in a concise way to check multiple values for None.
You can destructure a structure in pattern matching like so:
pub struct SomeMapping {
pub id: String,
pub other_id: Option<String>,
pub yet_another_id: Option<String>,
pub very_different_id: Option<String>,
}
fn main() {
let x = SomeMapping {
id: "R".to_string(),
other_id: Some("u".to_string()),
yet_another_id: Some("s".to_string()),
very_different_id: Some("t".to_string()),
};
if let SomeMapping {
id: a,
other_id: Some(b),
yet_another_id: Some(c),
very_different_id: Some(d),
} = x {
println!("{} {} {} {}", a, b, c, d);
}
}
It is documented in the Rust book chapter 18.

Convert enum variants with named data into separate structs using procedural macros

I'm writing a procedural macro to convert the variants of an enum into individual structs and implement some traits for that struct.
This works fine for unit and unnamed variants, but variants with named data will cause it to silently fail :).
Here is an example proc_macro definition:
extern crate proc_macro;
use quote::ToTokens;
use proc_macro::TokenStream;
use quote::quote;
use syn::{Data, DataEnum, DeriveInput};
#[proc_macro_derive(MyProcMacro)]
pub fn derive_my_proc_macro(input: TokenStream) -> TokenStream {
let ast: DeriveInput = syn::parse(input).unwrap();
// Error out if we're not annotating an enum
let data: DataEnum = match ast.data {
Data::Enum(d) => d,
_ => panic!("My structs can only be derived for enums"),
};
let variants = data.variants.iter();
let variant_structs = variants.map(|v| {
let var_id = &v.ident;
let fields = v.fields.clone().into_token_stream();
quote! {
pub struct #var_id #fields;
/* Implement traits for the new struct and stuff */
}
});
let gen = quote! {
#(#variant_structs)*
};
gen.into()
}
When I run it on this code:
#[derive(MyProcMacro)]
enum AllTypesOfVariants {
Unit,
OneUnNamed(bool),
MultiUnNamed(bool, bool, bool),
Named { _thing: bool },
MultiNamed { _thing: bool, _thing2: bool },
}
I get this expanded code (via cargo expand):
pub struct Unit;
pub struct OneUnNamed(bool);
pub struct MultiUnNamed(bool, bool, bool);
pub struct Named {
_thing: bool,
}
The expected result however would be:
pub struct Unit;
pub struct OneUnNamed(bool);
pub struct MultiUnNamed(bool, bool, bool);
pub struct Named {
_thing: bool,
}
pub struct MultiNamed {
_thing: bool,
_thing2: bool
}
The problem is in the semi-colon in the quote!().
Structs with unnamed fields should be terminated with a semicolon:
pub struct MultiUnNamed(bool, bool, bool);
But structs with named fields shouldn't:
pub struct MultiNamed {
_thing: bool,
_thing2: bool
}
The problem was solved by replacing:
quote! {
pub struct #var_id #fields;
}
with
match &v.fields {
Fields::Named(_) => {
quote! {
pub struct #var_id #fields
}
},
_ => {
quote! {
pub struct #var_id #fields;
}
}
}
(Also had to import syn::Fields)

Is it possible to create a macro to implement builder pattern methods?

I have a builder pattern implemented for my struct:
pub struct Struct {
pub grand_finals_modifier: bool,
}
impl Struct {
pub fn new() -> Struct {
Struct {
grand_finals_modifier: false,
}
}
pub fn grand_finals_modifier<'a>(&'a mut self, name: bool) -> &'a mut Struct {
self.grand_finals_modifier = grand_finals_modifier;
self
}
}
Is it possible in Rust to make a macro for methods like this to generalize and avoid a lot of duplicating code? Something that we can use as the following:
impl Struct {
builder_field!(hello, bool);
}
After reading the documentation, I've come up with this code:
macro_rules! builder_field {
($field:ident, $field_type:ty) => {
pub fn $field<'a>(&'a mut self,
$field: $field_type) -> &'a mut Self {
self.$field = $field;
self
}
};
}
struct Struct {
pub hello: bool,
}
impl Struct {
builder_field!(hello, bool);
}
fn main() {
let mut s = Struct {
hello: false,
};
s.hello(true);
println!("Struct hello is: {}", s.hello);
}
It does exactly what I need: creates a public builder method with specified name, specified member and type.
To complement the already accepted answer, since it is 4 years old by now, you should check out the crate rust-derive-builder. It uses procedural macros to automatically implement the builder pattern for any struct.

Creating default function parameters [duplicate]

This question already has answers here:
Default function arguments in Rust
(7 answers)
Closed 7 years ago.
Is there a way to create pseudo default function parameters in rust? I'd like to do something like
pub struct Circular<T> {
raw: Vec<T>,
current: u64
}
impl<T> Circular<T> {
pub fn new(t_raw: Vec<T>, t_current=0: u64) -> Circular<T> {
return Circular { raw: t_raw, current: t_current };
}
I'd like to have the option of settings the current variable, but it won't always be needed to be set. Is this a possible thing to do in Rust?
No, Rust doesn't support default function arguments. You have to define different methods, or in case of struct initialization (your example) you can use the struct update syntax like this:
use std::default::Default;
#[derive(Debug)]
pub struct Sample {
a: u32,
b: u32,
c: u32,
}
impl Default for Sample {
fn default() -> Self {
Sample { a: 2, b: 4, c: 6}
}
}
fn main() {
let s = Sample { c: 23, .. Sample::default() };
println!("{:?}", s);
}

Resources