1use proc_macro::TokenStream;
2use proc_macro2::TokenStream as Tokens;
3use quote::{format_ident, quote};
4use syn::{
5 parse_macro_input, parse_quote, spanned::Spanned, Data, DeriveInput, Expr, Fields, Ident,
6 Member, Type,
7};
8mod attrs;
9#[cfg(feature = "capnp")]
10mod auto_protocol;
11mod native;
12mod sql_model;
13
14#[proc_macro_derive(SqlModel, attributes(sql, model))]
16pub fn derive_sql_model(input: TokenStream) -> TokenStream {
17 sql_model::expand(parse_macro_input!(input as DeriveInput))
18 .unwrap_or_else(syn::Error::into_compile_error)
19 .into()
20}
21
22#[cfg(feature = "capnp")]
24#[proc_macro_attribute]
25pub fn capnp_models(args: TokenStream, input: TokenStream) -> TokenStream {
26 auto_protocol::expand(args.into(), input.into())
27 .unwrap_or_else(syn::Error::into_compile_error)
28 .into()
29}
30
31#[proc_macro_derive(Model, attributes(model))]
32pub fn derive_model(input: TokenStream) -> TokenStream {
33 expand(parse_macro_input!(input as DeriveInput))
34 .unwrap_or_else(syn::Error::into_compile_error)
35 .into()
36}
37
38struct Field {
39 ident: Ident,
40 member: Member,
41 ty: Type,
42 attr: attrs::Field,
43 input: String,
44 output: String,
45 doc: ::core::option::Option<String>,
46}
47#[derive(Clone, Copy, PartialEq)]
48enum Shape {
49 Named,
50 Tuple,
51 Unit,
52}
53fn shape(fields: &Fields) -> Shape {
54 match fields {
55 Fields::Named(_) => Shape::Named,
56 Fields::Unnamed(_) => Shape::Tuple,
57 Fields::Unit => Shape::Unit,
58 }
59}
60fn fields(
61 source: &Fields,
62 tag: ::core::option::Option<&str>,
63 container: &attrs::Container,
64) -> syn::Result<Vec<Field>> {
65 let mut inputs = std::collections::HashSet::new();
66 let mut outputs = std::collections::HashSet::new();
67 let mut extras = 0;
68 let result=source.iter().enumerate().map(|(i,field)|{
69 let ident=field.ident.clone().unwrap_or_else(||format_ident!("__tuple_{i}"));
70 let member=field.ident.clone().map(Member::Named).unwrap_or_else(||Member::Unnamed(i.into()));
71 let attr=attrs::field(&field.attrs)?;
72 if attr.extra{extras+=1;}
73 if matches!(source,Fields::Unnamed(_)) && (attr.flatten||attr.extra||attr.rename.is_some()||attr.validation_alias.is_some()||attr.serialization_alias.is_some()||attr.exclude||attr.has_default()){
74 return Err(syn::Error::new(field.span(),"tuple fields support validation and transformations; names, flatten, extra, exclude and defaults require named fields"));
75 }
76 if (attr.flatten||attr.extra)&&(attr.rename.is_some()||attr.validation_alias.is_some()||attr.serialization_alias.is_some()||attr.before.is_some()||attr.coerce||attr.has_rules()){
77 return Err(syn::Error::new(field.span(),"flatten and extra fields use their inner model's names, transformations and constraints"));
78 }
79 let base=attr.rename.clone().unwrap_or_else(||if field.ident.is_some(){ident.to_string().trim_start_matches("r#").to_owned()}else{i.to_string()});
80 let input=attr.validation_alias.clone().unwrap_or_else(||base.clone());let output=attr.serialization_alias.clone().unwrap_or(base);
81 if !attr.flatten&&!attr.extra{
82 if !inputs.insert(input.clone())||tag==Some(input.as_str()){return Err(syn::Error::new(ident.span(),"duplicate input field name or collision with enum tag"));}
83 if !attr.exclude&&(!outputs.insert(output.clone())||tag==Some(output.as_str())){return Err(syn::Error::new(ident.span(),"duplicate output field name or collision with enum tag"));}
84 }
85 let doc=attr.description.clone().or_else(||{
86 let text=field.attrs.iter().filter_map(|attr|{if !attr.path().is_ident("doc"){return None;}let syn::Meta::NameValue(v)=&attr.meta else{return None;};let Expr::Lit(v)=&v.value else{return None;};let syn::Lit::Str(v)=&v.lit else{return None;};Some(v.value().trim().to_owned())}).collect::<Vec<_>>();(!text.is_empty()).then(||text.join("\n"))
87 });
88 Ok(Field{ident,member,ty:field.ty.clone(),attr,input,output,doc})
89 }).collect::<syn::Result<Vec<_>>>()?;
90 if extras > 1 {
91 return Err(syn::Error::new(
92 source.span(),
93 "a model may have only one extra field",
94 ));
95 }
96 if container.allow_extra && extras != 1 {
97 return Err(syn::Error::new(
98 source.span(),
99 "extra = \"allow\" requires one #[model(extra)] map field",
100 ));
101 }
102 if !container.allow_extra && extras != 0 {
103 return Err(syn::Error::new(
104 source.span(),
105 "#[model(extra)] requires #[model(extra = \"allow\")]",
106 ));
107 }
108 Ok(result)
109}
110fn option<T: quote::ToTokens>(value: &::core::option::Option<T>) -> Tokens {
111 match value {
112 Some(v) => quote!(Some(#v)),
113 None => quote!(None),
114 }
115}
116fn rules(field: &Field, rd: &Tokens) -> Tokens {
117 let a = &field.attr;
118 let trim = a.trim;
119 let lower = a.lowercase;
120 let upper = a.uppercase;
121 let email = a.email;
122 let min = option(&a.min_length);
123 let max = option(&a.max_length);
124 let number = |v: &::core::option::Option<String>| match v {
125 Some(v) => quote!(Some(#rd::__private::number(#v))),
126 None => quote!(None),
127 };
128 let ge = number(&a.ge);
129 let gt = number(&a.gt);
130 let le = number(&a.le);
131 let lt = number(&a.lt);
132 let pattern = match &a.pattern {
133 Some(v) => {
134 quote!(Some(#rd::__private::regex::Regex::new(#v).expect("regex checked by Model derive")))
135 }
136 None => quote!(None),
137 };
138 quote!({static RULES: ::std::sync::OnceLock<#rd::rules::Rules>=::std::sync::OnceLock::new();RULES.get_or_init(||#rd::rules::Rules{trim:#trim,lowercase:#lower,uppercase:#upper,min_length:#min,max_length:#max,ge:#ge,gt:#gt,le:#le,lt:#lt,pattern:#pattern,email:#email})})
139}
140struct Mode<'a> {
141 rd: &'a Tokens,
142 borrow: bool,
143}
144impl Mode<'_> {
145 fn tr(&self) -> Tokens {
146 let rd = self.rd;
147 if self.borrow {
148 quote!(#rd::BorrowType<'__rydantic_de>)
149 } else {
150 quote!(#rd::JsonType)
151 }
152 }
153 fn decode(&self, ty: &Type, raw: Tokens, coerce: bool) -> Tokens {
154 let tr = self.tr();
155 if self.borrow {
156 quote!(<#ty as #tr>::decode(#raw,__rydantic_ctx,#coerce))
157 } else {
158 quote!(<#ty as #tr>::decode_input(#raw,__rydantic_ctx,#coerce))
159 }
160 }
161}
162fn default_expr(field: &Field, borrow: bool) -> ::core::option::Option<Tokens> {
163 let ty = &field.ty;
164 let a = &field.attr;
165 if a.default_trait {
166 Some(quote!(<#ty as ::core::default::Default>::default()))
167 } else if let Some(expr) = &a.default {
168 Some(
169 if matches!(
170 expr,
171 Expr::Lit(syn::ExprLit {
172 lit: syn::Lit::Str(_),
173 ..
174 })
175 ) {
176 if borrow {
177 quote!(::core::convert::From::from(#expr))
178 } else {
179 quote!((#expr).to_owned())
180 }
181 } else {
182 quote!(#expr)
183 },
184 )
185 } else {
186 a.default_factory.as_ref().map(|path| quote!(#path()))
187 }
188}
189fn field_value(field: &Field, raw: Tokens, mode: &Mode) -> Tokens {
190 let rd = mode.rd;
191 let tr = mode.tr();
192 let ty = &field.ty;
193 let rule = rules(field, rd);
194 let missing_error = quote!({__rydantic_ctx.push(#rd::ValidationError::new("missing","field is required").with_stage(#rd::Stage::Parse));None});
195 let default = default_expr(field, mode.borrow);
196 let missing = if let Some(value) = default {
197 quote!(Some({let value:#ty=#value;value}))
198 } else if field.attr.required {
199 missing_error.clone()
200 } else {
201 quote!(match <#ty as #tr>::missing(){Some(value)=>Some(value),None=>#missing_error})
202 };
203 let before=field.attr.before.as_ref().map(|path|quote!{
204 let value=__rydantic_raw.into_value(__rydantic_ctx)?;
205 __rydantic_raw=match #path(value){Ok(value)=>#rd::Input::Owned(value),Err(error)=>{__rydantic_ctx.push(error.with_stage(#rd::Stage::Parse));return None;}};
206 });
207 let decoded = mode.decode(ty, quote!(__rydantic_raw), field.attr.coerce);
208 let default_flow = if field.attr.before.is_some() {
209 quote! {let value:#ty=#missing?;let value=<#ty as #tr>::encode_input(&value,__rydantic_ctx);let mut __rydantic_raw=#rd::Input::Owned(value);#before #decoded?}
210 } else {
211 quote! {let value:#ty=#missing?;<#ty as #tr>::prepare_default(value,__rydantic_ctx)?}
212 };
213 let custom=field.attr.validate.as_ref().map(|path|quote!{if __rydantic_ctx.error_count()==__rydantic_start{if let Err(error)=#path(&__rydantic_value){__rydantic_ctx.push(error);}}});
214 let builtin=field.attr.has_rules().then(||quote!{let rules=#rule;__rydantic_value=<#ty as #tr>::normalize(__rydantic_value,rules,__rydantic_ctx)?;<#ty as #tr>::validate_rules(&__rydantic_value,rules,__rydantic_ctx);});
215 quote! {
216 let __rydantic_start=__rydantic_ctx.error_count();
217 let mut __rydantic_value=match #raw{Some(mut __rydantic_raw)=>{#before #decoded?},None=>{#default_flow}};
218 #builtin #custom Some(__rydantic_value)
219 }
220}
221fn with_location(field: &Field, index: usize, shape: Shape, body: Tokens, _rd: &Tokens) -> Tokens {
222 if field.attr.flatten || field.attr.extra || (shape == Shape::Tuple && index == usize::MAX) {
223 quote! {(||{#body})()}
224 } else if shape == Shape::Tuple {
225 quote! {__rydantic_ctx.at(#index,|__rydantic_ctx|{#body})}
226 } else {
227 let input = &field.input;
228 quote! {__rydantic_ctx.at(#input,|__rydantic_ctx|{#body})}
229 }
230}
231fn object_names(fields: &[Field], rd: &Tokens, tag: ::core::option::Option<&str>) -> Tokens {
232 let names=fields.iter().filter(|f|!f.attr.extra).map(|f|{let ty=&f.ty;let input=&f.input;let output=&f.output;let exclude=f.attr.exclude;
233 if f.attr.flatten{quote!{if !(mode==#rd::SchemaMode::Output&&#exclude){names.extend(<#ty as #rd::ObjectType>::field_names(mode,seen));}}}
234 else{quote!{if !(mode==#rd::SchemaMode::Output&&#exclude){names.push(if mode==#rd::SchemaMode::Input{#input}else{#output}.to_owned());}}}
235 });
236 let tag = tag.map(|tag| quote!(names.push(#tag.to_owned());));
237 quote! {let mut names=::std::vec::Vec::<::std::string::String>::new();#tag #(#names)* names}
238}
239fn collision_checks(
240 fields: &[Field],
241 values: &[Tokens],
242 rd: &Tokens,
243 tag: ::core::option::Option<&str>,
244) -> Tokens {
245 let tag = tag.map(|key| quote!(names.push(#key.to_owned());));
246 let entries = fields.iter().zip(values).map(|(field, value)| {
247 let ty=&field.ty; let input=&field.input; let output=&field.output; let exclude=field.attr.exclude;
248 if field.attr.flatten || field.attr.extra {
249 quote! { if !(mode==#rd::SchemaMode::Output && #exclude) { names.extend(<#ty as #rd::ObjectType>::reserved_names(#value,mode)); } }
250 } else {
251 quote! { if !(mode==#rd::SchemaMode::Output && #exclude) { names.push(if mode==#rd::SchemaMode::Input { #input } else { #output }.to_owned()); } }
252 }
253 });
254 let captures=fields.iter().filter(|f|f.attr.flatten||f.attr.extra).map(|f|{let ty=&f.ty;quote!(usize::from(<#ty as #rd::ObjectType>::captures_extra(&mut ::std::collections::HashSet::new())))});
255 quote! {
256 if 0usize #(+ #captures)* > 1 { __rydantic_ctx.push(#rd::ValidationError::new("flatten_ambiguous","only one flattened field may capture unknown keys")); }
257 for mode in [#rd::SchemaMode::Input,#rd::SchemaMode::Output] {
258 let mut names=::std::vec::Vec::new(); #tag #(#entries)*
259 #rd::__private::check_names(names,__rydantic_ctx);
260 }
261 }
262}
263fn layout_check(fields: &[Field], rd: &Tokens, tag: ::core::option::Option<&str>) -> Tokens {
264 let names = object_names(fields, rd, tag);
265 let catches=fields.iter().filter(|f|f.attr.extra||f.attr.flatten).map(|f|{let ty=&f.ty;quote!(usize::from(<#ty as #rd::ObjectType>::captures_extra(&mut ::std::collections::HashSet::new())))});
266 quote! {
267 for mode in [#rd::SchemaMode::Input,#rd::SchemaMode::Output]{let seen=&mut ::std::collections::HashSet::<&'static str>::new();let names={#names};#rd::__private::check_names(names,__rydantic_ctx);}
268 if 0usize #(+ #catches)*>1{__rydantic_ctx.push(#rd::ValidationError::new("flatten_ambiguous","only one flattened field may capture unknown keys"));return None;}
269 }
270}
271fn parse_shape(
272 fields: &[Field],
273 shape: Shape,
274 constructor: Tokens,
275 container: &attrs::Container,
276 mode: &Mode,
277 tag: ::core::option::Option<&str>,
278) -> Tokens {
279 let rd = mode.rd;
280 let tr = mode.tr();
281 let count = fields.len();
282 let newtype = shape == Shape::Tuple && count == 1;
283 let mut parses = vec![];
284 let locals = (0..count)
285 .map(|i| format_ident!("__rydantic_field_{i}"))
286 .collect::<Vec<_>>();
287 let mut order = (0..count).collect::<Vec<_>>();
289 order.sort_by_key(|i| fields[*i].attr.flatten || fields[*i].attr.extra);
290 for i in order {
291 let field = &fields[i];
292 let local = &locals[i];
293 let ty = &field.ty;
294 let input = &field.input;
295 let has_default = field.attr.has_default();
296 let raw = if shape == Shape::Named {
297 if field.attr.flatten || field.attr.extra {
298 quote! {{let names=<#ty as #rd::ObjectType>::field_names(#rd::SchemaMode::Input,&mut ::std::collections::HashSet::new());
299 let capture=<#ty as #rd::ObjectType>::captures_extra(&mut ::std::collections::HashSet::new());
300 let mut object=::std::collections::BTreeMap::new();
301 for name in names{if let Some(value)=__rydantic_object.remove(&name){object.insert(name,value);}}
302 if capture{object.extend(::core::mem::take(&mut __rydantic_object));}
303 if object.is_empty()&&(<#ty as #tr>::allows_missing()||#has_default){None}else{Some(#rd::Input::Object(object))}
304 }}
305 } else {
306 quote!(__rydantic_object.remove(#input))
307 }
308 } else if newtype {
309 quote!(Some(__rydantic_raw))
310 } else {
311 quote!(__rydantic_items.next())
312 };
313 let body = field_value(field, raw, mode);
314 let body = with_location(field, if newtype { usize::MAX } else { i }, shape, body, rd);
315 if field.attr.flatten || field.attr.extra {
316 let capture = quote!(<#ty as #rd::ObjectType>::captures_extra(&mut ::std::collections::HashSet::new()));
317 parses.push((
318 i,
319 quote! {if !#capture{#local= #body;}},
320 quote! {if #capture{#local= #body;}},
321 ));
322 } else {
323 parses.push((i, quote! {#local= #body;}, quote!()));
324 }
325 }
326 let first = parses.iter().map(|(_, a, _)| a);
327 let last = parses.iter().map(|(_, _, b)| b);
328 let unknown=(!container.ignore_extra&&shape==Shape::Named).then(||quote!{for (key,_) in __rydantic_object{__rydantic_ctx.at(key,|ctx|ctx.push(#rd::ValidationError::new("extra_forbidden","unknown field").with_stage(#rd::Stage::Parse)));}});
329 let setup = match shape {
330 Shape::Named => {
331 let check = layout_check(fields, rd, tag);
332 quote! {let mut __rydantic_object=__rydantic_raw.object(__rydantic_ctx)?;#check}
333 }
334 Shape::Tuple if !newtype => {
335 quote! {let items=__rydantic_raw.array(__rydantic_ctx)?;if items.len()!=#count{__rydantic_ctx.push(#rd::ValidationError::new("tuple_length",concat!("expected ",stringify!(#count)," tuple items")).with_param("expected",#count).with_param("actual",items.len()));return None;}let mut __rydantic_items=items.into_iter();}
336 }
337 Shape::Unit => {
338 quote! {if !__rydantic_raw.is_null(){__rydantic_ctx.push(#rd::ValidationError::new("type_error","expected null").with_stage(#rd::Stage::Parse));return None;}}
339 }
340 _ => quote!(),
341 };
342 let collision = if shape == Shape::Named {
343 let values = locals
344 .iter()
345 .map(|local| quote!(&#local))
346 .collect::<Vec<_>>();
347 collision_checks(fields, &values, rd, tag)
348 } else {
349 quote!()
350 };
351 let done = if count == 0 {
352 quote!({#collision Some(#constructor)})
353 } else {
354 quote! {match (#(#locals,)*){(#(Some(#locals),)*)=>{#collision Some(#constructor)},_=>None}}
355 };
356 quote! {#setup #(let mut #locals=None;)* #(#first)* #(#last)* #unknown #done}
357}
358fn encode_shape(
359 fields: &[Field],
360 values: &[Tokens],
361 shape: Shape,
362 mode: &Mode,
363 input: bool,
364 tag: ::core::option::Option<(&str, &str)>,
365) -> Tokens {
366 let rd = mode.rd;
367 let tr = mode.tr();
368 let method = if input {
369 format_ident!("encode_input")
370 } else {
371 format_ident!("encode")
372 };
373 let newtype = shape == Shape::Tuple && fields.len() == 1;
374 if shape == Shape::Unit {
375 return quote!(#rd::Value::Null);
376 }
377 let mut entries = vec![];
378 for (i, (field, value)) in fields.iter().zip(values).enumerate() {
379 if !input && field.attr.exclude {
380 continue;
381 }
382 let ty = &field.ty;
383 let key = if input { &field.input } else { &field.output };
384 let encoded = quote!(<#ty as #tr>::#method(#value,__rydantic_ctx));
385 if newtype {
386 return encoded;
387 }
388 if shape == Shape::Tuple {
389 entries.push(
390 quote! {__rydantic_items.push(__rydantic_ctx.at(#i,|__rydantic_ctx|#encoded));},
391 );
392 } else if field.attr.flatten || field.attr.extra {
393 entries.push(quote!{let value=#encoded;#rd::__private::merge(&mut __rydantic_object,value,__rydantic_ctx);});
394 } else {
395 entries.push(quote!{let value=__rydantic_ctx.at(#key,|__rydantic_ctx|#encoded);#rd::__private::merge(&mut __rydantic_object,#rd::__private::serde_json::json!({#key:value}),__rydantic_ctx);});
396 }
397 }
398 if shape == Shape::Tuple {
399 quote! {let mut __rydantic_items=::std::vec::Vec::new();#(#entries)* #rd::Value::Array(__rydantic_items)}
400 } else {
401 let tag=tag.map(|(tag,wire)|quote!{__rydantic_object.insert(#tag.to_owned(),#rd::__private::serde_json::json!(#wire));});
402 quote! {let mut __rydantic_object=#rd::__private::serde_json::Map::new();#tag #(#entries)* #rd::Value::Object(__rydantic_object)}
403 }
404}
405fn validate_fields(fields: &[Field], values: &[Tokens], shape: Shape, mode: &Mode) -> Tokens {
406 let rd = mode.rd;
407 let tr = mode.tr();
408 let checks=fields.iter().zip(values).enumerate().map(|(i,(field,value))|{
409 let ty=&field.ty;let rule=rules(field,rd);
410 let builtin=field.attr.has_rules().then(||quote!(<#ty as #tr>::validate_rules(#value,#rule,__rydantic_ctx);));
411 let custom=field.attr.validate.as_ref().map(|path|quote!(if let Err(error)=#path(#value){__rydantic_ctx.push(error);}));
412 let body=quote!{let start=__rydantic_ctx.error_count();<#ty as #tr>::validate_into(#value,__rydantic_ctx);if start==__rydantic_ctx.error_count(){#builtin #custom}};
413 with_location(field,if shape==Shape::Tuple&&fields.len()==1{usize::MAX}else{i},shape,body,rd)
414 });
415 let collision = if shape == Shape::Named {
416 collision_checks(fields, values, rd, None)
417 } else {
418 quote!()
419 };
420 quote!(#(#checks;)* #collision)
421}
422fn async_fields(fields: &[Field], values: &[Tokens], shape: Shape, rd: &Tokens) -> Tokens {
423 let checks=fields.iter().zip(values).enumerate().map(|(i,(field,value))|{
424 let ty=&field.ty;let input=&field.input;
425 let segment=if field.attr.flatten||field.attr.extra||(shape==Shape::Tuple&&fields.len()==1){quote!(None)}else if shape==Shape::Tuple{quote!(Some(#rd::PathSegment::from(#i)))}else{quote!(Some(#rd::PathSegment::from(#input)))};
426 let custom=field.attr.async_validate.as_ref().map(|path|quote!{if child.error_count()==start{if let Err(error)=#path(#value).await{child.push(error);}}});
427 quote!{let mut child=__rydantic_ctx.child(#segment);let start=child.error_count();<#ty as #rd::AsyncCheck>::check_async(#value,&mut child).await;#custom __rydantic_ctx.absorb(child);}
428 });
429 quote!(#(#checks)*)
430}
431fn property_schema(field: &Field, mode: &Mode) -> Tokens {
432 let rd = mode.rd;
433 let tr = mode.tr();
434 let ty = &field.ty;
435 let coerce = field.attr.coerce;
436 let rule = rules(field, rd);
437 let before=field.attr.before.as_ref().map(|path|quote!{if __rydantic_ctx.mode==#rd::SchemaMode::Input{property=#rd::__private::serde_json::json!({});#rd::schema::annotate_local(&mut property,concat!("before:",stringify!(#path)));}});
438 let condition = if field.attr.before.is_some() {
439 quote!(__rydantic_ctx.mode==#rd::SchemaMode::Output)
440 } else {
441 quote!(true)
442 };
443 let custom=field.attr.validate.iter().map(|path|quote!(#rd::schema::annotate_local(&mut property,concat!("validate:",stringify!(#path)));));
444 let asynchronous=field.attr.async_validate.iter().map(|path|quote!(#rd::schema::annotate_local(&mut property,concat!("async_validate:",stringify!(#path)));));
445 let desc = field
446 .doc
447 .as_ref()
448 .map(|text| quote!(property["description"]=#rd::__private::serde_json::json!(#text);));
449 let literal = field.attr.default.as_ref().and_then(|expr| match expr {
450 Expr::Lit(v) => match &v.lit {
451 syn::Lit::Str(v) => Some(serde_json::json!(v.value())),
452 syn::Lit::Bool(v) => Some(serde_json::json!(v.value)),
453 syn::Lit::Int(v) => v
454 .base10_digits()
455 .parse()
456 .ok()
457 .map(serde_json::Value::Number),
458 syn::Lit::Float(v) => v
459 .base10_digits()
460 .parse()
461 .ok()
462 .map(serde_json::Value::Number),
463 _ => None,
464 },
465 _ => None,
466 });
467 let annotation=literal.map(|v|{let text=v.to_string();quote!(if __rydantic_ctx.mode==#rd::SchemaMode::Input{property["default"]=#rd::__private::serde_json::from_str::<#rd::Value>(#text).expect("literal default");})});
468 quote! {{let mut property=<#ty as #tr>::schema(__rydantic_ctx,#coerce);#before if #condition{#rule.apply_schema(&mut property,__rydantic_ctx.mode,#coerce,<#ty as #tr>::kind());}#(#custom)* #(#asynchronous)* #desc #annotation property}}
469}
470fn schema_shape(
471 fields: &[Field],
472 shape: Shape,
473 container: &attrs::Container,
474 mode: &Mode,
475 tag: ::core::option::Option<(&str, &str)>,
476) -> Tokens {
477 let rd = mode.rd;
478 let tr = mode.tr();
479 if shape == Shape::Unit {
480 return quote!(#rd::__private::serde_json::json!({"type":"null"}));
481 }
482 if shape == Shape::Tuple {
483 let props = fields.iter().map(|f| property_schema(f, mode));
484 let count = fields.len();
485 if count == 0 {
486 return quote!(#rd::__private::serde_json::json!({"type":"array","items":false,"maxItems":0}));
487 }
488 if count == 1 {
489 return props.into_iter().next().expect("one field");
490 }
491 return quote!(#rd::__private::serde_json::json!({"type":"array","prefixItems":[#((#props)),*],"items":false,"minItems":#count,"maxItems":#count}));
492 }
493 let ignore = container.ignore_extra;
494 let known_names = object_names(fields, rd, tag.map(|(key, _)| key));
495 let captures=fields.iter().filter(|f|f.attr.flatten||f.attr.extra).map(|f|{let ty=&f.ty;quote!(usize::from(<#ty as #rd::ObjectType>::captures_extra(&mut ::std::collections::HashSet::new())))});
496 let tag=tag.map(|(key,value)|quote!{schema["properties"][#key]=#rd::__private::serde_json::json!({"type":"string","const":#value});schema["required"].as_array_mut().expect("required").push(#rd::__private::serde_json::json!(#key));});
497 let inserts=fields.iter().map(|f|{let ty=&f.ty;let input=&f.input;let output=&f.output;let exclude=f.attr.exclude;let required=f.attr.required;let default=f.attr.has_default();let property=property_schema(f,mode);
498 let insert=if f.attr.flatten||f.attr.extra{
499 let optional=quote!((__rydantic_ctx.mode==#rd::SchemaMode::Input&&#default)||((!#required||__rydantic_ctx.mode==#rd::SchemaMode::Output)&&<#ty as #tr>::allows_missing()));
500 quote!{let child=#property;#rd::__private::flatten_schema(&mut schema,child,(#optional),<#ty as #rd::ObjectType>::captures_extra(&mut ::std::collections::HashSet::new()),__rydantic_ctx);}
501 }else{quote!{let key=if __rydantic_ctx.mode==#rd::SchemaMode::Input{#input}else{#output};let property=#property;schema["properties"].as_object_mut().expect("properties").insert(key.to_owned(),property);if __rydantic_ctx.mode==#rd::SchemaMode::Output||#required||(!#default&&!<#ty as #tr>::allows_missing()){schema["required"].as_array_mut().expect("required").push(#rd::__private::serde_json::json!(key));}}};
502 quote!{if !(__rydantic_ctx.mode==#rd::SchemaMode::Output&&#exclude){#insert}}
503 });
504 quote! {{let mut schema=#rd::__private::serde_json::json!({"type":"object","properties":{},"required":[],"allOf":[],"additionalProperties":(#ignore&&__rydantic_ctx.mode==#rd::SchemaMode::Input)});#tag #(#inserts)*
505 let captures=0usize #(+ #captures)*;
506 if captures>1 { schema["allOf"].as_array_mut().expect("allOf").push(#rd::Value::Bool(false)); }
507 let mut views=::std::vec::Vec::new();
508 for mode in [#rd::SchemaMode::Input,#rd::SchemaMode::Output] {
509 let seen=&mut ::std::collections::HashSet::<&'static str>::new(); let names={#known_names};
510 let mut unique=::std::collections::HashSet::new();
511 if names.iter().any(|name|!unique.insert(name)) { schema["allOf"].as_array_mut().expect("allOf").push(#rd::Value::Bool(false)); }
512 views.push(names);
513 }
514 let mut required=::std::collections::HashSet::new();
515 schema["required"].as_array_mut().expect("required").retain(|key|required.insert(key.as_str().expect("key").to_owned()));
516 if captures>0 && views[0]!=views[1] && __rydantic_ctx.mode==#rd::SchemaMode::Input {#rd::schema::annotate_local(&mut schema,"extra_alias_collision");}
517 if schema["allOf"].as_array().is_some_and(|v|v.is_empty()){schema.as_object_mut().expect("schema").remove("allOf");}schema}}
518}
519fn constructor(fields: &[Field], shape: Shape, path: Tokens) -> Tokens {
520 let locals = (0..fields.len())
521 .map(|i| format_ident!("__rydantic_field_{i}"))
522 .collect::<Vec<_>>();
523 let names = fields.iter().map(|f| &f.ident);
524 match shape {
525 Shape::Named => quote!(#path{#(#names:#locals,)*}),
526 Shape::Tuple => quote!(#path(#(#locals,)*)),
527 Shape::Unit => path,
528 }
529}
530fn pattern(fields: &[Field], shape: Shape, path: Tokens) -> (Tokens, Vec<Tokens>) {
531 let locals = (0..fields.len())
532 .map(|i| format_ident!("__rydantic_field_{i}"))
533 .collect::<Vec<_>>();
534 let names = fields.iter().map(|f| &f.ident);
535 let values = locals.iter().map(|l| quote!(#l)).collect();
536 let pat = match shape {
537 Shape::Named => quote!(#path{#(#names:#locals,)*}),
538 Shape::Tuple => quote!(#path(#(#locals,)*)),
539 Shape::Unit => path,
540 };
541 (pat, values)
542}
543fn prepare_fields(fields: &[Field], shape: Shape, mode: &Mode, path: Tokens) -> Tokens {
544 let rd = mode.rd;
545 let tr = mode.tr();
546 let (pat, _) = pattern(fields, shape, path.clone());
547 let constructor = constructor(fields, shape, path);
548 let locals = (0..fields.len())
549 .map(|i| format_ident!("__rydantic_field_{i}"))
550 .collect::<Vec<_>>();
551 let prepare=fields.iter().enumerate().map(|(i,f)|{let ty=&f.ty;let local=&locals[i];let rule=rules(f,rd);
552 let raw=if let Some(path)=&f.attr.before{let decoded=mode.decode(ty,quote!(#rd::Input::Owned(raw)),f.attr.coerce);quote!{let raw=<#ty as #tr>::encode_input(&#local,__rydantic_ctx);let raw=match #path(raw){Ok(v)=>v,Err(e)=>{__rydantic_ctx.push(e.with_stage(#rd::Stage::Parse));return None;}};let mut value=#decoded?;}}
553 else{quote!(let mut value=<#ty as #tr>::prepare_default(#local,__rydantic_ctx)?;)};
554 let builtin=f.attr.has_rules().then(||quote!{value=<#ty as #tr>::normalize(value,#rule,__rydantic_ctx)?;<#ty as #tr>::validate_rules(&value,#rule,__rydantic_ctx);});
555 let custom=f.attr.validate.as_ref().map(|path|quote!{if start==__rydantic_ctx.error_count(){if let Err(error)=#path(&value){__rydantic_ctx.push(error);}}});
556 let body=quote!{let start=__rydantic_ctx.error_count();#raw #builtin #custom Some(value)};
557 let body=with_location(f,if shape==Shape::Tuple&&fields.len()==1{usize::MAX}else{i},shape,body,rd);quote!(let #local=#body;)
558 });
559 let done = if fields.is_empty() {
560 quote!(Some(#constructor))
561 } else {
562 quote!(match (#(#locals,)*){(#(Some(#locals),)*)=>Some(#constructor),_=>None})
563 };
564 quote!(#pat=>{#(#prepare)* #done})
565}
566fn expand(input: DeriveInput) -> syn::Result<Tokens> {
567 let rd = match proc_macro_crate::crate_name("rydantic")
568 .map_err(|e| syn::Error::new(input.ident.span(), e))?
569 {
570 proc_macro_crate::FoundCrate::Itself => quote!(::rydantic),
571 proc_macro_crate::FoundCrate::Name(name) => {
572 let name = format_ident!("{name}");
573 quote!(::#name)
574 }
575 };
576 let container = attrs::container(&input.attrs)?;
577 let native_capnp = native::expand(&input, &container, &rd)?;
578 let name = &input.ident;
579 let title = container.title.clone().unwrap_or_else(|| name.to_string());
580 let borrowed = input.generics.lifetimes().next().is_some();
581 let mode = Mode {
582 rd: &rd,
583 borrow: borrowed,
584 };
585 let tr = mode.tr();
586 let mut all_fields = Vec::new();
587 let mut object_impl = None;
588 let (decode, encode, encode_input, validate, schema, asynchronous, kind) = match &input.data {
589 Data::Struct(data) => {
590 if container.tag.is_some() || container.untagged {
591 return Err(syn::Error::new(
592 name.span(),
593 "tag and untagged are supported on enums",
594 ));
595 }
596 let fields = fields(&data.fields, None, &container)?;
597 let shape = shape(&data.fields);
598 let ctor = constructor(&fields, shape, quote!(Self));
599 let decode = parse_shape(&fields, shape, ctor, &container, &mode, None);
600 let values = fields
601 .iter()
602 .map(|f| {
603 let m = &f.member;
604 quote!(&self.#m)
605 })
606 .collect::<Vec<_>>();
607 let encode = encode_shape(&fields, &values, shape, &mode, false, None);
608 let encode_input = encode_shape(&fields, &values, shape, &mode, true, None);
609 let validate = validate_fields(&fields, &values, shape, &mode);
610 let schema = schema_shape(&fields, shape, &container, &mode, None);
611 let asynchronous = async_fields(&fields, &values, shape, &rd);
612 let kind = match shape {
613 Shape::Named => quote!(#rd::TypeKind::Object),
614 Shape::Tuple if fields.len() == 1 => {
615 let ty = &fields[0].ty;
616 quote!(<#ty as #tr>::kind())
617 }
618 Shape::Tuple => quote!(#rd::TypeKind::Array),
619 Shape::Unit => quote!(#rd::TypeKind::Any),
620 };
621 if shape == Shape::Named {
622 let names = object_names(&fields, &rd, None);
623 let present=fields.iter().map(|f|{let ty=&f.ty;let member=&f.member;let input=&f.input;let output=&f.output;let exclude=f.attr.exclude;
624 if f.attr.flatten||f.attr.extra{quote!{if !(mode==#rd::SchemaMode::Output&&#exclude){names.extend(<#ty as #rd::ObjectType>::reserved_names(&self.#member,mode));}}}
625 else{quote!{if !(mode==#rd::SchemaMode::Output&&#exclude){names.push(if mode==#rd::SchemaMode::Input{#input}else{#output}.to_owned());}}}
626 });
627 let extra = fields
628 .iter()
629 .filter(|f| f.attr.flatten || f.attr.extra)
630 .map(|f| {
631 let ty = &f.ty;
632 quote!(<#ty as #rd::ObjectType>::captures_extra(seen))
633 });
634 object_impl = Some(quote! {
635 fn reserved_names(&self,mode:#rd::SchemaMode)->::std::vec::Vec<::std::string::String>{let mut names=::std::vec::Vec::new();#(#present)* names}
636 fn field_names(mode:#rd::SchemaMode,seen:&mut ::std::collections::HashSet<&'static str>)->::std::vec::Vec<::std::string::String>{if !seen.insert(::core::any::type_name::<Self>()){return ::std::vec::Vec::new();}let names={#names};seen.remove(::core::any::type_name::<Self>());names}
637 fn captures_extra(seen:&mut ::std::collections::HashSet<&'static str>)->bool{if !seen.insert(::core::any::type_name::<Self>()){return false;}let captures=false #(|| #extra)*;seen.remove(::core::any::type_name::<Self>());captures}
638 });
639 }
640 all_fields.extend(fields);
641 (
642 decode,
643 encode,
644 encode_input,
645 validate,
646 schema,
647 asynchronous,
648 kind,
649 )
650 }
651 Data::Enum(data) => {
652 if data.variants.is_empty() {
653 return Err(syn::Error::new(
654 name.span(),
655 "Model requires at least one enum variant",
656 ));
657 }
658 let mut variants = vec![];
659 let mut seen = std::collections::HashSet::new();
660 for v in &data.variants {
661 let wire = attrs::variant_name(&v.attrs, &v.ident.to_string())?;
662 if !seen.insert(wire.clone()) {
663 return Err(syn::Error::new(
664 v.ident.span(),
665 "duplicate enum variant name",
666 ));
667 }
668 let shape = shape(&v.fields);
669 if container.tag.is_some() && shape == Shape::Tuple {
670 return Err(syn::Error::new(v.ident.span(),"internally tagged enums require named fields or unit variants; use untagged for tuple variants"));
671 }
672 if container.tag.is_none() && !container.untagged && shape != Shape::Unit {
673 return Err(syn::Error::new(
674 v.ident.span(),
675 "enums with fields require #[model(tag = \"...\")] or #[model(untagged)]",
676 ));
677 }
678 variants.push((
679 &v.ident,
680 wire,
681 shape,
682 fields(&v.fields, container.tag.as_deref(), &container)?,
683 ));
684 }
685 let mut decodes = vec![];
686 let mut encodes = vec![];
687 let mut input_encodes = vec![];
688 let mut validates = vec![];
689 let mut asyncs = vec![];
690 let mut schemas = vec![];
691 let wires = variants.iter().map(|(_, w, _, _)| w).collect::<Vec<_>>();
692 for (variant, wire, shape, fields) in &variants {
693 let (pat, values) = pattern(fields, *shape, quote!(Self::#variant));
694 let ctor = constructor(fields, *shape, quote!(Self::#variant));
695 let wire_shape = if container.tag.is_some() {
696 Shape::Named
697 } else {
698 *shape
699 };
700 let tag = container.tag.as_deref().map(|t| (t, wire.as_str()));
701 let (encode, encode_input, schema) =
702 if !container.untagged && container.tag.is_none() {
703 (
704 quote!(#rd::__private::serde_json::json!(#wire)),
705 quote!(#rd::__private::serde_json::json!(#wire)),
706 quote!(),
707 )
708 } else {
709 (
710 encode_shape(fields, &values, wire_shape, &mode, false, tag),
711 encode_shape(fields, &values, wire_shape, &mode, true, tag),
712 schema_shape(fields, wire_shape, &container, &mode, tag),
713 )
714 };
715 encodes.push(quote!(#pat=>{#encode}));
716 input_encodes.push(quote!(#pat=>{#encode_input}));
717 let checks = validate_fields(fields, &values, *shape, &mode);
718 validates.push(quote!(#pat=>{#checks}));
719 let checks = async_fields(fields, &values, *shape, &rd);
720 asyncs.push(quote!(#pat=>{#checks}));
721 schemas.push(schema);
722 if container.untagged {
723 let body = parse_shape(fields, *shape, ctor, &container, &mode, None);
724 decodes.push(quote!{
725 {let mut trial=#rd::Context::new();let result={let __rydantic_ctx=&mut trial;let __rydantic_raw=__rydantic_raw.clone();(||{#body})()};
726 match trial.finish(result){Ok(value)=>return Some(value),Err(errors)=>__rydantic_branches.push(#rd::__private::serde_json::json!({"variant":#wire,"errors":errors.to_json()}))}}
727 });
728 } else if container.tag.is_some() {
729 let body = parse_shape(
730 fields,
731 wire_shape,
732 ctor,
733 &container,
734 &mode,
735 container.tag.as_deref(),
736 );
737 decodes.push(quote!(#wire=>{let __rydantic_raw=#rd::Input::Object(__rydantic_object);#body}));
738 } else {
739 decodes.push(quote!(#wire=>Some(#ctor)));
740 }
741 }
742 let (decode, schema, kind) = if container.untagged {
743 (
744 quote! {let mut __rydantic_branches=::std::vec::Vec::<#rd::Value>::new();#(#decodes)* __rydantic_ctx.push(#rd::ValidationError::new("union_no_match","no untagged variant accepted the value").with_stage(#rd::Stage::Parse).with_param("branches",#rd::Value::Array(__rydantic_branches)));None},
745 quote!(#rd::__private::serde_json::json!({"anyOf":[#((#schemas)),*]})),
746 quote!(#rd::TypeKind::Any),
747 )
748 } else if let Some(tag) = &container.tag {
749 (
750 quote! {let mut __rydantic_object=__rydantic_raw.object(__rydantic_ctx)?;let tag=match __rydantic_object.remove(#tag){Some(raw)=>{let value=raw.into_value(__rydantic_ctx)?;match value{#rd::Value::String(value)=>value,_=>{__rydantic_ctx.at(#tag,|ctx|ctx.push(#rd::ValidationError::new("union_tag_type","discriminator must be a string").with_stage(#rd::Stage::Parse)));return None;}}},None=>{__rydantic_ctx.at(#tag,|ctx|ctx.push(#rd::ValidationError::new("union_tag_missing","discriminator is required").with_stage(#rd::Stage::Parse)));return None;}};
751 match tag.as_str(){#(#decodes,)* _=>{__rydantic_ctx.at(#tag,|ctx|ctx.push(#rd::ValidationError::new("union_tag_invalid","unknown discriminator").with_stage(#rd::Stage::Parse).with_param("expected",#rd::__private::serde_json::json!([#(#wires),*]))));None}}},
752 quote!(#rd::__private::serde_json::json!({"oneOf":[#((#schemas)),*],"discriminator":{"propertyName":#tag}})),
753 quote!(#rd::TypeKind::Object),
754 )
755 } else {
756 (
757 quote! {let raw=__rydantic_raw.into_value(__rydantic_ctx)?;match raw.as_str(){Some(wire)=>match wire{#(#decodes,)* _=>{__rydantic_ctx.push(#rd::ValidationError::new("enum","unknown enum value").with_stage(#rd::Stage::Parse).with_param("expected",#rd::__private::serde_json::json!([#(#wires),*])));None}},None=>{__rydantic_ctx.push(#rd::ValidationError::new("type_error","expected enum string").with_stage(#rd::Stage::Parse));None}}},
758 quote!(#rd::__private::serde_json::json!({"type":"string","enum":[#(#wires),*]})),
759 quote!(#rd::TypeKind::String),
760 )
761 };
762 for (_, _, _, fields) in variants {
763 all_fields.extend(fields);
764 }
765 (
766 decode,
767 quote!(match self{#(#encodes,)*}),
768 quote!(match self{#(#input_encodes,)*}),
769 quote!(match self{#(#validates,)*}),
770 schema,
771 quote!(match self{#(#asyncs,)*}),
772 kind,
773 )
774 }
775 Data::Union(_) => {
776 return Err(syn::Error::new(
777 name.span(),
778 "Model cannot be derived for unions",
779 ))
780 }
781 };
782 let prepare_default = {
783 let arms = match &input.data {
784 Data::Struct(data) => {
785 let fields = fields(&data.fields, None, &container)?;
786 let arm = prepare_fields(&fields, shape(&data.fields), &mode, quote!(Self));
787 quote!(#arm)
788 }
789 Data::Enum(data) => {
790 let mut arms = vec![];
791 for v in &data.variants {
792 let variant = &v.ident;
793 let fields = fields(&v.fields, container.tag.as_deref(), &container)?;
794 arms.push(prepare_fields(
795 &fields,
796 shape(&v.fields),
797 &mode,
798 quote!(Self::#variant),
799 ));
800 }
801 quote!(#(#arms,)*)
802 }
803 _ => unreachable!(),
804 };
805 let custom=container.validate.as_ref().map(|path|quote!{if start==ctx.error_count(){if let Some(value)=&value{if let Err(errors)=#path(value){ctx.extend(errors);}}}});
806 quote! {fn prepare_default(self,ctx:&mut #rd::Context)->::core::option::Option<Self>{let start=ctx.error_count();let value={let __rydantic_ctx=&mut *ctx;match self{#arms}};#custom value}}
807 };
808 let mut generics = input.generics.clone();
809 if borrowed {
810 generics.params.insert(0, parse_quote!('__rydantic_de));
811 for lt in input.generics.lifetimes() {
812 let lt = <.lifetime;
813 generics
814 .make_where_clause()
815 .predicates
816 .push(parse_quote!('__rydantic_de:#lt));
817 }
818 }
819 for p in generics.type_params_mut() {
820 p.bounds.push(parse_quote!(#tr));
821 }
822 fn contains_generic(ty: &Type, ident: &Ident) -> bool {
823 match ty{Type::Path(p)=>p.path.segments.iter().any(|s|s.ident==*ident||matches!(&s.arguments,syn::PathArguments::AngleBracketed(a) if a.args.iter().any(|arg|matches!(arg,syn::GenericArgument::Type(t)if contains_generic(t,ident))))),Type::Array(a)=>contains_generic(&a.elem,ident),Type::Reference(r)=>contains_generic(&r.elem,ident),Type::Tuple(t)=>t.elems.iter().any(|t|contains_generic(t,ident)),_=>false}
824 }
825 let mut assertions = vec![];
826 for f in &all_fields {
827 let ty = &f.ty;
828 let a = &f.attr;
829 let generic = input
830 .generics
831 .type_params()
832 .any(|p| contains_generic(ty, &p.ident));
833 let mut bounds = vec![];
834 if a.trim || a.lowercase || a.uppercase || a.email || a.pattern.is_some() {
835 assertions.push(quote!(__rydantic_assert_string::<#ty>();));
836 bounds.push(quote!(#rd::StringType));
837 }
838 if a.min_length.is_some() || a.max_length.is_some() {
839 assertions.push(quote!(__rydantic_assert_length::<#ty>();));
840 bounds.push(quote!(#rd::LengthType));
841 }
842 if a.ge.is_some() || a.gt.is_some() || a.le.is_some() || a.lt.is_some() {
843 assertions.push(quote!(__rydantic_assert_number::<#ty>();));
844 bounds.push(quote!(#rd::NumericType));
845 }
846 if a.flatten {
847 bounds.push(quote!(#rd::ObjectType));
848 }
849 if a.extra {
850 bounds.push(quote!(#rd::ExtraFields));
851 assertions.push(quote!(__rydantic_assert_extra::<#ty>();));
852 }
853 if a.default_trait {
854 bounds.push(quote!(::core::default::Default));
855 }
856 if generic {
857 for bound in bounds {
858 generics
859 .make_where_clause()
860 .predicates
861 .push(parse_quote!(#ty:#bound));
862 }
863 }
864 }
865 let (_, ty_generics, _) = input.generics.split_for_impl();
866 let (impl_generics, _, where_clause) = generics.split_for_impl();
867 let mut de_generics = generics.clone();
868 if !borrowed {
869 de_generics.params.insert(0, parse_quote!('__rydantic_de));
870 }
871 let (de_impl_generics, _, de_where_clause) = de_generics.split_for_impl();
872 let custom_parse=container.validate.as_ref().map(|path|quote!{if __rydantic_ctx.error_count()==start{if let Some(value)=&value{if let Err(errors)=#path(value){__rydantic_ctx.extend(errors);}}}});
873 let custom_validate=container.validate.as_ref().map(|path|quote!{if __rydantic_ctx.error_count()==start{if let Err(errors)=#path(self){__rydantic_ctx.extend(errors);}}});
874 let schema_custom=container.validate.as_ref().map(|path|quote!(#rd::schema::annotate_local(&mut schema,concat!("validate:",stringify!(#path)));));
875 let schema_async=container.async_validate.as_ref().map(|path|quote!(#rd::schema::annotate_local(&mut schema,concat!("async_validate:",stringify!(#path)));));
876 let direct_async = container.async_validate.is_some()
877 || all_fields.iter().any(|f| f.attr.async_validate.is_some());
878 let nested_async = all_fields.iter().map(|f| {
879 let ty = &f.ty;
880 quote!(<#ty as #tr>::async_required(seen))
881 });
882 let model_impl = if borrowed {
883 quote!(impl #impl_generics #rd::BorrowModel<'__rydantic_de> for #name #ty_generics #where_clause {})
884 } else {
885 quote!(impl #impl_generics #rd::Model for #name #ty_generics #where_clause {})
886 };
887 let dump = if borrowed {
888 quote!(<Self as #rd::BorrowModel<'__rydantic_de>>::dump(self))
889 } else {
890 quote!(<Self as #rd::Model>::dump(self))
891 };
892 let deserialize = if borrowed {
893 quote! {let raw=<&'__rydantic_de #rd::__private::serde_json::value::RawValue as #rd::__private::serde::Deserialize>::deserialize(deserializer)?;<Self as #rd::BorrowModel<'__rydantic_de>>::parse_raw(raw).map_err(#rd::__private::serde::de::Error::custom)}
894 } else {
895 quote! {let raw=<::std::boxed::Box<#rd::RawValue> as #rd::__private::serde::Deserialize>::deserialize(deserializer)?;<Self as #rd::Model>::parse_raw(&raw).map_err(#rd::__private::serde::de::Error::custom)}
896 };
897 let object_impl=object_impl.map(|body|quote!(impl #impl_generics #rd::ObjectType for #name #ty_generics #where_clause{#body}));
898 let bridge=(!borrowed).then(||quote!{
899 impl #de_impl_generics #rd::BorrowType<'__rydantic_de> for #name #ty_generics #de_where_clause{
900 fn decode(raw:#rd::Input<'__rydantic_de>,ctx:&mut #rd::Context,coerce:bool)->::core::option::Option<Self>{<Self as #rd::JsonType>::decode_input(raw,ctx,coerce)}
901 fn prepare_default(self,ctx:&mut #rd::Context)->::core::option::Option<Self>{<Self as #rd::JsonType>::prepare_default(self,ctx)}
902 fn encode(&self,ctx:&mut #rd::Context)->#rd::Value{<Self as #rd::JsonType>::encode(self,ctx)}
903 fn encode_input(&self,ctx:&mut #rd::Context)->#rd::Value{<Self as #rd::JsonType>::encode_input(self,ctx)}
904 fn schema(ctx:&mut #rd::SchemaContext,coerce:bool)->#rd::Value{<Self as #rd::JsonType>::schema(ctx,coerce)}
905 fn validate_into(&self,ctx:&mut #rd::Context){<Self as #rd::JsonType>::validate_into(self,ctx)}
906 fn normalize(self,rules:&#rd::rules::Rules,ctx:&mut #rd::Context)->::core::option::Option<Self>{<Self as #rd::JsonType>::normalize(self,rules,ctx)}
907 fn validate_rules(&self,rules:&#rd::rules::Rules,ctx:&mut #rd::Context){<Self as #rd::JsonType>::validate_rules(self,rules,ctx)}
908 fn async_required(seen:&mut ::std::collections::HashSet<&'static str>)->bool{<Self as #rd::JsonType>::async_required(seen)}
909 fn kind()->#rd::TypeKind{<Self as #rd::JsonType>::kind()}
910 }
911 });
912 let mut async_generics = input.generics.clone();
913 for p in async_generics.type_params_mut() {
914 p.bounds.push(parse_quote!(#rd::AsyncCheck));
915 }
916 let (async_impl_generics, _, async_where_clause) = async_generics.split_for_impl();
917 let custom_async=container.async_validate.as_ref().map(|path|quote!{if start==__rydantic_ctx.error_count(){if let Err(errors)=#path(self).await{__rydantic_ctx.extend(errors);}}});
918 let body = quote! {
919 fn __rydantic_assert_string<T:#rd::StringType>(){}fn __rydantic_assert_length<T:#rd::LengthType>(){}fn __rydantic_assert_number<T:#rd::NumericType>(){}fn __rydantic_assert_extra<T:#rd::ExtraFields>(){}
920 #(#assertions)* let start=__rydantic_ctx.error_count();let value=(||{#decode})();#custom_parse value
921 };
922 let decode_methods = if borrowed {
923 quote! {fn decode(__rydantic_raw:#rd::Input<'__rydantic_de>,__rydantic_ctx:&mut #rd::Context,_coerce:bool)->::core::option::Option<Self>{#body}}
924 } else {
925 quote! {
926 fn decode(raw:#rd::Value,ctx:&mut #rd::Context,coerce:bool)->::core::option::Option<Self>{<Self as #rd::JsonType>::decode_input(#rd::Input::Owned(raw),ctx,coerce)}
927 fn decode_input(__rydantic_raw:#rd::Input<'_>,__rydantic_ctx:&mut #rd::Context,_coerce:bool)->::core::option::Option<Self>{#body}
928 }
929 };
930 Ok(quote! {
931 impl #impl_generics #tr for #name #ty_generics #where_clause{
932 #decode_methods
933 #prepare_default
934 fn encode(&self,__rydantic_ctx:&mut #rd::Context)->#rd::Value{#encode}
935 fn encode_input(&self,__rydantic_ctx:&mut #rd::Context)->#rd::Value{#encode_input}
936 fn validate_into(&self,__rydantic_ctx:&mut #rd::Context){let start=__rydantic_ctx.error_count();#validate #custom_validate}
937 fn schema(__rydantic_ctx:&mut #rd::SchemaContext,_coerce:bool)->#rd::Value{__rydantic_ctx.reference(::core::any::type_name::<Self>(),|__rydantic_ctx|{let mut schema=#schema;schema["title"]=#rd::__private::serde_json::json!(#title);#schema_custom #schema_async schema})}
938 fn kind()->#rd::TypeKind{#kind}
939 fn async_required(seen:&mut ::std::collections::HashSet<&'static str>)->bool{if !seen.insert(::core::any::type_name::<Self>()){return false;}#direct_async #(|| #nested_async)*}
940 }
941 #model_impl #object_impl #bridge #native_capnp
942 impl #async_impl_generics #rd::AsyncCheck for #name #ty_generics #async_where_clause{
943 fn check_async<'__rydantic_future>(&'__rydantic_future self,__rydantic_ctx:&'__rydantic_future mut #rd::Context)->#rd::BoxFuture<'__rydantic_future,()>{
944 ::std::boxed::Box::pin(async move{let start=__rydantic_ctx.error_count();#asynchronous #custom_async})
945 }
946 }
947 impl #impl_generics #rd::__private::serde::Serialize for #name #ty_generics #where_clause{
948 fn serialize<S:#rd::__private::serde::Serializer>(&self,serializer:S)->::core::result::Result<S::Ok,S::Error>{let value=#dump.map_err(#rd::__private::serde::ser::Error::custom)?;#rd::__private::serde::Serialize::serialize(&value,serializer)}
949 }
950 impl #de_impl_generics #rd::__private::serde::Deserialize<'__rydantic_de> for #name #ty_generics #de_where_clause{
951 fn deserialize<D:#rd::__private::serde::Deserializer<'__rydantic_de>>(deserializer:D)->::core::result::Result<Self,D::Error>{#deserialize}
952 }
953 })
954}