1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use super::*;
pub mod roots {
use syn::{parse_quote, Path};
use super::*;
#[derive(FromAttributes, Default)]
#[darling(attributes(xvalue))]
pub struct RootValueOpts {
/// The text casing to use for unit variants when serializing and deserializing.
#[darling(default)]
pub rename_all: RenameRule,
/// The path to the module that provides the serialization and deserialization functions.
///
/// `::serialize` and `::deserialize` will be appended to this path and used as the `serialize_with` and `deserialize_with` functions.
#[darling(default)]
pub with: Option<Path>,
/// Use function to serialize the value.
///
/// Should have signature like `pub fn serialize<S: xmlity::Serializer>(value: &T, serializer: S) -> Result<S::Ok, S::Error>`
#[darling(default)]
pub serialize_with: Option<Expr>,
/// Use function to deserialize the value.
///
/// Should have signature like `fn deserialize<'de, D: xmlity::Deserializer<'de>>(deserializer: D) -> Result<T, D::Error>`
#[darling(default)]
pub deserialize_with: Option<Expr>,
}
impl RootValueOpts {
pub fn parse(ast: &DeriveInput) -> Result<Option<Self>, DeriveError> {
let Some(attr) = ast.attrs.iter().find(|attr| attr.path().is_ident("xvalue")) else {
return Ok(None);
};
let opts = Self::from_attributes(std::slice::from_ref(attr))?;
Ok(Some(opts))
}
pub fn serialize_with(&self) -> Option<Expr> {
self.serialize_with
.as_ref()
.map(|serialize_with| {
parse_quote! {
#serialize_with
}
})
.or_else(|| {
self.with.as_ref().map(|with| {
parse_quote! {
#with::serialize
}
})
})
}
pub fn deserialize_with(&self) -> Option<Expr> {
self.deserialize_with
.as_ref()
.map(|deserialize_with| {
parse_quote! {
#deserialize_with
}
})
.or_else(|| {
self.with.as_ref().map(|with| {
parse_quote! {
#with::deserialize
}
})
})
}
}
#[allow(clippy::large_enum_variant)]
pub enum RootOpts {
None,
Value(RootValueOpts),
}
impl RootOpts {
pub fn parse(ast: &syn::DeriveInput) -> Result<Self, DeriveError> {
let value_opts = RootValueOpts::parse(ast)?;
match value_opts {
Some(value_opts) => Ok(RootOpts::Value(value_opts)),
None => Ok(RootOpts::None),
}
}
}
}
pub mod variants {
use syn::Attribute;
use crate::options::records::roots::{RootAttributeOpts, RootElementOpts};
use super::*;
#[derive(Default, FromAttributes, Clone)]
#[darling(attributes(xvalue))]
pub struct RootValueOpts {
/// The text value to use for unit variants when serializing and deserializing.
pub value: Option<String>,
/// Set if whitespace should be ignored when deserializing.
/// - `Any` (*default*): Ignore any whitespace.
/// - `None`: Do not ignore whitespace.
///
/// *Deserialize only*
#[darling(default)]
pub ignore_whitespace: IgnoreWhitespace,
/// Set if comments should be ignored when deserializing.
/// - `Any` (*default*): Ignore any comments.
/// - `None`: Do not ignore comments.
///
/// *Deserialize only*
#[darling(default)]
pub ignore_comments: IgnoreComments,
/// Allow unknown values when deserializing.
/// - `Any`: Allow any unknown values.
/// - `AtEnd` (*default*): Allow unknown values only at the end of the element.
/// - `None`: Do not allow unknown values at all.
///
/// *Deserialize only*
#[darling(default)]
pub allow_unknown: AllowUnknown,
/// Set if the order of values is important when serializing or deserializing.
/// - `Strict`: The order of values must match the order in the struct or enum variant.
/// - `None` (*default*): The order of values does not matter, but the values must be present.
///
/// *Deserialize only*
#[darling(default)]
pub order: ElementOrder,
}
impl RootValueOpts {
pub fn parse(attrs: &[Attribute]) -> Result<Option<Self>, DeriveError> {
let Some(attr) = attrs.iter().find(|attr| attr.path().is_ident("xvalue")) else {
return Ok(None);
};
let opts = Self::from_attributes(std::slice::from_ref(attr))?;
Ok(Some(opts))
}
}
pub enum DeserializeRootOpts {
None,
Element(RootElementOpts),
Attribute(RootAttributeOpts),
Value(RootValueOpts),
}
impl DeserializeRootOpts {
pub fn parse(attrs: &[Attribute]) -> Result<Self, DeriveError> {
let element_opts = RootElementOpts::parse(attrs)?;
let attribute_opts = RootAttributeOpts::parse(attrs)?;
let value_opts = RootValueOpts::parse(attrs)?;
match (element_opts, attribute_opts, value_opts) {
(Some(element_opts), None, None) => Ok(Self::Element(element_opts)),
(None, Some(attribute_opts), None) => Ok(Self::Attribute(attribute_opts)),
(None, None, Some(value_opts)) => Ok(Self::Value(value_opts)),
(None, None, None) => Ok(Self::None),
_ => Err(DeriveError::custom("Wrong options. Only one of `xelement`, `xattribute`, or `xvalue` can be used for root elements.")),
}
}
}
}