aranya_capi_codegen/syntax/
opaque.rs1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens};
3use syn::{
4 parse::{Parse, ParseStream, Result},
5 Error, Ident, LitBool, LitInt,
6};
7
8use crate::{
9 attr::{Attr, Symbol},
10 ctx::Ctx,
11 util::KeyValPair,
12};
13
14#[derive(Clone, Debug, Eq, PartialEq)]
18pub struct Opaque {
19 pub size: LitInt,
21 pub align: LitInt,
23 pub capi: Option<Ident>,
25 pub generated: bool,
30}
31
32impl Opaque {
33 pub(super) fn parse(ctx: Option<&Ctx>, input: ParseStream<'_>) -> Result<Self> {
34 mod kw {
35 syn::custom_keyword!(size);
36 syn::custom_keyword!(align);
37 syn::custom_keyword!(capi);
38 syn::custom_keyword!(generated);
39 }
40 const SIZE: Symbol = Symbol("size");
41 const ALIGN: Symbol = Symbol("align");
42 const CAPI: Symbol = Symbol("capi");
43 const GENERATED: Symbol = Symbol("generated");
44
45 let mut size = Attr::none(ALIGN);
46 let mut align = Attr::none(SIZE);
47 let mut capi = Attr::none(CAPI);
48 let mut generated = Attr::none(GENERATED);
49
50 while !input.is_empty() {
51 let lookahead = input.lookahead1();
52 if lookahead.peek(kw::size) {
53 let KeyValPair { key, val } = input.parse::<KeyValPair<kw::size, LitInt>>()?;
54 size.set(key, val)?;
55 } else if lookahead.peek(kw::align) {
56 let KeyValPair { key, val } = input.parse::<KeyValPair<kw::align, LitInt>>()?;
57 align.set(key, val)?;
58 } else if lookahead.peek(kw::capi) {
59 let KeyValPair { key, val } = input.parse::<KeyValPair<kw::capi, Ident>>()?;
60 capi.set(key, val)?;
61 } else if lookahead.peek(kw::generated) {
62 let KeyValPair { key, val } =
63 input.parse::<KeyValPair<kw::generated, LitBool>>()?;
64 generated.set(key, val)?;
65 } else {
66 return Err(lookahead.error());
67 }
68 }
69
70 let size = size.get().ok_or(Error::new(
71 input.span(),
72 format!("missing `{SIZE}` argument"),
73 ))?;
74 let align = align.get().ok_or(Error::new(
75 input.span(),
76 format!("missing `{ALIGN}` argument"),
77 ))?;
78 let capi = capi.get().or_else(|| ctx.map(|ctx| ctx.capi.clone()));
79 let generated = generated.get().is_some_and(|a| a.value);
80 Ok(Self {
81 size,
82 align,
83 capi,
84 generated,
85 })
86 }
87}
88
89impl Parse for Opaque {
90 fn parse(input: ParseStream<'_>) -> Result<Self> {
91 Self::parse(None, input)
92 }
93}
94
95impl ToTokens for Opaque {
96 fn to_tokens(&self, tokens: &mut TokenStream) {
97 let size = &self.size;
98 let align = &self.align;
99 let capi = &self.capi;
100 let generated = self.generated;
101 tokens.extend(quote! {
103 #[#capi::opaque(size = #size, align = #align, generated = #generated)]
104 })
105 }
106}