mirror of
https://github.com/trussed-dev/serde-indexed.git
synced 2026-06-20 04:16:32 -07:00
Add index attribute for explicit index assignment
Fixes: https://github.com/trussed-dev/serde-indexed/issues/17
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
- No longer fails deserialising maps with unknown fields ([#19][])
|
||||
- Prefer explicit indexing over automatically assigned indices ([#17][]):
|
||||
- Require `auto_index` attribute to enable automatic index assignment
|
||||
- Add `index` attribute for explicit index assignment
|
||||
|
||||
[#2]: https://github.com/trussed-dev/serde-indexed/issues/2
|
||||
[#11]: https://github.com/trussed-dev/serde-indexed/pull/11
|
||||
|
||||
+3
-2
@@ -8,11 +8,12 @@ and a custom `offset` container attribute.
|
||||
use serde_indexed::{DeserializeIndexed, SerializeIndexed};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, SerializeIndexed, DeserializeIndexed)]
|
||||
#[serde_indexed(auto_index, offset = 1)]
|
||||
pub struct SomeKeys {
|
||||
#[serde(index = 1)]
|
||||
pub number: i32,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(index = 2, skip_serializing_if = "Option::is_none")]
|
||||
pub option: Option<u8>,
|
||||
#[serde(index = 3)]
|
||||
pub bytes: [u8; 7],
|
||||
}
|
||||
```
|
||||
|
||||
+36
-9
@@ -113,7 +113,12 @@ impl Parse for Input {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_field(index: usize, field: &syn::Field) -> Result<Field> {
|
||||
fn parse_field(
|
||||
attrs: &StructAttrs,
|
||||
auto_index: usize,
|
||||
field: &syn::Field,
|
||||
indices: &mut Vec<usize>,
|
||||
) -> Result<Field> {
|
||||
let ident = field
|
||||
.ident
|
||||
.as_ref()
|
||||
@@ -123,6 +128,7 @@ fn parse_field(index: usize, field: &syn::Field) -> Result<Field> {
|
||||
let mut deserialize_with = None;
|
||||
let mut serialize_with = None;
|
||||
let mut no_increment = false;
|
||||
let mut explicit_index = None;
|
||||
|
||||
for attr in &field.attrs {
|
||||
if attr.path().is_ident("serde") {
|
||||
@@ -191,6 +197,22 @@ fn parse_field(index: usize, field: &syn::Field) -> Result<Field> {
|
||||
serialize_with = Some(syn::parse2(serialize_tokens)?);
|
||||
deserialize_with = Some(syn::parse2(deserialize_tokens)?);
|
||||
|
||||
Ok(())
|
||||
} else if meta.path.is_ident("index") {
|
||||
if explicit_index.is_some() {
|
||||
return Err(meta.error("Multiple attributes for index"));
|
||||
}
|
||||
if attrs.auto_index {
|
||||
return Err(meta.error(
|
||||
"The index attribute cannot be combined with the auto_index attribute",
|
||||
));
|
||||
}
|
||||
let litint: LitInt = meta.value()?.parse()?;
|
||||
let int = litint.base10_parse()?;
|
||||
if indices.contains(&int) {
|
||||
return Err(meta.error("This index has already been assigned"));
|
||||
}
|
||||
explicit_index = Some(int);
|
||||
Ok(())
|
||||
} else {
|
||||
return Err(meta.error("Unkown field attribute"));
|
||||
@@ -199,6 +221,17 @@ fn parse_field(index: usize, field: &syn::Field) -> Result<Field> {
|
||||
}
|
||||
}
|
||||
|
||||
let index = if attrs.auto_index {
|
||||
auto_index
|
||||
} else if let Some(index) = explicit_index {
|
||||
indices.push(index);
|
||||
index
|
||||
} else {
|
||||
return Err(Error::new_spanned(
|
||||
field,
|
||||
"Field without index attribute and `#[serde(auto_index)]` is not enabled on the struct",
|
||||
));
|
||||
};
|
||||
Ok(Field {
|
||||
label: ident.to_string(),
|
||||
member: syn::Member::Named(ident.clone()),
|
||||
@@ -216,18 +249,12 @@ fn fields_from_ast(
|
||||
attrs: &StructAttrs,
|
||||
fields: &syn::punctuated::Punctuated<syn::Field, Token![,]>,
|
||||
) -> Result<Vec<Field>> {
|
||||
if !attrs.auto_index {
|
||||
return Err(Error::new_spanned(
|
||||
fields,
|
||||
"auto_index attribute must be set",
|
||||
));
|
||||
}
|
||||
|
||||
let mut indices = Vec::new();
|
||||
let mut index = 0;
|
||||
fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let field = parse_field(index, field)?;
|
||||
let field = parse_field(attrs, index, field, &mut indices)?;
|
||||
if !field.no_increment {
|
||||
index += 1;
|
||||
}
|
||||
|
||||
@@ -617,3 +617,42 @@ mod generics {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
mod index {
|
||||
use super::*;
|
||||
|
||||
#[derive(PartialEq, Debug, SerializeIndexed, DeserializeIndexed)]
|
||||
struct WithIndices {
|
||||
#[serde(index = 9)]
|
||||
test1: usize,
|
||||
#[serde(index = 2)]
|
||||
test2: usize,
|
||||
#[serde(index = 0x5A)]
|
||||
test3: usize,
|
||||
}
|
||||
|
||||
fn indices_example() -> WithIndices {
|
||||
WithIndices {
|
||||
test1: 42,
|
||||
test2: 1,
|
||||
test3: 99,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tokens() {
|
||||
assert_tokens(
|
||||
&indices_example(),
|
||||
&[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U64(9),
|
||||
Token::U64(42),
|
||||
Token::U64(2),
|
||||
Token::U64(1),
|
||||
Token::U64(0x5A),
|
||||
Token::U64(99),
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user