fluent_static_codegen/
function.rs

1use std::collections::HashMap;
2
3use fluent_static_function::FluentFunctionDescriptor;
4use proc_macro2::TokenStream;
5use quote::{format_ident, quote};
6use syn::Ident;
7
8pub trait FunctionCallGenerator {
9    fn generate(
10        &self,
11        function_name: &str,
12        positional_args: &Ident,
13        named_args: &Ident,
14    ) -> Option<TokenStream>;
15}
16
17pub struct FunctionRegistry {
18    fns: HashMap<String, TokenStream>,
19}
20
21impl FunctionRegistry {
22    pub fn register(
23        &mut self,
24        function_id: &str,
25        function_descriptor: impl FluentFunctionDescriptor,
26    ) -> &Self {
27        self.fns
28            .insert(function_id.to_string(), Self::fqn(function_descriptor));
29        self
30    }
31
32    fn fqn(function_descriptor: impl FluentFunctionDescriptor) -> TokenStream {
33        let path = function_descriptor.type_name();
34
35        // HACK fluent_static reexports fluent_static_function,
36        // need to patch function name
37        // to avoid fluent_static_function dependency
38        let path = if path.starts_with("fluent_static_function::builtins") {
39            path.replace("fluent_static_function", "fluent_static::function")
40        } else {
41            path.to_string()
42        };
43
44        let parts: Vec<&str> = path.split("::").collect();
45        let idents: Vec<_> = parts.iter().map(|part| format_ident!("{}", part)).collect();
46
47        quote! { #(#idents)::* }
48    }
49}
50
51impl Default for FunctionRegistry {
52    fn default() -> Self {
53        let fns = HashMap::new();
54        let mut result = Self { fns };
55
56        result.register("NUMBER", fluent_static_function::builtins::number);
57
58        result
59    }
60}
61
62impl FunctionCallGenerator for FunctionRegistry {
63    fn generate(
64        &self,
65        function_name: &str,
66        positional_args: &Ident,
67        named_args: &Ident,
68    ) -> Option<TokenStream> {
69        if let Some(fn_ident) = self.fns.get(function_name) {
70            Some(quote! {
71                #fn_ident(&#positional_args, &#named_args)
72            })
73        } else {
74            None
75        }
76    }
77}