blob: afd445ff9c5ae00f007e971a18e364f55300e7bd [file] [log] [blame]
//! Types representing individual functions.
//!
//! Each routine gets a module with its name, e.g. `mod sinf { /* ... */ }`. The module
//! contains a unit struct `Routine` which implements `MathOp`.
//!
//! Basically everything could be called a "function" here, so we loosely use the following
//! terminology:
//!
//! - "Function": the math operation that does not have an associated precision. E.g. `f(x) = e^x`,
//! `f(x) = log(x)`.
//! - "Routine": A code implementation of a math operation with a specific precision. E.g. `exp`,
//! `expf`, `expl`, `log`, `logf`.
//! - "Operation" / "Op": Something that relates a routine to a function or is otherwise higher
//! level. `Op` is also used as the name for generic parameters since it is terse.
use std::fmt;
use std::panic::{RefUnwindSafe, UnwindSafe};
pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty};
use crate::{CheckOutput, Float, TupleCall};
mod shared {
include!("../../crates/libm-macros/src/shared.rs");
}
/// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc).
#[libm_macros::function_enum(BaseName)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Identifier {}
impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
/// The name without any type specifier, e.g. `sin` and `sinf` both become `sin`.
#[libm_macros::base_name_enum]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BaseName {}
impl fmt::Display for BaseName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
/// Attributes ascribed to a `libm` routine including signature, type information,
/// and naming.
pub trait MathOp {
/// The float type used for this operation.
type FTy: Float;
/// The function type representing the signature in a C library.
type CFn: Copy;
/// Arguments passed to the C library function as a tuple. These may include `&mut` return
/// values.
type CArgs<'a>
where
Self: 'a;
/// The type returned by C implementations.
type CRet;
/// The signature of the Rust function as a `fn(...) -> ...` type.
type RustFn: Copy + UnwindSafe;
/// Arguments passed to the Rust library function as a tuple.
///
/// The required `TupleCall` bounds ensure this type can be passed either to the C function or
/// to the Rust function.
type RustArgs: Copy
+ TupleCall<Self::RustFn, Output = Self::RustRet>
+ TupleCall<Self::CFn, Output = Self::RustRet>
+ RefUnwindSafe;
/// Type returned from the Rust function.
type RustRet: CheckOutput<Self::RustArgs>;
/// The name of this function, including suffix (e.g. `sin`, `sinf`).
const IDENTIFIER: Identifier;
/// The name as a string.
const NAME: &'static str = Self::IDENTIFIER.as_str();
/// The name of the function excluding the type suffix, e.g. `sin` and `sinf` are both `sin`.
const BASE_NAME: BaseName = Self::IDENTIFIER.base_name();
/// The function in `libm` which can be called.
const ROUTINE: Self::RustFn;
/// Whether or not the function is part of libm public API.
const PUBLIC: bool;
}
/// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types).
pub type OpFTy<Op> = <Op as MathOp>::FTy;
/// Access the associated `FTy::Int` type from an op (helper to avoid ambiguous associated types).
pub type OpITy<Op> = <<Op as MathOp>::FTy as Float>::Int;
/// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types).
pub type OpCFn<Op> = <Op as MathOp>::CFn;
/// Access the associated `CRet` type from an op (helper to avoid ambiguous associated types).
pub type OpCRet<Op> = <Op as MathOp>::CRet;
/// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types).
pub type OpRustFn<Op> = <Op as MathOp>::RustFn;
/// Access the associated `RustArgs` type from an op (helper to avoid ambiguous associated types).
pub type OpRustArgs<Op> = <Op as MathOp>::RustArgs;
/// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types).
pub type OpRustRet<Op> = <Op as MathOp>::RustRet;
macro_rules! create_op_modules {
// Matcher for unary functions
(
fn_name: $fn_name:ident,
FTy: $FTy:ty,
CFn: $CFn:ty,
CArgs: $CArgs:ty,
CRet: $CRet:ty,
RustFn: $RustFn:ty,
RustArgs: $RustArgs:ty,
RustRet: $RustRet:ty,
public: $public:expr,
attrs: [$($attr:meta),*],
) => {
paste::paste! {
$(#[$attr])*
pub mod $fn_name {
use super::*;
pub struct Routine;
impl MathOp for Routine {
type FTy = $FTy;
type CFn = for<'a> $CFn;
type CArgs<'a> = $CArgs where Self: 'a;
type CRet = $CRet;
type RustFn = $RustFn;
type RustArgs = $RustArgs;
type RustRet = $RustRet;
const IDENTIFIER: Identifier = Identifier::[< $fn_name:camel >];
const ROUTINE: Self::RustFn = libm::$fn_name;
const PUBLIC: bool = $public;
}
}
}
};
}
libm_macros::for_each_function! {
callback: create_op_modules,
emit_types: all,
}