Comments (7)
Instead of extending skip_serializing_none
, I would suggest using serde_with::apply
unless there is a reason you cannot do so. It applies a set of other attributes to all fields with a matching type. In your case, you want the serde attribute that you write above each field, as part of the apply
macro. You can cover both structs OptOneMany
and FileConfigEnum
in a single invocation.
#[serde_with::apply(
OptOneMany => #[serde(default, skip_serializing_if = "OptOneMany::is_none")],
FileConfigEnum => ...,
)]
#[derive(Serialize)]
struct Foo {
field: OptOneMany,
}
from serde_with.
@jonasbb thanks, I didn't realize apply
could do that, thanks. The only issue I see is that I would still have to do it everywhere - which would become fairly verbose because of all duplications (I have 5-10 structs used for serialization). Ideally, I think it would be far more useful if skip_serialize_none
could be extended to tell it which enums behave "like Option" - i.e. to add an attribute on my own custom types:
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[serde_with::treat_as_option(NoVals)] // <-- this tells serde_with that NoVals is just like Option::None
pub enum OptOneMany<T> {
#[default]
NoVals,
One(T),
Many(Vec<T>),
}
from serde_with.
Rust macros do not work like that. I don't know of any way that would make this work.
Rust macros work on token only. They cannot know what type something is, since they run before typechecking. This makes it impossible for the skip_serialize_none
to lookup how to handle OptOneMany
. skip_serializing_none
only recognizes some patterns as Option
. They are listed under Limitations. Even a rename, like use std::option::Option as FooBar
will break the macro.
Another problem is that macro execution order is undefined. You cannot be sure that #[serde_with::treat_as_option(NoVals)]
will be processed before skip_serialize_none
.
The only option would be to make the OptOneMany
look basically indistinguishable from the real Option
type. I do not recommend this approach. It would require renaming/aliasing the type, having a is_none
function, etc.
from serde_with.
@jonasbb thanks for in depth explanation, agree, sadly it seems like a no go. One option of course would be to use the trait system rather than (or in addition to) the macros. Something like pub trait IsOptionable { fn is_none(&self) -> bool; }
. You would implement that trait on the Option object (and possibly a few others?), but then each other non-option value would still have to be tagged with some attribute like #[optionable]
- at least once per type in each struct (e.g. if there are multiple instances of the same type, derive macro can notice that the same type has already been identified as optionable.
from serde_with.
The skip_serialize_none
macro needs to decide at compile time, before type checking, if a field is of type Option
or not. I am not sure how you think the macro is supposed to use the IsOptionable
trait. Could you expand how you imagine that to work?
from serde_with.
#[derive(Serialize)]
#[skip_serializing_none]
struct Foo {
#[SkipIfNone] // <- this tells serde_with that field1, as well as other fields
field1: OptOneMany, // of type OptOneMany should be treated as having a .is_none()
// Technically we do not even need a dedicated trait - enough to just
field2: OptOneMany,
field3: OptOneMany,
field4: SomeOtherType, // <-- serialized as usual
}
To be honest, I am not too thrilled about this solution either -- magic is usually bad. The cleaner (but still a bit hacky?) is this:
#[derive(Serialize)]
#[skip_serializing_none(OptOneMany)] // <-- all fields of the listed types are assumed to have .is_none()
struct Foo {
field1: OptOneMany,
field2: OptOneMany,
field3: OptOneMany,
}
from serde_with.
I rather not complicate skip_serializing_none
with such type matching logic. It feels wrong to just work based on "magic" function names like is_none
here. The apply
macro is made for it. Yes, it can be a bit verbose, but I rather fix that.
from serde_with.
Related Issues (20)
- Question about minimum serde version HOT 6
- Serialize enum without tags HOT 2
- [usage question] Using DurationSeconds in a hashmap HOT 1
- unable to use chrono::DateTime<Utc> HOT 1
- RUSTSEC-2023-0075: Unaligned write of u64 on 32-bit and 16-bit platforms
- Support for serde_as attached to a struct decl (not a field) - multi-field struct with canonical representation via a primitive (e.g. String) HOT 3
- Bug? DisplayFromStr does not use FromStr and accepts invalid values - protected agains inside of impl of FromStr, attached demo HOT 2
- gate `serde_as` behind `is_human_readable` HOT 2
- [Feature request] Deserialization that only uses `FromStr` as a fallback HOT 3
- Feature Request: DurationMinutes
- Bool from anything HOT 1
- VecSkipError fails on tagged enum HOT 3
- Unable to use `serde_with::serde_as` in conjunction with `schemars(schema_with)` HOT 3
- how to deserialize duration like 30s HOT 1
- OneOrMany serialization not implemented? HOT 4
- `#[serde_as(deserialize_as = …)]` generates `#[schemars(deserialize_with(…))]`, which is invalid HOT 1
- serde_with without android dependencies HOT 1
- Deserialize a sequence from a map by ignoring keys HOT 2
- can I combine `#[serde(default = "default_template")]` and `#[serde_as(deserialize_as = "DefaultOnNull")]` HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from serde_with.