Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit 971bafa

Browse files
committed
Move the macro's input function list to a new module shared
This will enable us to `include!` the file to access these types in `libm-test`, rather than somehow reproducing the types as part of the macro. Ideally `libm-test` would just `use` the types from `libm-macros` but proc macro crates cannot currently export anything else. This also adjusts naming to closer match the scheme described in `libm_test::op`.
1 parent 83835d0 commit 971bafa

File tree

3 files changed

+320
-263
lines changed

3 files changed

+320
-263
lines changed

crates/libm-macros/src/enums.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use quote::quote;
55
use syn::spanned::Spanned;
66
use syn::{Fields, ItemEnum, Variant};
77

8-
use crate::{ALL_FUNCTIONS_FLAT, base_name};
8+
use crate::{ALL_OPERATIONS, base_name};
99

1010
/// Implement `#[function_enum]`, see documentation in `lib.rs`.
1111
pub fn function_enum(
@@ -33,7 +33,7 @@ pub fn function_enum(
3333
let mut as_str_arms = Vec::new();
3434
let mut base_arms = Vec::new();
3535

36-
for func in ALL_FUNCTIONS_FLAT.iter() {
36+
for func in ALL_OPERATIONS.iter() {
3737
let fn_name = func.name;
3838
let ident = Ident::new(&fn_name.to_upper_camel_case(), Span::call_site());
3939
let bname_ident = Ident::new(&base_name(fn_name).to_upper_camel_case(), Span::call_site());
@@ -85,8 +85,7 @@ pub fn base_name_enum(
8585
return Err(syn::Error::new(sp.span(), "no attributes expected"));
8686
}
8787

88-
let mut base_names: Vec<_> =
89-
ALL_FUNCTIONS_FLAT.iter().map(|func| base_name(func.name)).collect();
88+
let mut base_names: Vec<_> = ALL_OPERATIONS.iter().map(|func| base_name(func.name)).collect();
9089
base_names.sort_unstable();
9190
base_names.dedup();
9291

crates/libm-macros/src/lib.rs

Lines changed: 40 additions & 259 deletions
Original file line numberDiff line numberDiff line change
@@ -1,270 +1,18 @@
11
mod enums;
22
mod parse;
3-
4-
use std::sync::LazyLock;
3+
mod shared;
54

65
use parse::{Invocation, StructuredInput};
76
use proc_macro as pm;
87
use proc_macro2::{self as pm2, Span};
98
use quote::{ToTokens, quote};
9+
pub(crate) use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty};
1010
use syn::spanned::Spanned;
1111
use syn::visit_mut::VisitMut;
1212
use syn::{Ident, ItemEnum};
1313

14-
const ALL_FUNCTIONS: &[(Ty, Signature, Option<Signature>, &[&str])] = &[
15-
(
16-
// `fn(f32) -> f32`
17-
Ty::F32,
18-
Signature { args: &[Ty::F32], returns: &[Ty::F32] },
19-
None,
20-
&[
21-
"acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf",
22-
"coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f",
23-
"lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf",
24-
"sqrtf", "tanf", "tanhf", "tgammaf", "truncf",
25-
],
26-
),
27-
(
28-
// `(f64) -> f64`
29-
Ty::F64,
30-
Signature { args: &[Ty::F64], returns: &[Ty::F64] },
31-
None,
32-
&[
33-
"acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh",
34-
"erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10",
35-
"log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh",
36-
"tgamma", "trunc",
37-
],
38-
),
39-
(
40-
// `(f32, f32) -> f32`
41-
Ty::F32,
42-
Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] },
43-
None,
44-
&[
45-
"atan2f",
46-
"copysignf",
47-
"fdimf",
48-
"fmaxf",
49-
"fminf",
50-
"fmodf",
51-
"hypotf",
52-
"nextafterf",
53-
"powf",
54-
"remainderf",
55-
],
56-
),
57-
(
58-
// `(f64, f64) -> f64`
59-
Ty::F64,
60-
Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] },
61-
None,
62-
&[
63-
"atan2",
64-
"copysign",
65-
"fdim",
66-
"fmax",
67-
"fmin",
68-
"fmod",
69-
"hypot",
70-
"nextafter",
71-
"pow",
72-
"remainder",
73-
],
74-
),
75-
(
76-
// `(f32, f32, f32) -> f32`
77-
Ty::F32,
78-
Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] },
79-
None,
80-
&["fmaf"],
81-
),
82-
(
83-
// `(f64, f64, f64) -> f64`
84-
Ty::F64,
85-
Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] },
86-
None,
87-
&["fma"],
88-
),
89-
(
90-
// `(f32) -> i32`
91-
Ty::F32,
92-
Signature { args: &[Ty::F32], returns: &[Ty::I32] },
93-
None,
94-
&["ilogbf"],
95-
),
96-
(
97-
// `(f64) -> i32`
98-
Ty::F64,
99-
Signature { args: &[Ty::F64], returns: &[Ty::I32] },
100-
None,
101-
&["ilogb"],
102-
),
103-
(
104-
// `(i32, f32) -> f32`
105-
Ty::F32,
106-
Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] },
107-
None,
108-
&["jnf"],
109-
),
110-
(
111-
// `(i32, f64) -> f64`
112-
Ty::F64,
113-
Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] },
114-
None,
115-
&["jn"],
116-
),
117-
(
118-
// `(f32, i32) -> f32`
119-
Ty::F32,
120-
Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] },
121-
None,
122-
&["scalbnf", "ldexpf"],
123-
),
124-
(
125-
// `(f64, i64) -> f64`
126-
Ty::F64,
127-
Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] },
128-
None,
129-
&["scalbn", "ldexp"],
130-
),
131-
(
132-
// `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)`
133-
Ty::F32,
134-
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] },
135-
Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }),
136-
&["modff"],
137-
),
138-
(
139-
// `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)`
140-
Ty::F64,
141-
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] },
142-
Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }),
143-
&["modf"],
144-
),
145-
(
146-
// `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)`
147-
Ty::F32,
148-
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] },
149-
Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }),
150-
&["frexpf", "lgammaf_r"],
151-
),
152-
(
153-
// `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)`
154-
Ty::F64,
155-
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] },
156-
Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }),
157-
&["frexp", "lgamma_r"],
158-
),
159-
(
160-
// `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)`
161-
Ty::F32,
162-
Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] },
163-
Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }),
164-
&["remquof"],
165-
),
166-
(
167-
// `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)`
168-
Ty::F64,
169-
Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] },
170-
Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }),
171-
&["remquo"],
172-
),
173-
(
174-
// `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)`
175-
Ty::F32,
176-
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] },
177-
Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }),
178-
&["sincosf"],
179-
),
180-
(
181-
// `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)`
182-
Ty::F64,
183-
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] },
184-
Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }),
185-
&["sincos"],
186-
),
187-
];
188-
18914
const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"];
19015

