Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/component-macro/src/component.rs
1692 views
1
use proc_macro2::{Span, TokenStream};
2
use quote::{format_ident, quote};
3
use std::collections::HashSet;
4
use std::fmt;
5
use syn::parse::{Parse, ParseStream};
6
use syn::punctuated::Punctuated;
7
use syn::{Data, DeriveInput, Error, Ident, Result, Token, braced, parse_quote};
8
use wasmtime_component_util::{DiscriminantSize, FlagsSize};
9
10
mod kw {
11
syn::custom_keyword!(record);
12
syn::custom_keyword!(variant);
13
syn::custom_keyword!(flags);
14
syn::custom_keyword!(name);
15
syn::custom_keyword!(wasmtime_crate);
16
}
17
18
#[derive(Debug, Copy, Clone)]
19
enum Style {
20
Record,
21
Enum,
22
Variant,
23
}
24
25
impl fmt::Display for Style {
26
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27
match self {
28
Style::Record => f.write_str("record"),
29
Style::Enum => f.write_str("enum"),
30
Style::Variant => f.write_str("variant"),
31
}
32
}
33
}
34
35
#[derive(Debug, Clone)]
36
enum ComponentAttr {
37
Style(Style),
38
WasmtimeCrate(syn::Path),
39
}
40
41
impl Parse for ComponentAttr {
42
fn parse(input: ParseStream) -> Result<Self> {
43
let lookahead = input.lookahead1();
44
if lookahead.peek(kw::record) {
45
input.parse::<kw::record>()?;
46
Ok(ComponentAttr::Style(Style::Record))
47
} else if lookahead.peek(kw::variant) {
48
input.parse::<kw::variant>()?;
49
Ok(ComponentAttr::Style(Style::Variant))
50
} else if lookahead.peek(Token![enum]) {
51
input.parse::<Token![enum]>()?;
52
Ok(ComponentAttr::Style(Style::Enum))
53
} else if lookahead.peek(kw::wasmtime_crate) {
54
input.parse::<kw::wasmtime_crate>()?;
55
input.parse::<Token![=]>()?;
56
Ok(ComponentAttr::WasmtimeCrate(input.parse()?))
57
} else if input.peek(kw::flags) {
58
Err(input.error(
59
"`flags` not allowed here; \
60
use `wasmtime::component::flags!` macro to define `flags` types",
61
))
62
} else {
63
Err(lookahead.error())
64
}
65
}
66
}
67
68
fn find_rename(attributes: &[syn::Attribute]) -> Result<Option<syn::LitStr>> {
69
let mut name = None;
70
71
for attribute in attributes {
72
if !attribute.path().is_ident("component") {
73
continue;
74
}
75
let name_literal = attribute.parse_args_with(|parser: ParseStream<'_>| {
76
parser.parse::<kw::name>()?;
77
parser.parse::<Token![=]>()?;
78
parser.parse::<syn::LitStr>()
79
})?;
80
81
if name.is_some() {
82
return Err(Error::new_spanned(
83
attribute,
84
"duplicate field rename attribute",
85
));
86
}
87
88
name = Some(name_literal);
89
}
90
91
Ok(name)
92
}
93
94
fn add_trait_bounds(generics: &syn::Generics, bound: syn::TypeParamBound) -> syn::Generics {
95
let mut generics = generics.clone();
96
for param in &mut generics.params {
97
if let syn::GenericParam::Type(ref mut type_param) = *param {
98
type_param.bounds.push(bound.clone());
99
}
100
}
101
generics
102
}
103
104
pub struct VariantCase<'a> {
105
attrs: &'a [syn::Attribute],
106
ident: &'a syn::Ident,
107
ty: Option<&'a syn::Type>,
108
}
109
110
pub trait Expander {
111
fn expand_record(
112
&self,
113
name: &syn::Ident,
114
generics: &syn::Generics,
115
fields: &[&syn::Field],
116
wasmtime_crate: &syn::Path,
117
) -> Result<TokenStream>;
118
119
fn expand_variant(
120
&self,
121
name: &syn::Ident,
122
generics: &syn::Generics,
123
discriminant_size: DiscriminantSize,
124
cases: &[VariantCase],
125
wasmtime_crate: &syn::Path,
126
) -> Result<TokenStream>;
127
128
fn expand_enum(
129
&self,
130
name: &syn::Ident,
131
discriminant_size: DiscriminantSize,
132
cases: &[VariantCase],
133
wasmtime_crate: &syn::Path,
134
) -> Result<TokenStream>;
135
}
136
137
pub fn expand(expander: &dyn Expander, input: &DeriveInput) -> Result<TokenStream> {
138
let mut wasmtime_crate = None;
139
let mut style = None;
140
141
for attribute in &input.attrs {
142
if !attribute.path().is_ident("component") {
143
continue;
144
}
145
match attribute.parse_args()? {
146
ComponentAttr::WasmtimeCrate(c) => wasmtime_crate = Some(c),
147
ComponentAttr::Style(attr_style) => {
148
if style.is_some() {
149
return Err(Error::new_spanned(
150
attribute,
151
"duplicate `component` attribute",
152
));
153
}
154
style = Some(attr_style);
155
}
156
}
157
}
158
159
let style = style.ok_or_else(|| Error::new_spanned(input, "missing `component` attribute"))?;
160
let wasmtime_crate = wasmtime_crate.unwrap_or_else(default_wasmtime_crate);
161
match style {
162
Style::Record => expand_record(expander, input, &wasmtime_crate),
163
Style::Enum | Style::Variant => expand_variant(expander, input, style, &wasmtime_crate),
164
}
165
}
166
167
fn default_wasmtime_crate() -> syn::Path {
168
Ident::new("wasmtime", Span::call_site()).into()
169
}
170
171
fn expand_record(
172
expander: &dyn Expander,
173
input: &DeriveInput,
174
wasmtime_crate: &syn::Path,
175
) -> Result<TokenStream> {
176
let name = &input.ident;
177
178
let body = if let Data::Struct(body) = &input.data {
179
body
180
} else {
181
return Err(Error::new(
182
name.span(),
183
"`record` component types can only be derived for Rust `struct`s",
184
));
185
};
186
187
match &body.fields {
188
syn::Fields::Named(fields) => expander.expand_record(
189
&input.ident,
190
&input.generics,
191
&fields.named.iter().collect::<Vec<_>>(),
192
wasmtime_crate,
193
),
194
195
syn::Fields::Unnamed(_) | syn::Fields::Unit => Err(Error::new(
196
name.span(),
197
"`record` component types can only be derived for `struct`s with named fields",
198
)),
199
}
200
}
201
202
fn expand_variant(
203
expander: &dyn Expander,
204
input: &DeriveInput,
205
style: Style,
206
wasmtime_crate: &syn::Path,
207
) -> Result<TokenStream> {
208
let name = &input.ident;
209
210
let body = if let Data::Enum(body) = &input.data {
211
body
212
} else {
213
return Err(Error::new(
214
name.span(),
215
format!("`{style}` component types can only be derived for Rust `enum`s"),
216
));
217
};
218
219
if body.variants.is_empty() {
220
return Err(Error::new(
221
name.span(),
222
format!(
223
"`{style}` component types can only be derived for Rust `enum`s with at least one variant"
224
),
225
));
226
}
227
228
let discriminant_size = DiscriminantSize::from_count(body.variants.len()).ok_or_else(|| {
229
Error::new(
230
input.ident.span(),
231
"`enum`s with more than 2^32 variants are not supported",
232
)
233
})?;
234
235
let cases = body
236
.variants
237
.iter()
238
.map(
239
|syn::Variant {
240
attrs,
241
ident,
242
fields,
243
..
244
}| {
245
Ok(VariantCase {
246
attrs,
247
ident,
248
ty: match fields {
249
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
250
Some(&fields.unnamed[0].ty)
251
}
252
syn::Fields::Unit => None,
253
_ => {
254
return Err(Error::new(
255
name.span(),
256
format!(
257
"`{}` component types can only be derived for Rust `enum`s \
258
containing variants with {}",
259
style,
260
match style {
261
Style::Variant => "at most one unnamed field each",
262
Style::Enum => "no fields",
263
Style::Record => unreachable!(),
264
}
265
),
266
));
267
}
268
},
269
})
270
},
271
)
272
.collect::<Result<Vec<_>>>()?;
273
274
match style {
275
Style::Variant => expander.expand_variant(
276
&input.ident,
277
&input.generics,
278
discriminant_size,
279
&cases,
280
wasmtime_crate,
281
),
282
Style::Enum => {
283
validate_enum(input, &body, discriminant_size)?;
284
expander.expand_enum(&input.ident, discriminant_size, &cases, wasmtime_crate)
285
}
286
Style::Record => unreachable!(),
287
}
288
}
289
290
/// Validates component model `enum` definitions are accompanied with
291
/// appropriate `#[repr]` tags. Additionally requires that no discriminants are
292
/// listed to ensure that unsafe transmutes in lift are valid.
293
fn validate_enum(input: &DeriveInput, body: &syn::DataEnum, size: DiscriminantSize) -> Result<()> {
294
if !input.generics.params.is_empty() {
295
return Err(Error::new_spanned(
296
&input.generics.params,
297
"cannot have generics on an `enum`",
298
));
299
}
300
if let Some(clause) = &input.generics.where_clause {
301
return Err(Error::new_spanned(
302
clause,
303
"cannot have a where clause on an `enum`",
304
));
305
}
306
let expected_discr = match size {
307
DiscriminantSize::Size1 => "u8",
308
DiscriminantSize::Size2 => "u16",
309
DiscriminantSize::Size4 => "u32",
310
};
311
let mut found_repr = false;
312
for attr in input.attrs.iter() {
313
if !attr.meta.path().is_ident("repr") {
314
continue;
315
}
316
let list = attr.meta.require_list()?;
317
found_repr = true;
318
if list.tokens.to_string() != expected_discr {
319
return Err(Error::new_spanned(
320
&list.tokens,
321
format!(
322
"expected `repr({expected_discr})`, found `repr({})`",
323
list.tokens
324
),
325
));
326
}
327
}
328
if !found_repr {
329
return Err(Error::new_spanned(
330
&body.enum_token,
331
format!("missing required `#[repr({expected_discr})]`"),
332
));
333
}
334
335
for case in body.variants.iter() {
336
if let Some((_, expr)) = &case.discriminant {
337
return Err(Error::new_spanned(
338
expr,
339
"cannot have an explicit discriminant",
340
));
341
}
342
}
343
344
Ok(())
345
}
346
347
fn expand_record_for_component_type(
348
name: &syn::Ident,
349
generics: &syn::Generics,
350
fields: &[&syn::Field],
351
typecheck: TokenStream,
352
typecheck_argument: TokenStream,
353
wt: &syn::Path,
354
) -> Result<TokenStream> {
355
let internal = quote!(#wt::component::__internal);
356
357
let mut lower_generic_params = TokenStream::new();
358
let mut lower_generic_args = TokenStream::new();
359
let mut lower_field_declarations = TokenStream::new();
360
let mut abi_list = TokenStream::new();
361
let mut unique_types = HashSet::new();
362
363
for (index, syn::Field { ident, ty, .. }) in fields.iter().enumerate() {
364
let generic = format_ident!("T{}", index);
365
366
lower_generic_params.extend(quote!(#generic: Copy,));
367
lower_generic_args.extend(quote!(<#ty as #wt::component::ComponentType>::Lower,));
368
369
lower_field_declarations.extend(quote!(#ident: #generic,));
370
371
abi_list.extend(quote!(
372
<#ty as #wt::component::ComponentType>::ABI,
373
));
374
375
unique_types.insert(ty);
376
}
377
378
let generics = add_trait_bounds(generics, parse_quote!(#wt::component::ComponentType));
379
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
380
let lower = format_ident!("Lower{}", name);
381
382
// You may wonder why we make the types of all the fields of the #lower struct generic. This is to work
383
// around the lack of [perfect derive support in
384
// rustc](https://smallcultfollowing.com/babysteps//blog/2022/04/12/implied-bounds-and-perfect-derive/#what-is-perfect-derive)
385
// as of this writing.
386
//
387
// If the struct we're deriving a `ComponentType` impl for has any generic parameters, then #lower needs
388
// generic parameters too. And if we just copy the parameters and bounds from the impl to #lower, then the
389
// `#[derive(Clone, Copy)]` will fail unless the original generics were declared with those bounds, which
390
// we don't want to require.
391
//
392
// Alternatively, we could just pass the `Lower` associated type of each generic type as arguments to
393
// #lower, but that would require distinguishing between generic and concrete types when generating
394
// #lower_field_declarations, which would require some form of symbol resolution. That doesn't seem worth
395
// the trouble.
396
397
let expanded = quote! {
398
#[doc(hidden)]
399
#[derive(Clone, Copy)]
400
#[repr(C)]
401
pub struct #lower <#lower_generic_params> {
402
#lower_field_declarations
403
_align: [#wt::ValRaw; 0],
404
}
405
406
unsafe impl #impl_generics #wt::component::ComponentType for #name #ty_generics #where_clause {
407
type Lower = #lower <#lower_generic_args>;
408
409
const ABI: #internal::CanonicalAbiInfo =
410
#internal::CanonicalAbiInfo::record_static(&[#abi_list]);
411
412
#[inline]
413
fn typecheck(
414
ty: &#internal::InterfaceType,
415
types: &#internal::InstanceType<'_>,
416
) -> #internal::anyhow::Result<()> {
417
#internal::#typecheck(ty, types, &[#typecheck_argument])
418
}
419
}
420
};
421
422
Ok(quote!(const _: () = { #expanded };))
423
}
424
425
fn quote(size: DiscriminantSize, discriminant: usize) -> TokenStream {
426
match size {
427
DiscriminantSize::Size1 => {
428
let discriminant = u8::try_from(discriminant).unwrap();
429
quote!(#discriminant)
430
}
431
DiscriminantSize::Size2 => {
432
let discriminant = u16::try_from(discriminant).unwrap();
433
quote!(#discriminant)
434
}
435
DiscriminantSize::Size4 => {
436
let discriminant = u32::try_from(discriminant).unwrap();
437
quote!(#discriminant)
438
}
439
}
440
}
441
442
pub struct LiftExpander;
443
444
impl Expander for LiftExpander {
445
fn expand_record(
446
&self,
447
name: &syn::Ident,
448
generics: &syn::Generics,
449
fields: &[&syn::Field],
450
wt: &syn::Path,
451
) -> Result<TokenStream> {
452
let internal = quote!(#wt::component::__internal);
453
454
let mut lifts = TokenStream::new();
455
let mut loads = TokenStream::new();
456
457
for (i, syn::Field { ident, ty, .. }) in fields.iter().enumerate() {
458
let field_ty = quote!(ty.fields[#i].ty);
459
lifts.extend(
460
quote!(#ident: <#ty as #wt::component::Lift>::linear_lift_from_flat(
461
cx, #field_ty, &src.#ident
462
)?,),
463
);
464
465
loads.extend(
466
quote!(#ident: <#ty as #wt::component::Lift>::linear_lift_from_memory(
467
cx, #field_ty,
468
&bytes
469
[<#ty as #wt::component::ComponentType>::ABI.next_field32_size(&mut offset)..]
470
[..<#ty as #wt::component::ComponentType>::SIZE32]
471
)?,),
472
);
473
}
474
475
let generics = add_trait_bounds(generics, parse_quote!(#wt::component::Lift));
476
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
477
478
let extract_ty = quote! {
479
let ty = match ty {
480
#internal::InterfaceType::Record(i) => &cx.types[i],
481
_ => #internal::bad_type_info(),
482
};
483
};
484
485
let expanded = quote! {
486
unsafe impl #impl_generics #wt::component::Lift for #name #ty_generics #where_clause {
487
#[inline]
488
fn linear_lift_from_flat(
489
cx: &mut #internal::LiftContext<'_>,
490
ty: #internal::InterfaceType,
491
src: &Self::Lower,
492
) -> #internal::anyhow::Result<Self> {
493
#extract_ty
494
Ok(Self {
495
#lifts
496
})
497
}
498
499
#[inline]
500
fn linear_lift_from_memory(
501
cx: &mut #internal::LiftContext<'_>,
502
ty: #internal::InterfaceType,
503
bytes: &[u8],
504
) -> #internal::anyhow::Result<Self> {
505
#extract_ty
506
debug_assert!(
507
(bytes.as_ptr() as usize)
508
% (<Self as #wt::component::ComponentType>::ALIGN32 as usize)
509
== 0
510
);
511
let mut offset = 0;
512
Ok(Self {
513
#loads
514
})
515
}
516
}
517
};
518
519
Ok(expanded)
520
}
521
522
fn expand_variant(
523
&self,
524
name: &syn::Ident,
525
generics: &syn::Generics,
526
discriminant_size: DiscriminantSize,
527
cases: &[VariantCase],
528
wt: &syn::Path,
529
) -> Result<TokenStream> {
530
let internal = quote!(#wt::component::__internal);
531
532
let mut lifts = TokenStream::new();
533
let mut loads = TokenStream::new();
534
535
for (index, VariantCase { ident, ty, .. }) in cases.iter().enumerate() {
536
let index_u32 = u32::try_from(index).unwrap();
537
538
let index_quoted = quote(discriminant_size, index);
539
540
if let Some(ty) = ty {
541
let payload_ty = quote!(ty.cases[#index].unwrap_or_else(#internal::bad_type_info));
542
lifts.extend(
543
quote!(#index_u32 => Self::#ident(<#ty as #wt::component::Lift>::linear_lift_from_flat(
544
cx, #payload_ty, unsafe { &src.payload.#ident }
545
)?),),
546
);
547
548
loads.extend(
549
quote!(#index_quoted => Self::#ident(<#ty as #wt::component::Lift>::linear_lift_from_memory(
550
cx, #payload_ty, &payload[..<#ty as #wt::component::ComponentType>::SIZE32]
551
)?),),
552
);
553
} else {
554
lifts.extend(quote!(#index_u32 => Self::#ident,));
555
556
loads.extend(quote!(#index_quoted => Self::#ident,));
557
}
558
}
559
560
let generics = add_trait_bounds(generics, parse_quote!(#wt::component::Lift));
561
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
562
563
let from_bytes = match discriminant_size {
564
DiscriminantSize::Size1 => quote!(bytes[0]),
565
DiscriminantSize::Size2 => quote!(u16::from_le_bytes(bytes[0..2].try_into()?)),
566
DiscriminantSize::Size4 => quote!(u32::from_le_bytes(bytes[0..4].try_into()?)),
567
};
568
569
let extract_ty = quote! {
570
let ty = match ty {
571
#internal::InterfaceType::Variant(i) => &cx.types[i],
572
_ => #internal::bad_type_info(),
573
};
574
};
575
576
let expanded = quote! {
577
unsafe impl #impl_generics #wt::component::Lift for #name #ty_generics #where_clause {
578
#[inline]
579
fn linear_lift_from_flat(
580
cx: &mut #internal::LiftContext<'_>,
581
ty: #internal::InterfaceType,
582
src: &Self::Lower,
583
) -> #internal::anyhow::Result<Self> {
584
#extract_ty
585
Ok(match src.tag.get_u32() {
586
#lifts
587
discrim => #internal::anyhow::bail!("unexpected discriminant: {}", discrim),
588
})
589
}
590
591
#[inline]
592
fn linear_lift_from_memory(
593
cx: &mut #internal::LiftContext<'_>,
594
ty: #internal::InterfaceType,
595
bytes: &[u8],
596
) -> #internal::anyhow::Result<Self> {
597
let align = <Self as #wt::component::ComponentType>::ALIGN32;
598
debug_assert!((bytes.as_ptr() as usize) % (align as usize) == 0);
599
let discrim = #from_bytes;
600
let payload_offset = <Self as #internal::ComponentVariant>::PAYLOAD_OFFSET32;
601
let payload = &bytes[payload_offset..];
602
#extract_ty
603
Ok(match discrim {
604
#loads
605
discrim => #internal::anyhow::bail!("unexpected discriminant: {}", discrim),
606
})
607
}
608
}
609
};
610
611
Ok(expanded)
612
}
613
614
fn expand_enum(
615
&self,
616
name: &syn::Ident,
617
discriminant_size: DiscriminantSize,
618
cases: &[VariantCase],
619
wt: &syn::Path,
620
) -> Result<TokenStream> {
621
let internal = quote!(#wt::component::__internal);
622
623
let (from_bytes, discrim_ty) = match discriminant_size {
624
DiscriminantSize::Size1 => (quote!(bytes[0]), quote!(u8)),
625
DiscriminantSize::Size2 => (
626
quote!(u16::from_le_bytes(bytes[0..2].try_into()?)),
627
quote!(u16),
628
),
629
DiscriminantSize::Size4 => (
630
quote!(u32::from_le_bytes(bytes[0..4].try_into()?)),
631
quote!(u32),
632
),
633
};
634
let discrim_limit = proc_macro2::Literal::usize_unsuffixed(cases.len());
635
636
let extract_ty = quote! {
637
let ty = match ty {
638
#internal::InterfaceType::Enum(i) => &cx.types[i],
639
_ => #internal::bad_type_info(),
640
};
641
};
642
643
let expanded = quote! {
644
unsafe impl #wt::component::Lift for #name {
645
#[inline]
646
fn linear_lift_from_flat(
647
cx: &mut #internal::LiftContext<'_>,
648
ty: #internal::InterfaceType,
649
src: &Self::Lower,
650
) -> #internal::anyhow::Result<Self> {
651
#extract_ty
652
let discrim = src.tag.get_u32();
653
if discrim >= #discrim_limit {
654
#internal::anyhow::bail!("unexpected discriminant: {discrim}");
655
}
656
Ok(unsafe {
657
#internal::transmute::<#discrim_ty, #name>(discrim as #discrim_ty)
658
})
659
}
660
661
#[inline]
662
fn linear_lift_from_memory(
663
cx: &mut #internal::LiftContext<'_>,
664
ty: #internal::InterfaceType,
665
bytes: &[u8],
666
) -> #internal::anyhow::Result<Self> {
667
let align = <Self as #wt::component::ComponentType>::ALIGN32;
668
debug_assert!((bytes.as_ptr() as usize) % (align as usize) == 0);
669
let discrim = #from_bytes;
670
if discrim >= #discrim_limit {
671
#internal::anyhow::bail!("unexpected discriminant: {discrim}");
672
}
673
Ok(unsafe {
674
#internal::transmute::<#discrim_ty, #name>(discrim)
675
})
676
}
677
}
678
};
679
680
Ok(expanded)
681
}
682
}
683
684
pub struct LowerExpander;
685
686
impl Expander for LowerExpander {
687
fn expand_record(
688
&self,
689
name: &syn::Ident,
690
generics: &syn::Generics,
691
fields: &[&syn::Field],
692
wt: &syn::Path,
693
) -> Result<TokenStream> {
694
let internal = quote!(#wt::component::__internal);
695
696
let mut lowers = TokenStream::new();
697
let mut stores = TokenStream::new();
698
699
for (i, syn::Field { ident, ty, .. }) in fields.iter().enumerate() {
700
let field_ty = quote!(ty.fields[#i].ty);
701
lowers.extend(quote!(#wt::component::Lower::linear_lower_to_flat(
702
&self.#ident, cx, #field_ty, #internal::map_maybe_uninit!(dst.#ident)
703
)?;));
704
705
stores.extend(quote!(#wt::component::Lower::linear_lower_to_memory(
706
&self.#ident,
707
cx,
708
#field_ty,
709
<#ty as #wt::component::ComponentType>::ABI.next_field32_size(&mut offset),
710
)?;));
711
}
712
713
let generics = add_trait_bounds(generics, parse_quote!(#wt::component::Lower));
714
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
715
716
let extract_ty = quote! {
717
let ty = match ty {
718
#internal::InterfaceType::Record(i) => &cx.types[i],
719
_ => #internal::bad_type_info(),
720
};
721
};
722
723
let expanded = quote! {
724
unsafe impl #impl_generics #wt::component::Lower for #name #ty_generics #where_clause {
725
#[inline]
726
fn linear_lower_to_flat<T>(
727
&self,
728
cx: &mut #internal::LowerContext<'_, T>,
729
ty: #internal::InterfaceType,
730
dst: &mut core::mem::MaybeUninit<Self::Lower>,
731
) -> #internal::anyhow::Result<()> {
732
#extract_ty
733
#lowers
734
Ok(())
735
}
736
737
#[inline]
738
fn linear_lower_to_memory<T>(
739
&self,
740
cx: &mut #internal::LowerContext<'_, T>,
741
ty: #internal::InterfaceType,
742
mut offset: usize
743
) -> #internal::anyhow::Result<()> {
744
debug_assert!(offset % (<Self as #wt::component::ComponentType>::ALIGN32 as usize) == 0);
745
#extract_ty
746
#stores
747
Ok(())
748
}
749
}
750
};
751
752
Ok(expanded)
753
}
754
755
fn expand_variant(
756
&self,
757
name: &syn::Ident,
758
generics: &syn::Generics,
759
discriminant_size: DiscriminantSize,
760
cases: &[VariantCase],
761
wt: &syn::Path,
762
) -> Result<TokenStream> {
763
let internal = quote!(#wt::component::__internal);
764
765
let mut lowers = TokenStream::new();
766
let mut stores = TokenStream::new();
767
768
for (index, VariantCase { ident, ty, .. }) in cases.iter().enumerate() {
769
let index_u32 = u32::try_from(index).unwrap();
770
771
let index_quoted = quote(discriminant_size, index);
772
773
let discriminant_size = usize::from(discriminant_size);
774
775
let pattern;
776
let lower;
777
let store;
778
779
if ty.is_some() {
780
let ty = quote!(ty.cases[#index].unwrap_or_else(#internal::bad_type_info));
781
pattern = quote!(Self::#ident(value));
782
lower = quote!(value.linear_lower_to_flat(cx, #ty, dst));
783
store = quote!(value.linear_lower_to_memory(
784
cx,
785
#ty,
786
offset + <Self as #internal::ComponentVariant>::PAYLOAD_OFFSET32,
787
));
788
} else {
789
pattern = quote!(Self::#ident);
790
lower = quote!(Ok(()));
791
store = quote!(Ok(()));
792
}
793
794
lowers.extend(quote!(#pattern => {
795
#internal::map_maybe_uninit!(dst.tag).write(#wt::ValRaw::u32(#index_u32));
796
unsafe {
797
#internal::lower_payload(
798
#internal::map_maybe_uninit!(dst.payload),
799
|payload| #internal::map_maybe_uninit!(payload.#ident),
800
|dst| #lower,
801
)
802
}
803
}));
804
805
stores.extend(quote!(#pattern => {
806
*cx.get::<#discriminant_size>(offset) = #index_quoted.to_le_bytes();
807
#store
808
}));
809
}
810
811
let generics = add_trait_bounds(generics, parse_quote!(#wt::component::Lower));
812
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
813
814
let extract_ty = quote! {
815
let ty = match ty {
816
#internal::InterfaceType::Variant(i) => &cx.types[i],
817
_ => #internal::bad_type_info(),
818
};
819
};
820
821
let expanded = quote! {
822
unsafe impl #impl_generics #wt::component::Lower for #name #ty_generics #where_clause {
823
#[inline]
824
fn linear_lower_to_flat<T>(
825
&self,
826
cx: &mut #internal::LowerContext<'_, T>,
827
ty: #internal::InterfaceType,
828
dst: &mut core::mem::MaybeUninit<Self::Lower>,
829
) -> #internal::anyhow::Result<()> {
830
#extract_ty
831
match self {
832
#lowers
833
}
834
}
835
836
#[inline]
837
fn linear_lower_to_memory<T>(
838
&self,
839
cx: &mut #internal::LowerContext<'_, T>,
840
ty: #internal::InterfaceType,
841
mut offset: usize
842
) -> #internal::anyhow::Result<()> {
843
#extract_ty
844
debug_assert!(offset % (<Self as #wt::component::ComponentType>::ALIGN32 as usize) == 0);
845
match self {
846
#stores
847
}
848
}
849
}
850
};
851
852
Ok(expanded)
853
}
854
855
fn expand_enum(
856
&self,
857
name: &syn::Ident,
858
discriminant_size: DiscriminantSize,
859
_cases: &[VariantCase],
860
wt: &syn::Path,
861
) -> Result<TokenStream> {
862
let internal = quote!(#wt::component::__internal);
863
864
let extract_ty = quote! {
865
let ty = match ty {
866
#internal::InterfaceType::Enum(i) => &cx.types[i],
867
_ => #internal::bad_type_info(),
868
};
869
};
870
871
let (size, ty) = match discriminant_size {
872
DiscriminantSize::Size1 => (1, quote!(u8)),
873
DiscriminantSize::Size2 => (2, quote!(u16)),
874
DiscriminantSize::Size4 => (4, quote!(u32)),
875
};
876
let size = proc_macro2::Literal::usize_unsuffixed(size);
877
878
let expanded = quote! {
879
unsafe impl #wt::component::Lower for #name {
880
#[inline]
881
fn linear_lower_to_flat<T>(
882
&self,
883
cx: &mut #internal::LowerContext<'_, T>,
884
ty: #internal::InterfaceType,
885
dst: &mut core::mem::MaybeUninit<Self::Lower>,
886
) -> #internal::anyhow::Result<()> {
887
#extract_ty
888
#internal::map_maybe_uninit!(dst.tag)
889
.write(#wt::ValRaw::u32(*self as u32));
890
Ok(())
891
}
892
893
#[inline]
894
fn linear_lower_to_memory<T>(
895
&self,
896
cx: &mut #internal::LowerContext<'_, T>,
897
ty: #internal::InterfaceType,
898
mut offset: usize
899
) -> #internal::anyhow::Result<()> {
900
#extract_ty
901
debug_assert!(offset % (<Self as #wt::component::ComponentType>::ALIGN32 as usize) == 0);
902
let discrim = *self as #ty;
903
*cx.get::<#size>(offset) = discrim.to_le_bytes();
904
Ok(())
905
}
906
}
907
};
908
909
Ok(expanded)
910
}
911
}
912
913
pub struct ComponentTypeExpander;
914
915
impl Expander for ComponentTypeExpander {
916
fn expand_record(
917
&self,
918
name: &syn::Ident,
919
generics: &syn::Generics,
920
fields: &[&syn::Field],
921
wt: &syn::Path,
922
) -> Result<TokenStream> {
923
expand_record_for_component_type(
924
name,
925
generics,
926
fields,
927
quote!(typecheck_record),
928
fields
929
.iter()
930
.map(
931
|syn::Field {
932
attrs, ident, ty, ..
933
}| {
934
let name = find_rename(attrs)?.unwrap_or_else(|| {
935
let ident = ident.as_ref().unwrap();
936
syn::LitStr::new(&ident.to_string(), ident.span())
937
});
938
939
Ok(quote!((#name, <#ty as #wt::component::ComponentType>::typecheck),))
940
},
941
)
942
.collect::<Result<_>>()?,
943
wt,
944
)
945
}
946
947
fn expand_variant(
948
&self,
949
name: &syn::Ident,
950
generics: &syn::Generics,
951
_discriminant_size: DiscriminantSize,
952
cases: &[VariantCase],
953
wt: &syn::Path,
954
) -> Result<TokenStream> {
955
let internal = quote!(#wt::component::__internal);
956
957
let mut case_names_and_checks = TokenStream::new();
958
let mut lower_payload_generic_params = TokenStream::new();
959
let mut lower_payload_generic_args = TokenStream::new();
960
let mut lower_payload_case_declarations = TokenStream::new();
961
let mut lower_generic_args = TokenStream::new();
962
let mut abi_list = TokenStream::new();
963
let mut unique_types = HashSet::new();
964
965
for (index, VariantCase { attrs, ident, ty }) in cases.iter().enumerate() {
966
let rename = find_rename(attrs)?;
967
968
let name = rename.unwrap_or_else(|| syn::LitStr::new(&ident.to_string(), ident.span()));
969
970
if let Some(ty) = ty {
971
abi_list.extend(quote!(Some(<#ty as #wt::component::ComponentType>::ABI),));
972
973
case_names_and_checks.extend(
974
quote!((#name, Some(<#ty as #wt::component::ComponentType>::typecheck)),),
975
);
976
977
let generic = format_ident!("T{}", index);
978
979
lower_payload_generic_params.extend(quote!(#generic: Copy,));
980
lower_payload_generic_args.extend(quote!(#generic,));
981
lower_payload_case_declarations.extend(quote!(#ident: #generic,));
982
lower_generic_args.extend(quote!(<#ty as #wt::component::ComponentType>::Lower,));
983
984
unique_types.insert(ty);
985
} else {
986
abi_list.extend(quote!(None,));
987
case_names_and_checks.extend(quote!((#name, None),));
988
lower_payload_case_declarations.extend(quote!(#ident: [#wt::ValRaw; 0],));
989
}
990
}
991
992
let generics = add_trait_bounds(generics, parse_quote!(#wt::component::ComponentType));
993
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
994
let lower = format_ident!("Lower{}", name);
995
let lower_payload = format_ident!("LowerPayload{}", name);
996
997
// You may wonder why we make the types of all the fields of the #lower struct and #lower_payload union
998
// generic. This is to work around a [normalization bug in
999
// rustc](https://github.com/rust-lang/rust/issues/90903) such that the compiler does not understand that
1000
// e.g. `<i32 as ComponentType>::Lower` is `Copy` despite the bound specified in `ComponentType`'s
1001
// definition.
1002
//
1003
// See also the comment in `Self::expand_record` above for another reason why we do this.
1004
1005
let expanded = quote! {
1006
#[doc(hidden)]
1007
#[derive(Clone, Copy)]
1008
#[repr(C)]
1009
pub struct #lower<#lower_payload_generic_params> {
1010
tag: #wt::ValRaw,
1011
payload: #lower_payload<#lower_payload_generic_args>
1012
}
1013
1014
#[doc(hidden)]
1015
#[allow(non_snake_case)]
1016
#[derive(Clone, Copy)]
1017
#[repr(C)]
1018
union #lower_payload<#lower_payload_generic_params> {
1019
#lower_payload_case_declarations
1020
}
1021
1022
unsafe impl #impl_generics #wt::component::ComponentType for #name #ty_generics #where_clause {
1023
type Lower = #lower<#lower_generic_args>;
1024
1025
#[inline]
1026
fn typecheck(
1027
ty: &#internal::InterfaceType,
1028
types: &#internal::InstanceType<'_>,
1029
) -> #internal::anyhow::Result<()> {
1030
#internal::typecheck_variant(ty, types, &[#case_names_and_checks])
1031
}
1032
1033
const ABI: #internal::CanonicalAbiInfo =
1034
#internal::CanonicalAbiInfo::variant_static(&[#abi_list]);
1035
}
1036
1037
unsafe impl #impl_generics #internal::ComponentVariant for #name #ty_generics #where_clause {
1038
const CASES: &'static [Option<#internal::CanonicalAbiInfo>] = &[#abi_list];
1039
}
1040
};
1041
1042
Ok(quote!(const _: () = { #expanded };))
1043
}
1044
1045
fn expand_enum(
1046
&self,
1047
name: &syn::Ident,
1048
_discriminant_size: DiscriminantSize,
1049
cases: &[VariantCase],
1050
wt: &syn::Path,
1051
) -> Result<TokenStream> {
1052
let internal = quote!(#wt::component::__internal);
1053
1054
let mut case_names = TokenStream::new();
1055
let mut abi_list = TokenStream::new();
1056
1057
for VariantCase { attrs, ident, ty } in cases.iter() {
1058
let rename = find_rename(attrs)?;
1059
1060
let name = rename.unwrap_or_else(|| syn::LitStr::new(&ident.to_string(), ident.span()));
1061
1062
if ty.is_some() {
1063
return Err(Error::new(
1064
ident.span(),
1065
"payloads are not permitted for `enum` cases",
1066
));
1067
}
1068
abi_list.extend(quote!(None,));
1069
case_names.extend(quote!(#name,));
1070
}
1071
1072
let lower = format_ident!("Lower{}", name);
1073
1074
let cases_len = cases.len();
1075
let expanded = quote! {
1076
#[doc(hidden)]
1077
#[derive(Clone, Copy)]
1078
#[repr(C)]
1079
pub struct #lower {
1080
tag: #wt::ValRaw,
1081
}
1082
1083
unsafe impl #wt::component::ComponentType for #name {
1084
type Lower = #lower;
1085
1086
#[inline]
1087
fn typecheck(
1088
ty: &#internal::InterfaceType,
1089
types: &#internal::InstanceType<'_>,
1090
) -> #internal::anyhow::Result<()> {
1091
#internal::typecheck_enum(ty, types, &[#case_names])
1092
}
1093
1094
const ABI: #internal::CanonicalAbiInfo =
1095
#internal::CanonicalAbiInfo::enum_(#cases_len);
1096
}
1097
1098
unsafe impl #internal::ComponentVariant for #name {
1099
const CASES: &'static [Option<#internal::CanonicalAbiInfo>] = &[#abi_list];
1100
}
1101
};
1102
1103
Ok(quote!(const _: () = { #expanded };))
1104
}
1105
}
1106
1107
#[derive(Debug)]
1108
struct Flag {
1109
rename: Option<String>,
1110
name: String,
1111
}
1112
1113
impl Parse for Flag {
1114
fn parse(input: ParseStream) -> Result<Self> {
1115
let attributes = syn::Attribute::parse_outer(input)?;
1116
1117
let rename = find_rename(&attributes)?.map(|literal| literal.value());
1118
1119
input.parse::<Token![const]>()?;
1120
let name = input.parse::<syn::Ident>()?.to_string();
1121
1122
Ok(Self { rename, name })
1123
}
1124
}
1125
1126
#[derive(Debug)]
1127
pub struct Flags {
1128
name: String,
1129
flags: Vec<Flag>,
1130
}
1131
1132
impl Parse for Flags {
1133
fn parse(input: ParseStream) -> Result<Self> {
1134
let name = input.parse::<syn::Ident>()?.to_string();
1135
1136
let content;
1137
braced!(content in input);
1138
1139
let flags = content
1140
.parse_terminated(Flag::parse, Token![;])?
1141
.into_iter()
1142
.collect();
1143
1144
Ok(Self { name, flags })
1145
}
1146
}
1147
1148
pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
1149
let wt = default_wasmtime_crate();
1150
let size = FlagsSize::from_count(flags.flags.len());
1151
1152
let ty;
1153
let eq;
1154
1155
let count = flags.flags.len();
1156
1157
match size {
1158
FlagsSize::Size0 => {
1159
ty = quote!(());
1160
eq = quote!(true);
1161
}
1162
FlagsSize::Size1 => {
1163
ty = quote!(u8);
1164
1165
eq = if count == 8 {
1166
quote!(self.__inner0.eq(&rhs.__inner0))
1167
} else {
1168
let mask = !(0xFF_u8 << count);
1169
1170
quote!((self.__inner0 & #mask).eq(&(rhs.__inner0 & #mask)))
1171
};
1172
}
1173
FlagsSize::Size2 => {
1174
ty = quote!(u16);
1175
1176
eq = if count == 16 {
1177
quote!(self.__inner0.eq(&rhs.__inner0))
1178
} else {
1179
let mask = !(0xFFFF_u16 << count);
1180
1181
quote!((self.__inner0 & #mask).eq(&(rhs.__inner0 & #mask)))
1182
};
1183
}
1184
FlagsSize::Size4Plus(n) => {
1185
ty = quote!(u32);
1186
1187
let comparisons = (0..(n - 1))
1188
.map(|index| {
1189
let field = format_ident!("__inner{}", index);
1190
1191
quote!(self.#field.eq(&rhs.#field) &&)
1192
})
1193
.collect::<TokenStream>();
1194
1195
let field = format_ident!("__inner{}", n - 1);
1196
1197
eq = if count % 32 == 0 {
1198
quote!(#comparisons self.#field.eq(&rhs.#field))
1199
} else {
1200
let mask = !(0xFFFF_FFFF_u32 << (count % 32));
1201
1202
quote!(#comparisons (self.#field & #mask).eq(&(rhs.#field & #mask)))
1203
}
1204
}
1205
}
1206
1207
let count;
1208
let mut as_array;
1209
let mut bitor;
1210
let mut bitor_assign;
1211
let mut bitand;
1212
let mut bitand_assign;
1213
let mut bitxor;
1214
let mut bitxor_assign;
1215
let mut not;
1216
1217
match size {
1218
FlagsSize::Size0 => {
1219
count = 0;
1220
as_array = quote!([]);
1221
bitor = quote!(Self {});
1222
bitor_assign = quote!();
1223
bitand = quote!(Self {});
1224
bitand_assign = quote!();
1225
bitxor = quote!(Self {});
1226
bitxor_assign = quote!();
1227
not = quote!(Self {});
1228
}
1229
FlagsSize::Size1 | FlagsSize::Size2 => {
1230
count = 1;
1231
as_array = quote!([self.__inner0 as u32]);
1232
bitor = quote!(Self {
1233
__inner0: self.__inner0.bitor(rhs.__inner0)
1234
});
1235
bitor_assign = quote!(self.__inner0.bitor_assign(rhs.__inner0));
1236
bitand = quote!(Self {
1237
__inner0: self.__inner0.bitand(rhs.__inner0)
1238
});
1239
bitand_assign = quote!(self.__inner0.bitand_assign(rhs.__inner0));
1240
bitxor = quote!(Self {
1241
__inner0: self.__inner0.bitxor(rhs.__inner0)
1242
});
1243
bitxor_assign = quote!(self.__inner0.bitxor_assign(rhs.__inner0));
1244
not = quote!(Self {
1245
__inner0: self.__inner0.not()
1246
});
1247
}
1248
FlagsSize::Size4Plus(n) => {
1249
count = usize::from(n);
1250
as_array = TokenStream::new();
1251
bitor = TokenStream::new();
1252
bitor_assign = TokenStream::new();
1253
bitand = TokenStream::new();
1254
bitand_assign = TokenStream::new();
1255
bitxor = TokenStream::new();
1256
bitxor_assign = TokenStream::new();
1257
not = TokenStream::new();
1258
1259
for index in 0..n {
1260
let field = format_ident!("__inner{}", index);
1261
1262
as_array.extend(quote!(self.#field,));
1263
bitor.extend(quote!(#field: self.#field.bitor(rhs.#field),));
1264
bitor_assign.extend(quote!(self.#field.bitor_assign(rhs.#field);));
1265
bitand.extend(quote!(#field: self.#field.bitand(rhs.#field),));
1266
bitand_assign.extend(quote!(self.#field.bitand_assign(rhs.#field);));
1267
bitxor.extend(quote!(#field: self.#field.bitxor(rhs.#field),));
1268
bitxor_assign.extend(quote!(self.#field.bitxor_assign(rhs.#field);));
1269
not.extend(quote!(#field: self.#field.not(),));
1270
}
1271
1272
as_array = quote!([#as_array]);
1273
bitor = quote!(Self { #bitor });
1274
bitand = quote!(Self { #bitand });
1275
bitxor = quote!(Self { #bitxor });
1276
not = quote!(Self { #not });
1277
}
1278
};
1279
1280
let name = format_ident!("{}", flags.name);
1281
1282
let mut constants = TokenStream::new();
1283
let mut rust_names = TokenStream::new();
1284
let mut component_names = TokenStream::new();
1285
1286
for (index, Flag { name, rename }) in flags.flags.iter().enumerate() {
1287
rust_names.extend(quote!(#name,));
1288
1289
let component_name = rename.as_ref().unwrap_or(name);
1290
component_names.extend(quote!(#component_name,));
1291
1292
let fields = match size {
1293
FlagsSize::Size0 => quote!(),
1294
FlagsSize::Size1 => {
1295
let init = 1_u8 << index;
1296
quote!(__inner0: #init)
1297
}
1298
FlagsSize::Size2 => {
1299
let init = 1_u16 << index;
1300
quote!(__inner0: #init)
1301
}
1302
FlagsSize::Size4Plus(n) => (0..n)
1303
.map(|i| {
1304
let field = format_ident!("__inner{}", i);
1305
1306
let init = if index / 32 == usize::from(i) {
1307
1_u32 << (index % 32)
1308
} else {
1309
0
1310
};
1311
1312
quote!(#field: #init,)
1313
})
1314
.collect::<TokenStream>(),
1315
};
1316
1317
let name = format_ident!("{}", name);
1318
1319
constants.extend(quote!(pub const #name: Self = Self { #fields };));
1320
}
1321
1322
let generics = syn::Generics {
1323
lt_token: None,
1324
params: Punctuated::new(),
1325
gt_token: None,
1326
where_clause: None,
1327
};
1328
1329
let fields = {
1330
let ty = syn::parse2::<syn::Type>(ty.clone())?;
1331
1332
(0..count)
1333
.map(|index| syn::Field {
1334
attrs: Vec::new(),
1335
vis: syn::Visibility::Inherited,
1336
ident: Some(format_ident!("__inner{}", index)),
1337
colon_token: None,
1338
ty: ty.clone(),
1339
mutability: syn::FieldMutability::None,
1340
})
1341
.collect::<Vec<_>>()
1342
};
1343
1344
let fields = fields.iter().collect::<Vec<_>>();
1345
1346
let component_type_impl = expand_record_for_component_type(
1347
&name,
1348
&generics,
1349
&fields,
1350
quote!(typecheck_flags),
1351
component_names,
1352
&wt,
1353
)?;
1354
1355
let internal = quote!(#wt::component::__internal);
1356
1357
let field_names = fields
1358
.iter()
1359
.map(|syn::Field { ident, .. }| ident)
1360
.collect::<Vec<_>>();
1361
1362
let fields = fields
1363
.iter()
1364
.map(|syn::Field { ident, .. }| quote!(#[doc(hidden)] #ident: #ty,))
1365
.collect::<TokenStream>();
1366
1367
let (field_interface_type, field_size) = match size {
1368
FlagsSize::Size0 => (quote!(NOT USED), 0usize),
1369
FlagsSize::Size1 => (quote!(#internal::InterfaceType::U8), 1),
1370
FlagsSize::Size2 => (quote!(#internal::InterfaceType::U16), 2),
1371
FlagsSize::Size4Plus(_) => (quote!(#internal::InterfaceType::U32), 4),
1372
};
1373
1374
let expanded = quote! {
1375
#[derive(Copy, Clone, Default)]
1376
pub struct #name { #fields }
1377
1378
impl #name {
1379
#constants
1380
1381
pub fn as_array(&self) -> [u32; #count] {
1382
#as_array
1383
}
1384
1385
pub fn empty() -> Self {
1386
Self::default()
1387
}
1388
1389
pub fn all() -> Self {
1390
use core::ops::Not;
1391
Self::default().not()
1392
}
1393
1394
pub fn contains(&self, other: Self) -> bool {
1395
*self & other == other
1396
}
1397
1398
pub fn intersects(&self, other: Self) -> bool {
1399
*self & other != Self::empty()
1400
}
1401
}
1402
1403
impl core::cmp::PartialEq for #name {
1404
fn eq(&self, rhs: &#name) -> bool {
1405
#eq
1406
}
1407
}
1408
1409
impl core::cmp::Eq for #name { }
1410
1411
impl core::fmt::Debug for #name {
1412
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1413
#internal::format_flags(&self.as_array(), &[#rust_names], f)
1414
}
1415
}
1416
1417
impl core::ops::BitOr for #name {
1418
type Output = #name;
1419
1420
fn bitor(self, rhs: #name) -> #name {
1421
#bitor
1422
}
1423
}
1424
1425
impl core::ops::BitOrAssign for #name {
1426
fn bitor_assign(&mut self, rhs: #name) {
1427
#bitor_assign
1428
}
1429
}
1430
1431
impl core::ops::BitAnd for #name {
1432
type Output = #name;
1433
1434
fn bitand(self, rhs: #name) -> #name {
1435
#bitand
1436
}
1437
}
1438
1439
impl core::ops::BitAndAssign for #name {
1440
fn bitand_assign(&mut self, rhs: #name) {
1441
#bitand_assign
1442
}
1443
}
1444
1445
impl core::ops::BitXor for #name {
1446
type Output = #name;
1447
1448
fn bitxor(self, rhs: #name) -> #name {
1449
#bitxor
1450
}
1451
}
1452
1453
impl core::ops::BitXorAssign for #name {
1454
fn bitxor_assign(&mut self, rhs: #name) {
1455
#bitxor_assign
1456
}
1457
}
1458
1459
impl core::ops::Not for #name {
1460
type Output = #name;
1461
1462
fn not(self) -> #name {
1463
#not
1464
}
1465
}
1466
1467
#component_type_impl
1468
1469
unsafe impl #wt::component::Lower for #name {
1470
fn linear_lower_to_flat<T>(
1471
&self,
1472
cx: &mut #internal::LowerContext<'_, T>,
1473
_ty: #internal::InterfaceType,
1474
dst: &mut core::mem::MaybeUninit<Self::Lower>,
1475
) -> #internal::anyhow::Result<()> {
1476
#(
1477
self.#field_names.linear_lower_to_flat(
1478
cx,
1479
#field_interface_type,
1480
#internal::map_maybe_uninit!(dst.#field_names),
1481
)?;
1482
)*
1483
Ok(())
1484
}
1485
1486
fn linear_lower_to_memory<T>(
1487
&self,
1488
cx: &mut #internal::LowerContext<'_, T>,
1489
_ty: #internal::InterfaceType,
1490
mut offset: usize
1491
) -> #internal::anyhow::Result<()> {
1492
debug_assert!(offset % (<Self as #wt::component::ComponentType>::ALIGN32 as usize) == 0);
1493
#(
1494
self.#field_names.linear_lower_to_memory(
1495
cx,
1496
#field_interface_type,
1497
offset,
1498
)?;
1499
offset += core::mem::size_of_val(&self.#field_names);
1500
)*
1501
Ok(())
1502
}
1503
}
1504
1505
unsafe impl #wt::component::Lift for #name {
1506
fn linear_lift_from_flat(
1507
cx: &mut #internal::LiftContext<'_>,
1508
_ty: #internal::InterfaceType,
1509
src: &Self::Lower,
1510
) -> #internal::anyhow::Result<Self> {
1511
Ok(Self {
1512
#(
1513
#field_names: #wt::component::Lift::linear_lift_from_flat(
1514
cx,
1515
#field_interface_type,
1516
&src.#field_names,
1517
)?,
1518
)*
1519
})
1520
}
1521
1522
fn linear_lift_from_memory(
1523
cx: &mut #internal::LiftContext<'_>,
1524
_ty: #internal::InterfaceType,
1525
bytes: &[u8],
1526
) -> #internal::anyhow::Result<Self> {
1527
debug_assert!(
1528
(bytes.as_ptr() as usize)
1529
% (<Self as #wt::component::ComponentType>::ALIGN32 as usize)
1530
== 0
1531
);
1532
#(
1533
let (field, bytes) = bytes.split_at(#field_size);
1534
let #field_names = #wt::component::Lift::linear_lift_from_memory(
1535
cx,
1536
#field_interface_type,
1537
field,
1538
)?;
1539
)*
1540
Ok(Self { #(#field_names,)* })
1541
}
1542
}
1543
};
1544
1545
Ok(expanded)
1546
}
1547
1548