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