I'm trying to create a function arg and other things in syn and often I see a need for a span:
FnArg::Typed(PatType {
attrs: vec![],
pat: Box::new(Pat::Ident(PatIdent {
attrs: vec![],
by_ref: Some(Ref { span: ? }),
mutability: None,
ident: Ident::new(struct_name.as_str(), ?),
subpat: None,
})),
colon_token: Colon { spans: item_impl. },
ty: todo!(),
})
which is not even from syn but from proc_macro.
What exactly is a Span and what do I need to put in span above?
Span is the information about where a token is textually located in a file (i.e. the line and column numbers), as well what macro (if any) generated it.
The compiler uses the span information of a token in two major ways:
Error reporting. If a parser or compiler error occurs relating to the token, it will report the error using the token's span.
Properly maintaining the span of tokens you generate can be the difference between a compiler error highlighting only the relevant part inside of a procedural macro versus highlighting the entire procedural macro body.
Macro hygiene. Rust macros' hygiene system means that variables, labels, etc declared inside of a macro_rules macro are not visible to the call site, and vice versa, without explicitly passing them in, even if they use the same name. The span contains the info about what "context" a variable was declared in, so that they don't conflict.
What span to use is context dependent and based a lot on what you are using your procedural macro for. My general advice is, if you are generating some code "based on" some input to the procedural macro, try to copy the span of the tokens that most influence that generated code, so that if there is an error, the cause of it will be easily identifiable.
Related
So I have this component called BulletSpawner which spawns bullets every once in a while. I want this component to be as versatile as possible for my Danmaku game so that I don't have to change it again later. So it has fields like a TrajectoryBuilder for the trajectory of the bullets. And I wanted to include a field to allow inserting components on the bullet. That way, I could have multiple BulletSpawner spawning bullet with different shapes, sprites, etc... track the bullets a specific BulletSpawner had spawned.
I first tried writing the field to_insert: Arc<dyn Bundle> but it messaged me that 'Bundle' couldn't be made into an object. So I tried to use a vector of components to_insert: Vec<Arc<Component<Storage=Table>>> and that way it accepted the field. but now I have issues writing the snippet of code to insert the components
for component: &Arc<dyn Component<Storage=Table>> in bullet_spawner.to_insert.iter() {
new_bullet.insert(*Arc::borrow(component));
}
but now it's telling me that type annotation is needed, as it cannot infer the type for the type parameter 'impl Bundle' of the associated function insert.
These methods however feel like hacking so I would prefer an 'official' way.
I believe that what you have won't work in Bevy due to how it uses types for Components. When you store dyn Component there isn't a way back to the solid type that Bevy needs to work out which table to store it in.
Instead, you could change the design a little for the BulletSpawner so that it owns a function instead of instantiated components. e.g.
#[derive(Component)]
struct BulletSpawner {
// e.g. bundle: Bullet,
bundle_fn: Box<dyn Fn(&Commands) + Send + Sync>,
}
impl BulletSpawner {
fn create_bullet(&self, cmds: &Commands) {
(self.bundle_fn)(cmds);
}
}
fn spawner_startup_system(cmds: Commands) {
// Add new "spawner"
cmds.spawn(BulletSpawner {
bundle_fn: Box::new(|cmds| {
cmds.spawn(FastBullet {});
}),
});
}
That said, this still feels a little off. Splitting the concept of the BulletSpawner into multiple Component's might make for a more understandable structure, e.g. FastBulletSpawner.
Sample code :
use serde_json::{json, Value};
fn main() {
let a: Rc<RefCell<Value>> = Rc::new(RefCell::new(json!({"a": "value"})));
let v: Rc<RefCell<Vec<Value>>> = Rc::new(RefCell::new(vec![]));
// How to push a into v, but keep `a` and `v` for future uses
}
I want to push Value a into vector v (link pointer), but still be able to use a later on.
I've tried the following:
1.
v.borrow_mut().push(*a.borrow_mut());
This does not work, as Value does not implement Copy trait, thus could not be dereferenced
2.
v.borrow_mut().push(RefCell::take(&a));
This works, however a has now lost the contents. I do understand that there should only be one owner, but I'm not sure how to achieve what I need.
The Why
I have a Value which I need to modify depending on some other data which is in a tree structure. I want to recursively walk through that other data tree, and pass along this Value to be modified.
In my function, I have this Value signature as Rc<RefCell<Value>>, and depending on the case I sometimes need to add nested properties, so I may need to add a property containing a vector with a new json!({}), and pass it as a new Rc<RefCell<Value>> to sub-iterations to append data to this specific subtree.
So, if you have any advice - maybe I need to change the recursive function's signature to have this data as Rc<RefCell<&Value>> instead, to have only one owner ? That seems like an awful lot of all sorts of references stacked upon one another, not sure which is the good way
Edit1: Updated sample to include Rc<RefCell<_>>
I'd like to additively deserialize multiple files over the same data structure, where "additively" means that each new file deserializes by overwriting the fields that it effectively contains, leaving unmodified the ones that it does not. The context is config files; deserialize an "app" config provided by the app, then override it with a per-"user" config file.
I use "file" hear for the sake of clarity; this could be any deserializing data source.
Note: After writing the below, I realized maybe the question boils down to: is there a clever use of #[serde(default = ...)] to provide a default from an existing data structure? I'm not sure if that's (currently) possible.
Example
Data structure
struct S {
x: f32,
y: String,
}
"App" file (using JSON for example):
{ "x": 5.0, "y": "app" }
"User" file overriding only "y":
{ "y": "user" }
Expected deserializing (app, then user):
assert_eq!(s.x, 5.0);
assert_eq!(s.y, "user");
Expected solution
I'm ignoring on purpose any "dynamic" solution storing all config settings into, say, a single HashMap; although this works and is flexible, this is fairly inconvenient to use at runtime, and potentially slower. So I'm calling this approach out of scope for this question.
Data structure can contain other structs. Avoid having to write too many per-struct code manually (like implementing Deserialize by hand). A typical config file for a moderate-sized app can contains hundreds of settings, I don't want the burden of having to maintain those.
All fields can be expected to implement Default. The idea is that the first deserialized file would fallback on Default::default() for all missing fields, while subsequent ones would fallback on already-existing values if not explicitly overridden in the new file.
Avoid having to change every single field of every single struct to Option<T> just for the sake of serializing/deserializing. This would make runtime usage very painful, where due to above property there would anyway be no None value ever once deserialization completed (since, if a field is missing from all files, it defaults to Default::default() anyway).
I'm fine with a solution containing only a fixed number (2) of overriding files ("app" and "user" in example above).
Current partial solution
I know how to do the first part of falling back to Default; this is well documented. Simply use #[serde(default)] on all structs.
One approach would be to simply deserialize twice with #[serde(default)] and override any field which is equal to its default in the app config with its value in the user config. But this 1) probably requires all fields to implement Eq or PartialEq, and 2) is potentially expensive and not very elegant (lose the info during deserialization, then try to somehow recreate it).
I have a feeling I possibly need a custom Deserializer to hold a reference/value of the existing data structure, which I would fallback to when a field is not found, since the default one doesn't provide any user context when deserializing. But I'm not sure how to keep track of which field is currently being deserialized.
Any hint or idea much appreciated, thanks!
Frustratingly, serde::Deserialize has a method called deserialize_in_place that is explicitly omitted from docs.rs and is considered "part of the public API but hidden from rustdoc to hide it from newbies". This method does exactly what you're asking for (deserialize into an existing &mut T object), especially if you implement it yourself to ensure that only provided keys are overridden and other keys are ignored.
Specifically, I'm trying to put macro output into a doc comment. I was excited that this does exactly what I want:
/// foo
///
#[doc="bar\n\nbaz"]
///
/// quux
struct Dummy;
The next step would be to replace that string with my content. According to this, I can't write #[doc=my_content!()], and attribute macros are procedural, so I need another crate for that, plus (I think) my content could be generated without the need for any procedural macro features.
Is there a way to do this with "conventional macros" in some way, or am I out of luck?
Edit: starting with 1.54.0, Attributes can invoke function-like macros, enabling the code proposed in the question. Original answer below :
The answer seems to be no.
Looking at the grammar for attributes, apart from parentheses, commas and equals signs, attributes can ultimately only contain literals. So on this level, there is no way Rust allows more here.
However, inverting the structure enables something like this, and the doc-comment crate does this for doc comments. Instead of calling a macro from inside an attribute, use a macro to create an attribute; that macro is then not constrained to only taking literals*. The downside is, the item that the attribute should apply to must be part of the macro call. So this
#[doc=my_content!()]
struct Foo;
becomes this:
doc_comment!(
my_content!(),
struct Foo;
);
The definition of the macro is straight-forward:
#[macro_export]
macro_rules! doc_comment {
($x:expr, $($tt:tt)*) => {
#[doc = $x]
$($tt)*
};
}
(omitted a branch of the original macro that is not part of the core pattern)
(thanks to jonas-schlevink for pointing me to this)
*except for that last part (getting macro content into the attribute), the linked question's answer already does exactly that.
I have a massively repeating code pattern like this:
public SomeReturnType InitiateAndSecureTransaction(string token, IPaymentDetailsUpdateable paymentDetails)
{
return WithService<MyServiceClient, SomeReturnType>(proxy => proxy.InitiateAndSecureTransaction(token, paymentDetails));
}
To help me implement this pattern in some fifty odd methods, I have a live template like this:
return WithService<$CLASS_NAME$ServiceClient, $RETURN_TYPE$>(proxy => proxy.$CONTAINING_METHOD$($PARAMS$));
The $PARAMS$ parameter is assigned the macro Execute smart completion, and this works wonderfully, but I'm spoilt. I insert the whole WithService call with about three tabs, but ReSharper only gets the first parameter of the enclosing method, and I have to intellisense through the rest. Is there any way I can simply copy all of the enclosing method's paramaters?