use core::ffi::CStr;
use crate::wrapper::{Nuclide, NuclideMixture, SandiaDecayDataBase, StdString};
pub trait NuclideSpec {
fn get_nuclide<'l>(&self, database: &'l SandiaDecayDataBase) -> Option<&'l Nuclide<'l>>;
fn mixture_activity(&self, time: f64, mixture: &NuclideMixture<'_>) -> Option<f64>;
fn mixture_num_atoms(&self, time: f64, mixture: &NuclideMixture<'_>) -> Option<f64>;
}
macro_rules! impl_as_cpp_string {
(<$l:ident> $t:ty) => {
impl<const $l: usize> NuclideSpec for $t {
#[inline]
fn get_nuclide<'l>(
&self,
database: &'l SandiaDecayDataBase,
) -> Option<&'l Nuclide<'l>> {
database.nuclide_by_name(*self)
}
#[inline]
fn mixture_activity(
&self,
time: f64,
mixture: &NuclideMixture<'_>,
) -> Option<f64> {
mixture.activity_by_symbol(time, *self)
}
#[inline]
fn mixture_num_atoms(
&self,
time: f64,
mixture: &NuclideMixture<'_>,
) -> Option<f64> {
mixture.atoms_by_symbol(time, *self)
}
}
};
($t:ty) => {
impl_as_cpp_string!(@$t);
#[cfg(feature = "alloc")]
impl_as_cpp_string!(@alloc::boxed::Box<$t>);
#[cfg(feature = "alloc")]
impl_as_cpp_string!(@alloc::borrow::Cow<'_, $t>);
};
(@$t:ty) => {
impl NuclideSpec for $t {
#[inline]
fn get_nuclide<'l>(
&self,
database: &'l SandiaDecayDataBase,
) -> Option<&'l Nuclide<'l>> {
database.nuclide_by_name(self)
}
#[inline]
fn mixture_activity(
&self,
time: f64,
mixture: &NuclideMixture<'_>,
) -> Option<f64> {
mixture.activity_by_symbol(time, self)
}
#[inline]
fn mixture_num_atoms(
&self,
time: f64,
mixture: &NuclideMixture<'_>,
) -> Option<f64> {
mixture.atoms_by_symbol(time, self)
}
}
impl_as_cpp_string!(@@&$t);
impl_as_cpp_string!(@@&&$t);
};
(@@$t:ty) => {
impl NuclideSpec for $t {
#[inline]
fn get_nuclide<'l>(
&self,
database: &'l SandiaDecayDataBase,
) -> Option<&'l Nuclide<'l>> {
database.nuclide_by_name(&**self)
}
#[inline]
fn mixture_activity(
&self,
time: f64,
mixture: &NuclideMixture<'_>,
) -> Option<f64> {
mixture.activity_by_symbol(time, &**self)
}
#[inline]
fn mixture_num_atoms(
&self,
time: f64,
mixture: &NuclideMixture<'_>,
) -> Option<f64> {
mixture.atoms_by_symbol(time, &**self)
}
}
};
}
impl_as_cpp_string!(@StdString);
impl_as_cpp_string!(CStr);
#[cfg(feature = "alloc")]
impl_as_cpp_string!(@alloc::ffi::CString);
impl_as_cpp_string!(str);
#[cfg(feature = "alloc")]
impl_as_cpp_string!(@alloc::string::String);
impl_as_cpp_string!([u8]);
#[cfg(feature = "alloc")]
impl_as_cpp_string!(@alloc::vec::Vec<u8>);
#[cfg(feature = "std")]
impl_as_cpp_string!(std::ffi::OsStr);
#[cfg(feature = "std")]
impl_as_cpp_string!(@std::ffi::OsString);
#[cfg(feature = "std")]
impl_as_cpp_string!(std::path::Path);
#[cfg(feature = "std")]
impl_as_cpp_string!(@std::path::PathBuf);
impl_as_cpp_string!(<N> [u8; N]);
impl_as_cpp_string!(<N> &[u8; N]);
impl_as_cpp_string!(<N> &&[u8; N]);
impl NuclideSpec for Nuclide<'_> {
#[inline]
fn get_nuclide<'l>(&self, database: &'l SandiaDecayDataBase) -> Option<&'l Nuclide<'l>> {
database.nuclide_by_name(&self.symbol)
}
#[inline]
fn mixture_activity(&self, time: f64, mixture: &NuclideMixture<'_>) -> Option<f64> {
mixture.activity_by_nuclide(time, self)
}
#[inline]
fn mixture_num_atoms(&self, time: f64, mixture: &NuclideMixture<'_>) -> Option<f64> {
mixture.atoms_by_nuclide(time, self)
}
}
impl NuclideSpec for &Nuclide<'_> {
#[inline]
fn get_nuclide<'l>(&self, database: &'l SandiaDecayDataBase) -> Option<&'l Nuclide<'l>> {
database.nuclide_by_name(&self.symbol)
}
#[inline]
fn mixture_activity(&self, time: f64, mixture: &NuclideMixture<'_>) -> Option<f64> {
mixture.activity_by_nuclide(time, self)
}
#[inline]
fn mixture_num_atoms(&self, time: f64, mixture: &NuclideMixture<'_>) -> Option<f64> {
mixture.atoms_by_nuclide(time, self)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NumSpec {
pub z: i32,
pub mass_number: i32,
pub iso: Option<i32>,
}
impl NuclideSpec for NumSpec {
#[inline]
fn get_nuclide<'l>(&self, database: &'l SandiaDecayDataBase) -> Option<&'l Nuclide<'l>> {
database.nuclide_by_num(self.z, self.mass_number, self.iso.unwrap_or(0))
}
#[inline]
fn mixture_activity(&self, time: f64, mixture: &NuclideMixture<'_>) -> Option<f64> {
mixture.activity_by_num(time, self)
}
#[inline]
fn mixture_num_atoms(&self, time: f64, mixture: &NuclideMixture<'_>) -> Option<f64> {
mixture.atoms_by_num(time, self)
}
}
#[macro_export]
macro_rules! nuclide {
($symbol:ident-$a:literal) => {
$crate::nuclide_spec::NumSpec {
z: $crate::element_inner!($symbol),
mass_number: $a,
iso: None,
}
};
($symbol:ident-$a:ident) => {
$crate::nuclide_spec::NumSpec {
z: $crate::element_inner!($symbol),
mass_number: $a,
iso: None,
}
};
($symbol:ident-$a:literal m) => {
compile_error!("nspec! macro does not support isomers, sorry");
};
($symbol:ident-$a:ident m) => {
compile_error!("nspec! macro does not support isomers, sorry");
};
}