Skip to content

Commit 07586db

Browse files
Add index attribute for explicit index assignment
Fixes: #17
1 parent 3deb892 commit 07586db

File tree

4 files changed

+79
-11
lines changed

4 files changed

+79
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- No longer fails deserialising maps with unknown fields ([#19][])
1212
- Prefer explicit indexing over automatically assigned indices ([#17][]):
1313
- Require `auto_index` attribute to enable automatic index assignment
14+
- Add `index` attribute for explicit index assignment
1415

1516
[#2]: https://github.com/trussed-dev/serde-indexed/issues/2
1617
[#11]: https://github.com/trussed-dev/serde-indexed/pull/11

src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ and a custom `offset` container attribute.
88
use serde_indexed::{DeserializeIndexed, SerializeIndexed};
99
1010
#[derive(Clone, Debug, PartialEq, SerializeIndexed, DeserializeIndexed)]
11-
#[serde_indexed(auto_index, offset = 1)]
1211
pub struct SomeKeys {
12+
#[serde(index = 1)]
1313
pub number: i32,
14-
#[serde(skip_serializing_if = "Option::is_none")]
14+
#[serde(index = 2, skip_serializing_if = "Option::is_none")]
1515
pub option: Option<u8>,
16+
#[serde(index = 3)]
1617
pub bytes: [u8; 7],
1718
}
1819
```

src/parse.rs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,12 @@ impl Parse for Input {
113113
}
114114
}
115115

116-
fn parse_field(index: usize, field: &syn::Field) -> Result<Field> {
116+
fn parse_field(
117+
attrs: &StructAttrs,
118+
auto_index: usize,
119+
field: &syn::Field,
120+
indices: &mut Vec<usize>,
121+
) -> Result<Field> {
117122
let ident = field
118123
.ident
119124
.as_ref()
@@ -123,6 +128,7 @@ fn parse_field(index: usize, field: &syn::Field) -> Result<Field> {
123128
let mut deserialize_with = None;
124129
let mut serialize_with = None;
125130
let mut no_increment = false;
131+
let mut explicit_index = None;
126132

127133
for attr in &field.attrs {
128134
if attr.path().is_ident("serde") {
@@ -191,6 +197,22 @@ fn parse_field(index: usize, field: &syn::Field) -> Result<Field> {
191197
serialize_with = Some(syn::parse2(serialize_tokens)?);
192198
deserialize_with = Some(syn::parse2(deserialize_tokens)?);
193199

200+
Ok(())
201+
} else if meta.path.is_ident("index") {
202+
if explicit_index.is_some() {
203+
return Err(meta.error("Multiple attributes for index"));
204+
}
205+
if attrs.auto_index {
206+
return Err(meta.error(
207+
"The index attribute cannot be combined with the auto_index attribute",
208+
));
209+
}
210+
let litint: LitInt = meta.value()?.parse()?;
211+
let int = litint.base10_parse()?;
212+
if indices.contains(&int) {
213+
return Err(meta.error("This index has already been assigned"));
214+
}
215+
explicit_index = Some(int);
194216
Ok(())
195217
} else {
196218
return Err(meta.error("Unkown field attribute"));
@@ -199,6 +221,17 @@ fn parse_field(index: usize, field: &syn::Field) -> Result<Field> {
199221
}
200222
}
201223

224+
let index = if attrs.auto_index {
225+
auto_index
226+
} else if let Some(index) = explicit_index {
227+
indices.push(index);
228+
index
229+
} else {
230+
return Err(Error::new_spanned(
231+
field,
232+
"Field without index attribute and `#[serde(auto_index)]` is not enabled on the struct",
233+
));
234+
};
202235
Ok(Field {
203236
label: ident.to_string(),
204237
member: syn::Member::Named(ident.clone()),
@@ -216,18 +249,12 @@ fn fields_from_ast(
216249
attrs: &StructAttrs,
217250
fields: &syn::punctuated::Punctuated<syn::Field, Token![,]>,
218251
) -> Result<Vec<Field>> {
219-
if !attrs.auto_index {
220-
return Err(Error::new_spanned(
221-
fields,
222-
"auto_index attribute must be set",
223-
));
224-
}
225-
252+
let mut indices = Vec::new();
226253
let mut index = 0;
227254
fields
228255
.iter()
229256
.map(|field| {
230-
let field = parse_field(index, field)?;
257+
let field = parse_field(attrs, index, field, &mut indices)?;
231258
if !field.no_increment {
232259
index += 1;
233260
}

tests/basics.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,3 +617,42 @@ mod generics {
617617
)
618618
}
619619
}
620+
621+
mod index {
622+
use super::*;
623+
624+
#[derive(PartialEq, Debug, SerializeIndexed, DeserializeIndexed)]
625+
struct WithIndices {
626+
#[serde(index = 9)]
627+
test1: usize,
628+
#[serde(index = 2)]
629+
test2: usize,
630+
#[serde(index = 0x5A)]
631+
test3: usize,
632+
}
633+
634+
fn indices_example() -> WithIndices {
635+
WithIndices {
636+
test1: 42,
637+
test2: 1,
638+
test3: 99,
639+
}
640+
}
641+
642+
#[test]
643+
fn tokens() {
644+
assert_tokens(
645+
&indices_example(),
646+
&[
647+
Token::Map { len: Some(3) },
648+
Token::U64(9),
649+
Token::U64(42),
650+
Token::U64(2),
651+
Token::U64(1),
652+
Token::U64(0x5A),
653+
Token::U64(99),
654+
Token::MapEnd,
655+
],
656+
);
657+
}
658+
}

0 commit comments

Comments
 (0)