Is there any crate or functionality that allows me to copy the fields from another structure?
Crate A
struct Product {
name: String,
sku: String,
amount: i32,
}
Crate B
#[derive(copy_fields_from = "a::Product", InputObject)]
struct ProductApi {}
I have to expose several objects from another crate in an API that uses
"#[derive(InputObject)]". For that, I have to duplicate all the structures of the other structure. Is it possible to copy the fields of another structure? Perhaps using hypothetical syntax such as #[derive(copy_fields_from ="a::Product")].
No, there is no way of doing this cleanly.
If you felt you had to do this, you'd need to write a build script that:
Located the source code of the target crate.
Parsed the source code using a crate like syn.
Located the types in question.
Output them again.
See also:
How do I apply a macro attribute to a function defined in a separate module?
Add Serialize attribute to type from third-party lib
Is it possible for one struct to extend an existing struct, keeping all the fields?
For your specific case, I'd advocate implementing whatever trait(s) by hand.
Related
I have been working on configuration parsing code and wondered if you could help me to pick the best types for this code.
I am trying to parse the following TOML:
[default]
a=10
b="abc"
[section1]
a = 78
[section2]
b="xyz"
The types of keys are the same in each section and each field follows the chain of defaults: sectionX.value => default.value => default value hardcoded in Rust via x.value.or(default.value).or(Some(...) for each field.
The most straightforward way to declare it in Rust (including serde attributes)
struct Section{
a: Option<usize>,
b: Option<String>,
}
The problem is that I want to parse all defaults first, and then use a fully materialized struct with no unassigned values in my code.
struct Section{
a: usize,
b: String,
}
I can use the following approaches:
Use original Section struct and always to unwrap/expect because I "know" the defaults have been assigned in the config parsing code. I make a mistake, I can catch panic and that does not look tidy. I'd like to leverage more help from the compiler.
Use the second Section struct (the one that has no Options). I can assign defaults via Serde annotations, but then I am loosing the signal that something was unspecified and needs a default from another level.
Declare both variants of the struct. This is the most verbose variant and I will look even more verbose when I grow 20+ fields or embedded structs in the config.
Generated Solution 3 via macros or some clever typing. Is there a crate for this? Maybe Section could have some generic type that can be Option in one place, but then "newtype" wrapper with a single value somewhere else?
Something else?
Some of the solutions above would work alright, but maybe there is a known elegant solution.
I'm using tonic framework, a rust grpc server implementation. In the generated rust code from the proto file, I have a struct which has a field:
#[prost(message, optional, tag="3")]
pub data: ::core::option::Option<::prost_types::Value>,
generated from a protobuff field:
google.protobuf.Value data = 3;
I can't seem to find a way to init data which is type prost_types::Value by converting a struct I have. I'm doing something like:
prost_types::Value::try_from(myOwnsStructVar)
But it does not work. Anyone have used prost_types lib before and know how to encode/convert to prost_types::Value
myOwnsStructVar is a type struct. I need to convert it to prost_types::Struct So then I can do:
prost_types::value::Kind::StructValue(myOwnsStructVarAfterConversiontToProstStruct)
Just from looking at the docs, we can see that Value is a struct with a single public field kind which is of type Option<Kind>. The docs say that if this field is None then that indicates an error. If you look at the docs for Kind, then it's apparent this is where the actual data is stored. So if you want to initialize something of type Value then you'd want to do something like the following, substituting in the appropriate variant of Kind for your use case:
Value {
kind: Some(Kind::NumberValue(10.0f64))
}
The reason that your try_from solution didn't work is because there are no TryFrom implementations for Value other than the default blanket implementation.
I was curious whether it is possible to change the code inside the struct that uses derive macro, or are you only limited to generating the new code outside?
Example
Adding another field to the Building struct through SomeMacro.
#[derive(SomeMacro)]
pub struct Building {
colour: String,
// Add height: u8 through derive macro
}
It is not possible. This is a fundamental characteristic of derive macros: they take an existing item's tokens and generate new, separate items (usually trait impls).
If you want to modify the struct item itself, you must instead make an attribute macro, which can return a replacement for the input tokens. Attribute macros aren't invoked using the derive attribute but are attributes themselves: #[some_macro] pub struct Building { ...
Maybe this just bothers me, but in certain cases I'd like to have one struct per module file.
Let's say I have a struct named User like this:
struct User {
name: String
}
And let's say I have a file structure like where the User struct code is located in src/models/user.rs like this:
src/
models/
user.rs
And now I'd like to be able to use the User struct like this:
use crate::models::User;
Of course that's not possible. Instead it needs to be referred with:
use crate::models::user::User;
To me this looks quite ugly and I consider it redundant if both words, user and User, are part of the module path.
Is there any solution that doesn't seem to be as "clumsy" as the one just described?
It might as well be the case that I missed something regarding how the rust module naming system works.
You can re-export the User struct in the models module with pub use user::User; and optionally make the user submodule private (so that no one outside of models can access it). Externally, the User struct can then be referred to as a member of the models module with crate::models::User.
See also:
The Rust Reference: use Visibility
I'm trying to provide "views" of non-owned structs to separate components of a system.
Assume a set of traits with distinct methods: Drawable, Modifiable and a number of structs which implement at least one of the traits - SimpleBox, Panel, Expression.
Different components of the system will need to frequently access sequences of these objects, using methods of specific traits; consider a DrawingManager or a ModifyManager:
struct DrawingManager {
items: Vec<Weak<Drawable>>,
}
struct ModifyManager {
items: Vec<Weak<Modifiable>>
}
While a single object may be referenced in both managers, assume that there is a separate single owner of all structs:
struct ObjectManager {
boxes: Vec<Rc<Box>>,
panels: Vec<Rc<Panel>>,
expressions: Vec<Rc<Expression>>,
}
Ideally, it would be useful to be able to manage deleting structs from one place - i.e simply removing it from the ObjectManager being enough to invalidate references in all other components (hence the use of Weak).
Is there a way of doing this?
Is this the correct way to achieve this?
Is there a more idiomatic way of implementing this functionality?
The system contains several traits, so making a single trait using methods of all the other traits seems like a bad idea. Several traits have more than one method, so replacing them with closures is not possible.
What I have tried
As one object may produce one or more Rc<Trait>, we might envision implementing this with a HashMap<ID, Vec<Rc<Any>>> whereby we make each struct have a unique ID, which maps to a list of all Rc that have been made for it.
When we want to remove an object, we remove it from the corresponding list, and remove the entry in the hashmap, invalidating all Weak references.
However, implementing this fails, as to insert into the HashMap, one must upcast a Rc<Trait> -> Rc<Any>, only to downcast it later.
I'm not sure if this is the idiomatic way of doing this, but I've since developed a crate providing this functionality - dependent_view.
Using the crate, the initial problem can be solved by using DependentRc instead of plain Rc's:
struct ObjectManager {
boxes: Vec<DependentRc<Box>>,
panels: Vec<DependentRc<Panel>>,
expressions: Vec<DependentRc<Expression>>
}
let object_manager : ObjectManager = ObjectManager::new();
Then using macros provided by the crate, we can obtain Weak<> references to these structs:
let box_view : Weak<Drawable> = to_view!(object_manager.boxes[0]);
let panel_view : Weak<Drawable> = to_view!(object_manager.panels[0]);
let expression_view : Weak<Drawable> = to_view!(object_manager.expressions[0]);
With this, dropping the corresponding DependentRc<> will invalidate all Weak<> references that have been made of it.