191-
/// A type used in a function signature.
192-
#[allow(dead_code)]
193-
#[derive(Debug, Clone, Copy)]
194-
enum Ty {
195-
F16,
196-
F32,
197-
F64,
198-
F128,
199-
I32,
200-
CInt,
201-
MutF16,
202-
MutF32,
203-
MutF64,
204-
MutF128,
205-
MutI32,
206-
MutCInt,
207-
}
208-
209-
impl ToTokens for Ty {
210-
fn to_tokens(&self, tokens: &mut pm2::TokenStream) {
211-
let ts = match self {
212-
Ty::F16 => quote! { f16 },
213-
Ty::F32 => quote! { f32 },
214-
Ty::F64 => quote! { f64 },
215-
Ty::F128 => quote! { f128 },
216-
Ty::I32 => quote! { i32 },
217-
Ty::CInt => quote! { ::core::ffi::c_int },
218-
Ty::MutF16 => quote! { &'a mut f16 },
219-
Ty::MutF32 => quote! { &'a mut f32 },
220-
Ty::MutF64 => quote! { &'a mut f64 },
221-
Ty::MutF128 => quote! { &'a mut f128 },
222-
Ty::MutI32 => quote! { &'a mut i32 },
223-
Ty::MutCInt => quote! { &'a mut core::ffi::c_int },
224-
};
225-
226-
tokens.extend(ts);
227-
}
228-
}
229-
230-
/// Representation of e.g. `(f32, f32) -> f32`
231-
#[derive(Debug, Clone)]
232-
struct Signature {
233-
args: &'static [Ty],
234-
returns: &'static [Ty],
235-
}
236-
237-
/// Combined information about a function implementation.
238-
#[derive(Debug, Clone)]
239-
struct FunctionInfo {
240-
name: &'static str,
241-
base_fty: Ty,
242-
/// Function signature for C implementations
243-
c_sig: Signature,
244-
/// Function signature for Rust implementations
245-
rust_sig: Signature,
246-
}
247-
248-
/// A flat representation of `ALL_FUNCTIONS`.
249-
static ALL_FUNCTIONS_FLAT: LazyLock<Vec<FunctionInfo>> = LazyLock::new(|| {
250-
let mut ret = Vec::new();
251-
252-
for (base_fty, rust_sig, c_sig, names) in ALL_FUNCTIONS {
253-
for name in *names {
254-
let api = FunctionInfo {
255-
name,
256-
base_fty: *base_fty,
257-
rust_sig: rust_sig.clone(),
258-
c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()),
259-
};
260-
ret.push(api);
261-
}
262-
}
263-
264-
ret.sort_by_key(|item| item.name);
265-
ret
266-
});
267-
26816
/// Populate an enum with a variant representing function. Names are in upper camel case.
26917
///
27018
/// Applied to an empty enum. Expects one attribute `#[function_enum(BaseName)]` that provides
@@ -382,7 +130,7 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream {
382130
/// Check for any input that is structurally correct but has other problems.
383131
///
384132
/// Returns the list of function names that we should expand for.
385-
fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static FunctionInfo>> {
133+
fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static MathOpInfo>> {
386134
// Collect lists of all functions that are provied as macro inputs in various fields (only,
387135
// skip, attributes).
388136
let attr_mentions = input
@@ -398,7 +146,7 @@ fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static FunctionInf
398146

399147
// Make sure that every function mentioned is a real function
400148
for mentioned in all_mentioned_fns {
401-
if !ALL_FUNCTIONS_FLAT.iter().any(|func| mentioned == func.name) {
149+
if !ALL_OPERATIONS.iter().any(|func| mentioned == func.name) {
402150
let e = syn::Error::new(
403151
mentioned.span(),
404152
format!("unrecognized function name `{mentioned}`"),
@@ -417,7 +165,7 @@ fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static FunctionInf
417165

418166
// Construct a list of what we intend to expand
419167
let mut fn_list = Vec::new();
420-
for func in ALL_FUNCTIONS_FLAT.iter() {
168+
for func in ALL_OPERATIONS.iter() {
421169
let fn_name = func.name;
422170
// If we have an `only` list and it does _not_ contain this function name, skip it
423171
if input.only.as_ref().is_some_and(|only| !only.iter().any(|o| o == fn_name)) {
@@ -498,7 +246,7 @@ fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static FunctionInf
498246
}
499247

500248
/// Expand our structured macro input into invocations of the callback macro.
501-
fn expand(input: StructuredInput, fn_list: &[&FunctionInfo]) -> syn::Result<pm2::TokenStream> {
249+
fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result<pm2::TokenStream> {
502250
let mut out = pm2::TokenStream::new();
503251
let default_ident = Ident::new("_", Span::call_site());
504252
let callback = input.callback;
@@ -545,7 +293,7 @@ fn expand(input: StructuredInput, fn_list: &[&FunctionInfo]) -> syn::Result<pm2:
545293
None => pm2::TokenStream::new(),
546294
};
547295

548-
let base_fty = func.base_fty;
296+
let base_fty = func.float_ty;
549297
let c_args = &func.c_sig.args;
550298
let c_ret = &func.c_sig.returns;
551299
let rust_args = &func.rust_sig.args;
@@ -648,3 +396,36 @@ fn base_name(name: &str) -> &str {
648396
.unwrap_or(name),
649397
}
650398
}
399+
400+
impl ToTokens for Ty {
401+
fn to_tokens(&self, tokens: &mut pm2::TokenStream) {
402+
let ts = match self {
403+
Ty::F16 => quote! { f16 },
404+
Ty::F32 => quote! { f32 },
405+
Ty::F64 => quote! { f64 },
406+
Ty::F128 => quote! { f128 },
407+
Ty::I32 => quote! { i32 },
408+
Ty::CInt => quote! { ::core::ffi::c_int },
409+
Ty::MutF16 => quote! { &'a mut f16 },
410+
Ty::MutF32 => quote! { &'a mut f32 },
411+
Ty::MutF64 => quote! { &'a mut f64 },
412+
Ty::MutF128 => quote! { &'a mut f128 },
413+
Ty::MutI32 => quote! { &'a mut i32 },
414+
Ty::MutCInt => quote! { &'a mut core::ffi::c_int },
415+
};
416+
417+
tokens.extend(ts);
418+
}
419+
}
420+
impl ToTokens for FloatTy {
421+
fn to_tokens(&self, tokens: &mut pm2::TokenStream) {
422+
let ts = match self {
423+
FloatTy::F16 => quote! { f16 },
424+
FloatTy::F32 => quote! { f32 },
425+
FloatTy::F64 => quote! { f64 },
426+
FloatTy::F128 => quote! { f128 },
427+
};
428+
429+
tokens.extend(ts);
430+
}
431+
}

0 commit comments

Comments
 (0)