aranya_capi_codegen/syntax/
opaque.rs1use proc_macro2::TokenStream;
2use quote::{ToTokens, quote};
3use syn::{
4 Error, Ident, LitInt,
5 parse::{Parse, ParseStream, Result},
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}
26
27impl Opaque {
28 pub(super) fn parse(ctx: Option<&Ctx>, input: ParseStream<'_>) -> Result<Self> {
29 mod kw {
30 syn::custom_keyword!(size);
31 syn::custom_keyword!(align);
32 syn::custom_keyword!(capi);
33 }
34 const SIZE: Symbol = Symbol("size");
35 const ALIGN: Symbol = Symbol("align");
36 const CAPI: Symbol = Symbol("capi");
37
38 let mut size = Attr::none(ALIGN);
39 let mut align = Attr::none(SIZE);
40 let mut capi = Attr::none(CAPI);
41
42 while !input.is_empty() {
43 let lookahead = input.lookahead1();
44 if lookahead.peek(kw::size) {
45 let KeyValPair { key, val } = input.parse::<KeyValPair<kw::size, LitInt>>()?;
46 size.set(key, val)?;
47 } else if lookahead.peek(kw::align) {
48 let KeyValPair { key, val } = input.parse::<KeyValPair<kw::align, LitInt>>()?;
49 align.set(key, val)?;
50 } else if lookahead.peek(kw::capi) {
51 let KeyValPair { key, val } = input.parse::<KeyValPair<kw::capi, Ident>>()?;
52 capi.set(key, val)?;
53 } else {
54 return Err(lookahead.error());
55 }
56 }
57
58 let size = size.get().ok_or(Error::new(
59 input.span(),
60 format!("missing `{SIZE}` argument"),
61 ))?;
62 let align = align.get().ok_or(Error::new(
63 input.span(),
64 format!("missing `{ALIGN}` argument"),
65 ))?;
66 let capi = capi.get().or_else(|| ctx.map(|ctx| ctx.capi.clone()));
67 Ok(Self { size, align, capi })
68 }
69}
70
71impl Parse for Opaque {
72 fn parse(input: ParseStream<'_>) -> Result<Self> {
73 Self::parse(None, input)
74 }
75}
76
77impl ToTokens for Opaque {
78 fn to_tokens(&self, tokens: &mut TokenStream) {
79 let size = &self.size;
80 let align = &self.align;
81 let capi = &self.capi;
82 tokens.extend(quote! {
84 #[#capi::opaque(size = #size, align = #align)]
85 });
86 }
87}