golem_wasm_derive/
lib.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Golem Source License v1.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://license.golem.cloud/LICENSE
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod from;
16mod into;
17
18use proc_macro::TokenStream;
19use proc_macro2::Ident;
20use syn::parse::{Parse, ParseStream};
21use syn::{Attribute, LitStr, Type, Variant};
22
23#[allow(clippy::duplicated_attributes)]
24#[proc_macro_derive(IntoValue, attributes(wit_transparent, unit_case, wit_field))]
25pub fn derive_into_value(input: TokenStream) -> TokenStream {
26    into::derive_into_value(input)
27}
28
29#[allow(clippy::duplicated_attributes)]
30#[proc_macro_derive(
31    FromValue,
32    attributes(wit_transparent, unit_case, wit_field, from_value)
33)]
34pub fn derive_from_value(input: TokenStream) -> TokenStream {
35    from::derive_from_value(input)
36}
37
38#[derive(Default)]
39struct WitField {
40    skip: bool,
41    rename: Option<LitStr>,
42    convert: Option<Type>,
43    convert_vec: Option<Type>,
44    convert_option: Option<Type>,
45}
46
47fn parse_wit_field_attribute(attr: &Attribute) -> WitField {
48    attr.parse_args_with(WitField::parse)
49        .expect("failed to parse wit_field attribute")
50}
51
52impl Parse for WitField {
53    fn parse(input: ParseStream) -> syn::Result<Self> {
54        let mut skip = false;
55        let mut rename = None;
56        let mut convert = None;
57        let mut convert_vec = None;
58        let mut convert_option = None;
59
60        while !input.is_empty() {
61            let ident: Ident = input.parse()?;
62            if ident == "skip" {
63                skip = true;
64            } else if ident == "rename" {
65                input.parse::<syn::Token![=]>()?;
66                rename = Some(input.parse()?);
67            } else if ident == "convert" {
68                input.parse::<syn::Token![=]>()?;
69                convert = Some(input.parse()?);
70            } else if ident == "convert_vec" {
71                input.parse::<syn::Token![=]>()?;
72                convert_vec = Some(input.parse()?);
73            } else if ident == "convert_option" {
74                input.parse::<syn::Token![=]>()?;
75                convert_option = Some(input.parse()?);
76            } else {
77                return Err(syn::Error::new(ident.span(), "unexpected attribute"));
78            }
79        }
80
81        Ok(WitField {
82            skip,
83            rename,
84            convert,
85            convert_vec,
86            convert_option,
87        })
88    }
89}
90
91fn is_unit_case(variant: &Variant) -> bool {
92    variant.fields.is_empty()
93        || variant
94            .attrs
95            .iter()
96            .any(|attr| attr.path().is_ident("unit_case"))
97}