Skip to content

Commit 63980dd

Browse files
Merge branch 'main' into transit
2 parents 0628291 + b2c8816 commit 63980dd

File tree

27 files changed

+345
-57
lines changed

27 files changed

+345
-57
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use swim_form_derive::*;
2+
3+
fn main() {
4+
#[allow(non_snake_case)]
5+
#[derive(Form)]
6+
#[form_root(::swim_form)]
7+
enum Duplicates {
8+
First {
9+
#[form(convention = "camel")]
10+
first_field: i32,
11+
firstField: i32,
12+
},
13+
#[form(fields_convention = "camel")]
14+
Second {
15+
first_field: i32,
16+
#[form(name = "firstField")]
17+
second_field: i32,
18+
}
19+
}
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Form field names must be unique. Duplicated names: [firstField]
2+
--> src/tests/derive/form/enum_duplicate_fields.rs:8:9
3+
|
4+
8 | / First {
5+
9 | | #[form(convention = "camel")]
6+
10 | | first_field: i32,
7+
11 | | firstField: i32,
8+
12 | | },
9+
| |_________^
10+
11+
error: Form field names must be unique. Duplicated names: [firstField]
12+
--> src/tests/derive/form/enum_duplicate_fields.rs:13:9
13+
|
14+
13 | / #[form(fields_convention = "camel")]
15+
14 | | Second {
16+
15 | | first_field: i32,
17+
16 | | #[form(name = "firstField")]
18+
17 | | second_field: i32,
19+
18 | | }
20+
| |_________^
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use swim_form_derive::*;
2+
3+
fn main() {
4+
#[allow(non_snake_case)]
5+
#[derive(Form)]
6+
#[form_root(::swim_form)]
7+
enum Duplicates {
8+
First {
9+
first_field: i32,
10+
second_Field: i32,
11+
},
12+
#[form(tag = "First")]
13+
Second,
14+
}
15+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: Duplicate enumeration tag: "First"
2+
--> src/tests/derive/form/enum_duplicate_tags.rs:4:5
3+
|
4+
4 | / #[allow(non_snake_case)]
5+
5 | | #[derive(Form)]
6+
6 | | #[form_root(::swim_form)]
7+
7 | | enum Duplicates {
8+
... |
9+
13 | | Second,
10+
14 | | }
11+
| |_____^
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use swim_form_derive::*;
2+
3+
fn main() {
4+
#[derive(Form)]
5+
#[form_root(::swim_form)]
6+
#[allow(non_snake_case)]
7+
struct Duplicates {
8+
#[form(convention = "camel")]
9+
second_field: i32,
10+
secondField: String,
11+
}
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: Form field names must be unique. Duplicated names: [secondField]
2+
--> src/tests/derive/form/struct_duplicate_fields.rs:6:5
3+
|
4+
6 | / #[allow(non_snake_case)]
5+
7 | | struct Duplicates {
6+
8 | | #[form(convention = "camel")]
7+
9 | | second_field: i32,
8+
10 | | secondField: String,
9+
11 | | }
10+
| |_____^

api/swim_form_derive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ proc-macro = true
1010

1111
[dependencies]
1212
either = { workspace = true }
13-
swim_utilities = { path = "../../swim_utilities", features = ["errors"] }
13+
swim_utilities = { path = "../../swim_utilities", features = ["errors", "text"] }
1414
macro_utilities = { path = "../../macro_utilities" }
1515
proc-macro2 = { workspace = true }
1616
syn = { workspace = true, features = ["full"] }

api/swim_form_derive/src/structural/mod.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::structural::read::DeriveStructuralReadable;
2020
use crate::structural::write::DeriveStructuralWritable;
2121
use proc_macro2::TokenStream;
2222
use quote::ToTokens;
23+
use swim_utilities::errors::validation::Validation;
2324
use swim_utilities::errors::Errors;
2425
use syn::{Data, DeriveInput, Generics};
2526

@@ -67,11 +68,25 @@ pub fn build_derive_structural_writable(
6768
}
6869
}
6970

71+
fn validate_and_check_fields<Flds>(
72+
input: StructDef<'_, Flds>,
73+
) -> Result<StructModel, Errors<syn::Error>>
74+
where
75+
Flds: StructLike,
76+
{
77+
StructModel::validate(input)
78+
.and_then(|model| match model.check_field_names(input.source()) {
79+
Ok(_) => Validation::valid(model),
80+
Err(err) => Validation::Validated(model, Errors::of(err)),
81+
})
82+
.into_result()
83+
}
84+
7085
fn struct_derive_structural_writable<'a, Flds: StructLike>(
7186
input: StructDef<'a, Flds>,
7287
generics: &'a Generics,
7388
) -> Result<TokenStream, Errors<syn::Error>> {
74-
let model = StructModel::validate(input).into_result()?;
89+
let model = validate_and_check_fields(input)?;
7590
let segregated = SegregatedStructModel::from(&model);
7691
let derive = DeriveStructuralWritable(segregated, generics);
7792
Ok(derive.into_token_stream())
@@ -81,7 +96,7 @@ fn struct_derive_structural_form<'a, Flds: StructLike>(
8196
input: StructDef<'a, Flds>,
8297
generics: &'a Generics,
8398
) -> Result<TokenStream, Errors<syn::Error>> {
84-
let model = StructModel::validate(input).into_result()?;
99+
let model = validate_and_check_fields(input)?;
85100
let segregated = SegregatedStructModel::from(&model);
86101
let derive_writable = DeriveStructuralWritable(segregated.clone(), generics);
87102
let derive_readable = DeriveStructuralReadable(segregated, generics);
@@ -139,7 +154,7 @@ fn struct_derive_structural_readable<Flds: StructLike>(
139154
input: StructDef<'_, Flds>,
140155
generics: &Generics,
141156
) -> Result<TokenStream, Errors<syn::Error>> {
142-
let model = StructModel::validate(input).into_result()?;
157+
let model = validate_and_check_fields(input)?;
143158
let segregated = SegregatedStructModel::from(&model);
144159
let derive = DeriveStructuralReadable(segregated, generics);
145160
Ok(derive.into_token_stream())

api/swim_form_derive/src/structural/model/enumeration/mod.rs

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use macro_utilities::attr_names::FORM_NAME;
2020
use macro_utilities::attributes::consume_attributes;
2121
use quote::ToTokens;
2222
use std::collections::HashSet;
23-
use swim_utilities::errors::validation::{validate2, Validation, ValidationItExt};
23+
use swim_utilities::errors::validation::{Validation, ValidationItExt};
2424
use swim_utilities::errors::Errors;
2525
use syn::{Attribute, DataEnum, Ident};
2626

@@ -108,37 +108,50 @@ impl<'a> ValidateFrom<EnumDef<'a>> for EnumModel<'a> {
108108
let transform = Validation::Validated(parts, Errors::from(errs))
109109
.and_then(|parts| combine_enum_trans_parts(top, parts));
110110

111-
let init = Validation::valid(Vec::with_capacity(num_var));
112-
let variants =
113-
definition
114-
.variants
115-
.iter()
116-
.validate_fold(init, false, |mut var_models, variant| {
117-
let struct_def =
118-
StructDef::new(root, &variant.ident, variant, &variant.attrs, variant);
119-
let model = StructModel::validate(struct_def).and_then(|model| {
111+
let init = transform.map(|t| (t, Vec::with_capacity(num_var)));
112+
let variants = definition.variants.iter().validate_fold(
113+
init,
114+
false,
115+
|(transform, mut var_models), variant| {
116+
let struct_def =
117+
StructDef::new(root, &variant.ident, variant, &variant.attrs, variant);
118+
let model = StructModel::validate(struct_def)
119+
.map(|mut v| {
120+
v.apply(&transform);
121+
v
122+
})
123+
.and_then(|v| {
124+
if let Err(err) = v.check_field_names(variant) {
125+
Validation::Validated(v, Errors::of(err))
126+
} else {
127+
Validation::valid(v)
128+
}
129+
})
130+
.and_then(|model| {
120131
if model.fields_model.has_tag_field() {
121132
let err = syn::Error::new_spanned(variant, VARIANT_WITH_TAG);
122133
Validation::Validated(model, err.into())
123134
} else {
124135
Validation::valid(model)
125136
}
126137
});
127-
match model {
128-
Validation::Validated(model, errs) => {
129-
var_models.push(model);
130-
Validation::Validated(var_models, errs)
131-
}
132-
Validation::Failed(errs) => Validation::Validated(var_models, errs),
138+
match model {
139+
Validation::Validated(model, errs) => {
140+
var_models.push(model);
141+
Validation::Validated((transform, var_models), errs)
142+
}
143+
Validation::Failed(errs) => {
144+
Validation::Validated((transform, var_models), errs)
133145
}
134-
});
146+
}
147+
},
148+
);
135149

136-
validate2(variants, transform).and_then(|(mut variants, transform)| {
150+
variants.and_then(|(_, mut variants)| {
137151
let names = variants.iter_mut().validate_fold(
138152
Validation::valid(HashSet::new()),
139153
false,
140154
|mut names, v| {
141-
v.apply(&transform);
142155
let name = match &mut v.transform {
143156
StructTransform::Standard { rename, .. } => {
144157
rename.transform(|| v.name.to_string()).to_string()

api/swim_form_derive/src/structural/model/field/mod.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use macro_utilities::attributes::NestedMetaConsumer;
2121
use macro_utilities::{FieldKind, NameTransform, NameTransformConsumer, Symbol, Transformation};
2222
use proc_macro2::TokenStream;
2323
use quote::{ToTokens, TokenStreamExt};
24+
use std::borrow::Cow;
2425
use std::ops::Add;
2526
use swim_utilities::errors::validation::Validation;
2627
use syn::{Field, Ident, Meta, NestedMeta, Type};
@@ -112,13 +113,24 @@ impl<'a> FieldModel<'a> {
112113

113114
pub struct ResolvedName<'a>(&'a FieldModel<'a>);
114115

115-
impl<'a> ToTokens for ResolvedName<'a> {
116-
fn to_tokens(&self, tokens: &mut TokenStream) {
116+
impl<'a> ResolvedName<'a> {
117+
fn intrinsic_name(&self) -> String {
117118
let ResolvedName(field) = self;
118-
let name_fn = || match field.selector {
119+
match field.selector {
119120
FieldSelector::Ordinal(i) => format!("value_{}", i),
120121
FieldSelector::Named(id) => id.to_string(),
121-
};
122+
}
123+
}
124+
125+
pub fn as_cow(&self) -> Cow<'a, str> {
126+
self.0.transform.transform_cow(self.intrinsic_name())
127+
}
128+
}
129+
130+
impl<'a> ToTokens for ResolvedName<'a> {
131+
fn to_tokens(&self, tokens: &mut TokenStream) {
132+
let ResolvedName(field) = self;
133+
let name_fn = || self.intrinsic_name();
122134
field.transform.transform(name_fn).to_tokens(tokens);
123135
}
124136
}

0 commit comments

Comments
 (0)