1mod attr_name;
26mod enums;
27
28use proc_macro::TokenStream;
29use proc_macro2::TokenStream as Tokens;
30use quote::quote;
31use syn::{Data, DeriveInput, Fields, Ident, LitStr, Type, parse_macro_input};
32
33thread_local! {
34 static KRATE: std::cell::RefCell<Tokens> = std::cell::RefCell::new(quote!(::yog_data));
37 static CAMEL: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
39}
40
41fn krate() -> Tokens {
43 KRATE.with(|k| k.borrow().clone())
44}
45
46fn default_path() -> syn::Path {
49 use proc_macro_crate::{FoundCrate, crate_name};
50 use yog_ids::rust_crate;
51 let own = quote::format_ident!("{}", rust_crate::DATA_RUST_NAME);
52 match crate_name(rust_crate::DATA) {
53 Ok(FoundCrate::Name(name)) => {
54 let name = quote::format_ident!("{name}");
55 return syn::parse_quote!(::#name);
56 }
57 Ok(FoundCrate::Itself) => return syn::parse_quote!(::#own),
58 Err(_) => {}
59 }
60 match crate_name(rust_crate::API) {
61 Ok(FoundCrate::Name(api)) => {
62 let api = quote::format_ident!("{api}");
63 syn::parse_quote!(::#api::#own)
64 }
65 _ => syn::parse_quote!(::#own),
66 }
67}
68
69#[proc_macro_derive(Schema, attributes(data))]
70pub fn derive_schema(input: TokenStream) -> TokenStream {
71 let input = parse_macro_input!(input as DeriveInput);
72 let mut container = match attrs(&input.attrs) {
73 Ok(a) => a,
74 Err(e) => return e.to_compile_error().into(),
75 };
76 if let syn::Data::Enum(e) = &input.data
78 && container.tag.is_none()
79 && e.variants
80 .iter()
81 .any(|v| !matches!(v.fields, syn::Fields::Unit))
82 {
83 container.tag = Some(yog_ids::word::TYPE.to_owned());
84 }
85 let camel = match container.rename_all.as_deref() {
86 None => false,
87 Some(attr_name::CAMEL_CASE) => true,
88 Some(_) => {
89 return syn::Error::new_spanned(
90 &input.ident,
91 "rename_all = \"camelCase\" is the one case",
92 )
93 .to_compile_error()
94 .into();
95 }
96 };
97 CAMEL.with(|c| c.set(camel));
98 let path = container.krate.take().unwrap_or_else(default_path);
99 KRATE.with(|k| *k.borrow_mut() = quote!(#path));
100 match expand(&input, &container) {
101 Ok(t) => t.into(),
102 Err(e) => e.to_compile_error().into(),
103 }
104}
105
106#[derive(Default)]
107struct Attrs {
108 rename: Option<String>,
109 rename_all: Option<String>,
111 default: Option<Option<syn::Path>>,
112 skip: bool,
113 tag: Option<String>,
114 with: Option<Type>,
115 range: Option<(f64, f64)>,
116 other: bool,
118 krate: Option<syn::Path>,
120 view: bool,
122}
123
124fn attrs(list: &[syn::Attribute]) -> syn::Result<Attrs> {
125 let mut a = Attrs::default();
126 for attr in list.iter().filter(|a| a.path().is_ident(attr_name::DATA)) {
127 attr.parse_nested_meta(|meta| {
128 if meta.path.is_ident(attr_name::RENAME) {
129 a.rename = Some(meta.value()?.parse::<LitStr>()?.value());
130 } else if meta.path.is_ident(attr_name::RENAME_ALL) {
131 a.rename_all = Some(meta.value()?.parse::<LitStr>()?.value());
132 } else if meta.path.is_ident(attr_name::TAG) {
133 a.tag = Some(meta.value()?.parse::<LitStr>()?.value());
134 } else if meta.path.is_ident(attr_name::DEFAULT) {
135 a.default = Some(if meta.input.peek(syn::Token![=]) {
136 Some(meta.value()?.parse::<LitStr>()?.parse()?)
137 } else {
138 None
139 });
140 } else if meta.path.is_ident(attr_name::RANGE) {
141 let lit = meta.value()?.parse::<LitStr>()?;
142 let text = lit.value();
143 let parsed = text.split_once("..=").and_then(|(lo, hi)| {
144 Some((
145 lo.trim().parse::<f64>().ok()?,
146 hi.trim().parse::<f64>().ok()?,
147 ))
148 });
149 a.range = Some(parsed.ok_or_else(|| {
150 syn::Error::new_spanned(&lit, "range = \"lo..=hi\" (numbers)")
151 })?);
152 } else if meta.path.is_ident(attr_name::WITH) {
153 a.with = Some(meta.value()?.parse::<LitStr>()?.parse()?);
154 } else if meta.path.is_ident(attr_name::SKIP) {
155 a.skip = true;
156 } else if meta.path.is_ident(attr_name::VIEW) {
157 a.view = true;
158 } else if meta.path.is_ident(attr_name::OTHER) {
159 a.other = true;
160 } else if meta.path.is_ident(attr_name::CRATE) {
161 a.krate = Some(meta.value()?.parse::<LitStr>()?.parse()?);
162 } else {
163 return Err(meta
164 .error("unknown `data` attribute (rename, rename_all, default, skip, tag, with, range, other, crate, view)"));
165 }
166 Ok(())
167 })?;
168 }
169 Ok(a)
170}
171
172fn docs(list: &[syn::Attribute]) -> String {
173 let mut lines = Vec::new();
174 for attr in list.iter().filter(|a| a.path().is_ident(attr_name::DOC)) {
175 if let syn::Meta::NameValue(nv) = &attr.meta
176 && let syn::Expr::Lit(syn::ExprLit {
177 lit: syn::Lit::Str(s),
178 ..
179 }) = &nv.value
180 {
181 lines.push(s.value().trim().to_string());
182 }
183 }
184 let mut out = String::new();
186 for line in lines {
187 if line.is_empty() {
188 if !out.ends_with("\n\n") && !out.is_empty() {
189 out.push_str("\n\n");
190 }
191 } else {
192 if !out.is_empty() && !out.ends_with('\n') {
193 out.push(' ');
194 }
195 out.push_str(&line);
196 }
197 }
198 out.trim_end().to_string()
199}
200
201fn field_key(ident: &Ident) -> String {
203 let name = ident.to_string().trim_start_matches("r#").to_string();
204 if !CAMEL.with(std::cell::Cell::get) {
205 return name;
206 }
207 let mut out = String::new();
208 let mut upper = false;
209 for c in name.chars() {
210 match c {
211 '_' => upper = !out.is_empty(),
212 c if upper => {
213 out.push(c.to_ascii_uppercase());
214 upper = false;
215 }
216 c => out.push(c),
217 }
218 }
219 out
220}
221
222fn fields_as_written<T>(f: impl FnOnce() -> T) -> T {
225 let camel = CAMEL.with(|c| c.replace(false));
226 let out = f();
227 CAMEL.with(|c| c.set(camel));
228 out
229}
230
231fn variant_key(ident: &Ident) -> String {
233 let name = ident.to_string();
234 if CAMEL.with(std::cell::Cell::get) {
235 yog_codegen::camel(&name)
236 } else {
237 yog_codegen::snake(&name)
238 }
239}
240
241struct NamedField {
242 ident: Ident,
243 ty: Type,
244 key: String,
245 doc: String,
246 default: Option<Option<syn::Path>>,
247 skip: bool,
248 with: Type,
250 codec: bool,
252 range: Option<(f64, f64)>,
253}
254
255fn named_fields(fields: &syn::FieldsNamed) -> syn::Result<Vec<NamedField>> {
256 let krate = krate();
257 fields
258 .named
259 .iter()
260 .map(|f| {
261 let a = attrs(&f.attrs)?;
262 let Some(ident) = f.ident.clone() else {
263 return Err(syn::Error::new_spanned(
264 f,
265 "Schema: a named field without a name",
266 ));
267 };
268 let key = a.rename.unwrap_or_else(|| field_key(&ident));
269 Ok(NamedField {
270 ident,
271 ty: f.ty.clone(),
272 key,
273 doc: docs(&f.attrs),
274 default: a.default,
275 skip: a.skip,
276 codec: a.with.is_some(),
277 with: a
278 .with
279 .unwrap_or_else(|| syn::parse_quote!(#krate::with::Plain)),
280 range: a.range,
281 })
282 })
283 .collect()
284}
285
286fn field_shapes(fields: &[NamedField]) -> Tokens {
288 let krate = krate();
289 let items = fields.iter().filter(|f| !f.skip).map(|f| {
290 let (key, doc, ty, w) = (&f.key, &f.doc, &f.ty, &f.with);
291 let has_default = f.default.is_some();
292 let range = match f.range {
293 Some((lo, hi)) => quote! { ::std::option::Option::Some((#lo, #hi)) },
294 None => quote! { ::std::option::Option::None },
295 };
296 quote! {
297 #krate::schema::Field {
298 name: #key,
299 doc: #doc,
300 shape: <#w as #krate::with::With<#ty>>::shape,
301 required: !#has_default && <#w as #krate::with::With<#ty>>::absent().is_none(),
302 range: #range,
303 }
304 }
305 });
306 quote! { ::std::vec![#(#items),*] }
307}
308
309fn read_fields(fields: &[NamedField], ctor: Tokens) -> Tokens {
311 let keys = fields.iter().filter(|f| !f.skip).map(|f| &f.key);
312 let lets = fields.iter().map(|f| {
313 let (ident, ty, key, w) = (&f.ident, &f.ty, &f.key, &f.with);
314 if f.skip {
315 return quote! { let #ident: ::std::option::Option<#ty> = ::std::option::Option::Some(::std::default::Default::default()); };
316 }
317 match &f.default {
318 None => quote! { let #ident = cx.field_with::<#w, #ty>(map, #key); },
319 Some(None) => quote! { let #ident = cx.field_or_with::<#w, #ty>(map, #key, ::std::default::Default::default); },
320 Some(Some(path)) => quote! { let #ident = cx.field_or_with::<#w, #ty>(map, #key, #path); },
321 }
322 });
323 let ranges = fields.iter().filter_map(|f| {
324 let (ident, key) = (&f.ident, &f.key);
325 let (lo, hi) = f.range?;
326 Some(quote! { let #ident = cx.in_range(#key, #ident, #lo, #hi); })
327 });
328 let inits = fields.iter().map(|f| {
329 let ident = &f.ident;
330 quote! { #ident: #ident? }
331 });
332 quote! {
333 cx.unknown_keys(map, &[#(#keys),*]);
334 cx.own_keys(|cx| {
335 #(#lets)*
336 #(#ranges)*
337 ::std::option::Option::Some(#ctor { #(#inits),* })
338 })
339 }
340}
341
342fn write_fields(fields: &[NamedField]) -> Tokens {
344 let krate = krate();
345 let puts = fields.iter().filter(|f| !f.skip).map(|f| {
346 let (ident, key, ty, w) = (&f.ident, &f.key, &f.ty, &f.with);
347 quote! {
348 if !<#w as #krate::with::With<#ty>>::skip(#ident) {
349 m.insert(#key, <#w as #krate::with::With<#ty>>::write(#ident));
350 }
351 }
352 });
353 quote! { #(#puts)* }
354}
355
356fn encode_fields(fields: &[NamedField]) -> Tokens {
358 let krate = krate();
359 let written: Vec<_> = fields.iter().filter(|f| !f.skip).collect();
360 let counts = written.iter().map(|f| {
361 let (ident, ty, w) = (&f.ident, &f.ty, &f.with);
362 quote! { + usize::from(!<#w as #krate::with::With<#ty>>::skip(#ident)) }
363 });
364 let puts = written.iter().map(|f| {
365 let (ident, key, ty, w) = (&f.ident, &f.key, &f.ty, &f.with);
366 quote! {
367 if !<#w as #krate::with::With<#ty>>::skip(#ident) {
368 __yog_w.key(#key);
369 <#w as #krate::with::With<#ty>>::encode(#ident, __yog_w);
370 }
371 }
372 });
373 quote! {
374 __yog_w.map(0 #(#counts)*);
375 #(#puts)*
376 }
377}
378
379fn decode_fields(fields: &[NamedField], ctor: Tokens) -> Option<Tokens> {
382 let krate = krate();
383 if fields.iter().any(|f| f.range.is_some()) {
384 return None;
385 }
386 let read: Vec<_> = fields.iter().filter(|f| !f.skip).collect();
387 let slot = |f: &NamedField| quote::format_ident!("__yog_field_{}", f.ident);
389 let slots = read.iter().map(|f| {
390 let (s, ty) = (slot(f), &f.ty);
391 quote! { let mut #s: ::std::option::Option<#ty> = ::std::option::Option::None; }
392 });
393 let arms = read.iter().map(|f| {
394 let (s, key, ty, w) = (slot(f), &f.key, &f.ty, &f.with);
395 quote! { #key => #s = ::std::option::Option::Some(<#w as #krate::with::With<#ty>>::decode(__yog_d)?), }
396 });
397 let inits = fields.iter().map(|f| {
398 let (ident, ty, w) = (&f.ident, &f.ty, &f.with);
399 let value = if f.skip {
400 quote! { ::std::default::Default::default() }
401 } else {
402 let missing = match &f.default {
403 None => quote! { <#w as #krate::with::With<#ty>>::absent()? },
404 Some(None) => quote! { ::std::default::Default::default() },
405 Some(Some(path)) => quote! { #path() },
406 };
407 let s = slot(f);
408 quote! { match #s { ::std::option::Option::Some(__yog_v) => __yog_v, ::std::option::Option::None => #missing } }
409 };
410 quote! { #ident: #value }
411 });
412 Some(quote! {
413 let __yog_n = __yog_d.map()?;
414 #(#slots)*
415 for _ in 0..__yog_n {
416 match __yog_d.key()? {
417 #(#arms)*
418 _ => return ::std::option::Option::None,
419 }
420 }
421 __yog_d.leave();
422 ::std::option::Option::Some(#ctor { #(#inits),* })
423 })
424}
425
426fn pack_fields(fields: &[NamedField]) -> Tokens {
428 let krate = krate();
429 let puts = fields.iter().filter(|f| !f.skip).map(|f| {
430 let (ident, ty, w) = (&f.ident, &f.ty, &f.with);
431 quote! { <#w as #krate::with::With<#ty>>::pack(#ident, __yog_p); }
432 });
433 quote! {
434 let __yog_at = __yog_p.begin();
435 #(#puts)*
436 __yog_p.end(__yog_at);
437 }
438}
439
440fn unpack_fields(fields: &[NamedField], ctor: Tokens) -> Tokens {
444 let krate = krate();
445 let slot = |f: &NamedField| quote::format_ident!("__yog_field_{}", f.ident);
446 let gets = fields.iter().filter(|f| !f.skip).map(|f| {
447 let (s, ty, w) = (slot(f), &f.ty, &f.with);
448 quote! {
449 let #s: ::std::option::Option<#ty> = if __yog_u.more(__yog_end) {
450 ::std::option::Option::Some(<#w as #krate::with::With<#ty>>::unpack(__yog_u)?)
451 } else {
452 ::std::option::Option::None
453 };
454 }
455 });
456 let inits = fields.iter().map(|f| {
457 let (ident, ty, w) = (&f.ident, &f.ty, &f.with);
458 let value = if f.skip {
459 quote! { ::std::default::Default::default() }
460 } else {
461 let s = slot(f);
462 let missing = match &f.default {
463 None => quote! { <#w as #krate::with::With<#ty>>::absent()? },
464 Some(None) => quote! { ::std::default::Default::default() },
465 Some(Some(path)) => quote! { #path() },
466 };
467 quote! { match #s { ::std::option::Option::Some(__yog_v) => __yog_v, ::std::option::Option::None => #missing } }
468 };
469 quote! { #ident: #value }
470 });
471 quote! {
472 let __yog_end = __yog_u.begin()?;
473 #(#gets)*
474 __yog_u.leave(__yog_end)?;
475 ::std::option::Option::Some(#ctor { #(#inits),* })
476 }
477}
478
479fn expand_named(named: &syn::FieldsNamed, shape_name: &str, doc: &str) -> syn::Result<Tokens> {
481 let krate = krate();
482 let fields = named_fields(named)?;
483 let shapes = field_shapes(&fields);
484 let read = read_fields(&fields, quote! { Self });
485 let idents: Vec<_> = fields.iter().map(|f| &f.ident).collect();
486 let write = write_fields(&fields);
487 let encode = encode_fields(&fields);
488 let decode = decode_fields(&fields, quote! { Self }).map(|body| {
489 quote! {
490 fn decode(__yog_d: &mut #krate::binary::Decoder<'_>) -> ::std::option::Option<Self> {
491 #body
492 }
493 }
494 });
495 let pack = pack_fields(&fields);
496 let unpack = unpack_fields(&fields, quote! { Self });
497 Ok(quote! {
498 #[allow(unused_variables)]
500 fn encode(&self, __yog_w: &mut #krate::binary::Writer) {
501 let Self { #(#idents),* } = self;
502 #encode
503 }
504 #decode
505 #[allow(unused_variables)]
507 fn pack(&self, __yog_p: &mut #krate::frame::Packer) {
508 let Self { #(#idents),* } = self;
509 #pack
510 }
511 fn unpack(__yog_u: &mut #krate::frame::Unpacker<'_>) -> ::std::option::Option<Self> {
512 #unpack
513 }
514 fn shape() -> #krate::Shape {
515 #krate::Shape::Struct(#krate::schema::StructShape { name: #shape_name, doc: #doc, fields: #shapes })
516 }
517 fn read(v: &#krate::ValueRef<'_>, cx: &mut #krate::Reader) -> ::std::option::Option<Self> {
518 let map = cx.map(v)?;
519 #read
520 }
521 #[allow(unused_variables)]
523 fn write(&self) -> #krate::Value {
524 let Self { #(#idents),* } = self;
525 let mut m = #krate::Map::new();
526 #write
527 #krate::Value::Map(m)
528 }
529 })
530}
531
532fn view_items(input: &DeriveInput, fields: &[NamedField]) -> syn::Result<Tokens> {
536 let krate = krate();
537 let (name, vis) = (&input.ident, &input.vis);
538 if !input.generics.params.is_empty() {
539 return Err(syn::Error::new_spanned(
540 name,
541 "Schema: `view` is for a struct without generics",
542 ));
543 }
544 let view = quote::format_ident!("{}View", name);
545 let shown: Vec<&NamedField> = fields.iter().filter(|f| !f.skip).collect();
546 let types = shown.iter().map(|f| {
547 let (ident, ty) = (&f.ident, &f.ty);
548 if f.codec {
549 quote! { pub #ident: #ty, }
550 } else {
551 quote! { pub #ident: <#ty as #krate::frame::View<'a>>::View, }
552 }
553 });
554 let reads = shown.iter().map(|f| {
555 let (ident, ty, w) = (&f.ident, &f.ty, &f.with);
556 let read = if f.codec {
557 quote! { <#w as #krate::with::With<#ty>>::unpack(__yog_u)? }
558 } else {
559 quote! { <#ty as #krate::frame::View<'a>>::unpack_view(__yog_u)? }
560 };
561 quote! { let #ident = if __yog_u.more(__yog_end) { #read } else { return ::std::option::Option::None }; }
562 });
563 let idents = shown.iter().map(|f| &f.ident);
564 let doc =
565 format!("[`{name}`] viewed in a frame: strings borrowed, packed numbers read in place.");
566 Ok(quote! {
567 #[doc = #doc]
568 #vis struct #view<'a> {
569 #(#types)*
570 _frame: ::std::marker::PhantomData<&'a ()>,
571 }
572
573 impl<'a> #krate::frame::View<'a> for #name {
574 type View = #view<'a>;
575 type ListView = #krate::frame::List<'a, Self>;
576 fn unpack_view(__yog_u: &mut #krate::frame::Unpacker<'a>) -> ::std::option::Option<#view<'a>> {
577 let __yog_end = __yog_u.begin()?;
578 #(#reads)*
579 __yog_u.leave(__yog_end)?;
580 ::std::option::Option::Some(#view { #(#idents,)* _frame: ::std::marker::PhantomData })
581 }
582 fn unpack_list_view(__yog_u: &mut #krate::frame::Unpacker<'a>) -> ::std::option::Option<Self::ListView> {
583 #krate::frame::list(__yog_u)
584 }
585 }
586 })
587}
588
589fn expand(input: &DeriveInput, top: &Attrs) -> syn::Result<Tokens> {
590 let krate = krate();
591 let name = &input.ident;
592 let (impl_g, ty_g, where_g) = input.generics.split_for_impl();
593 let shape_name = top.rename.clone().unwrap_or_else(|| name.to_string());
594 let doc = docs(&input.attrs);
595 let body = match &input.data {
596 Data::Struct(s) => match &s.fields {
597 Fields::Named(named) => expand_named(named, &shape_name, &doc)?,
598 Fields::Unnamed(u) if u.unnamed.len() == 1 => expand_newtype(&u.unnamed[0].ty),
599 _ => {
600 return Err(syn::Error::new_spanned(
601 name,
602 "Schema: a struct needs named fields or exactly one unnamed field",
603 ));
604 }
605 },
606 Data::Enum(e) => enums::expand_enum(e, top, &shape_name, &doc)?,
607 Data::Union(_) => {
608 return Err(syn::Error::new_spanned(
609 name,
610 "Schema: unions aren't supported",
611 ));
612 }
613 };
614 let view = view_of(input, top)?;
615 let fields = fields_of(input)?;
616 Ok(quote! {
617 impl #impl_g #krate::Schema for #name #ty_g #where_g {
618 #body
619 }
620 #view
621 #fields
622 })
623}
624
625fn fields_of(input: &DeriveInput) -> syn::Result<Tokens> {
627 let krate = krate();
628 let name = &input.ident;
629 let (impl_g, ty_g, where_g) = input.generics.split_for_impl();
630 let Data::Struct(syn::DataStruct {
631 fields: Fields::Named(named),
632 ..
633 }) = &input.data
634 else {
635 return Ok(quote! {});
636 };
637 let pairs = named_fields(named)?.into_iter().map(|f| {
638 let ident = f.ident.to_string();
639 let ident = ident.trim_start_matches("r#");
640 let key = &f.key;
641 quote! { (#ident, #key) }
642 });
643 Ok(quote! {
644 impl #impl_g #krate::schema::Fields for #name #ty_g #where_g {
645 const FIELDS: &'static [(&'static str, &'static str)] = &[#(#pairs),*];
646 }
647 })
648}
649
650fn expand_newtype(ty: &Type) -> Tokens {
652 let krate = krate();
653 quote! {
654 fn shape() -> #krate::Shape { <#ty as #krate::Schema>::shape() }
655 fn read(v: &#krate::ValueRef<'_>, cx: &mut #krate::Reader) -> ::std::option::Option<Self> {
656 <#ty as #krate::Schema>::read(v, cx).map(Self)
657 }
658 fn write(&self) -> #krate::Value { #krate::Schema::write(&self.0) }
659 fn encode(&self, w: &mut #krate::binary::Writer) { #krate::Schema::encode(&self.0, w) }
660 fn decode(d: &mut #krate::binary::Decoder<'_>) -> ::std::option::Option<Self> {
661 <#ty as #krate::Schema>::decode(d).map(Self)
662 }
663 fn pack(&self, p: &mut #krate::frame::Packer) { #krate::Schema::pack(&self.0, p) }
664 fn unpack(u: &mut #krate::frame::Unpacker<'_>) -> ::std::option::Option<Self> {
665 <#ty as #krate::Schema>::unpack(u).map(Self)
666 }
667 fn absent() -> ::std::option::Option<Self> { <#ty as #krate::Schema>::absent().map(Self) }
668 fn skip(&self) -> bool { #krate::Schema::skip(&self.0) }
669 }
670}
671
672fn view_of(input: &DeriveInput, top: &Attrs) -> syn::Result<Tokens> {
674 let krate = krate();
675 let name = &input.ident;
676 Ok(match (&input.data, top.view) {
677 (
678 Data::Struct(syn::DataStruct {
679 fields: Fields::Named(named),
680 ..
681 }),
682 true,
683 ) => view_items(input, &named_fields(named)?)?,
684 (_, true) => {
685 return Err(syn::Error::new_spanned(
686 name,
687 "Schema: `view` is for a struct with named fields",
688 ));
689 }
690 (Data::Enum(e), false)
691 if top.tag.is_none()
692 && input.generics.params.is_empty()
693 && e.variants.iter().all(|v| matches!(v.fields, Fields::Unit)) =>
694 {
695 quote! {
696 impl<'a> #krate::frame::View<'a> for #name {
697 type View = Self;
698 type ListView = ::std::vec::Vec<Self>;
699 fn unpack_view(u: &mut #krate::frame::Unpacker<'a>) -> ::std::option::Option<Self> {
700 <Self as #krate::Schema>::unpack(u)
701 }
702 fn unpack_list_view(u: &mut #krate::frame::Unpacker<'a>) -> ::std::option::Option<::std::vec::Vec<Self>> {
703 <Self as #krate::Schema>::unpack_list(u)
704 }
705 }
706 }
707 }
708 _ => quote! {},
709 })
710}