use std::{
cell::{Cell, UnsafeCell},
collections::HashMap,
mem::MaybeUninit,
sync::Once,
};
use crate::core::Zai;
struct Lazy<T, F = fn() -> T> {
once: Once,
init: Cell<Option<F>>,
value: UnsafeCell<MaybeUninit<T>>,
}
impl<T, F: FnOnce() -> T> Lazy<T, F> {
const fn new(init: F) -> Self {
Lazy {
once: Once::new(),
init: Cell::new(Some(init)),
value: UnsafeCell::new(MaybeUninit::uninit()),
}
}
fn get(&self) -> &T {
self.once.call_once(|| {
let value = (self.init.take().unwrap())();
unsafe {
(*self.value.get()).write(value);
}
});
unsafe { (*self.value.get()).assume_init_ref() }
}
}
unsafe impl<T: Sync + Send, F: Sync + Send> Sync for Lazy<T, F> {}
unsafe impl<T: Send, F: Send> Send for Lazy<T, F> {}
pub trait AtomicMassLibrary {
fn get(&self, zai: Zai) -> Option<f64>;
}
static ENDFB_ATOMIC_MASSES: Lazy<HashMap<Zai, f64>> = Lazy::new(|| {
let source = include_str!("../../data/atomic_masses/endfb");
init_atomic_masses(source)
});
static JEFF_ATOMIC_MASSES: Lazy<HashMap<Zai, f64>> = Lazy::new(|| {
let source = include_str!("../../data/atomic_masses/jeff");
init_atomic_masses(source)
});
static JENDL_ATOMIC_MASSES: Lazy<HashMap<Zai, f64>> = Lazy::new(|| {
let source = include_str!("../../data/atomic_masses/jendl");
init_atomic_masses(source)
});
#[derive(Debug)]
pub struct EndfbAtomicMassLibrary;
impl AtomicMassLibrary for EndfbAtomicMassLibrary {
fn get(&self, zai: Zai) -> Option<f64> {
ENDFB_ATOMIC_MASSES.get().get(&zai).copied()
}
}
#[derive(Debug)]
pub struct JeffAtomicMassLibrary;
impl AtomicMassLibrary for JeffAtomicMassLibrary {
fn get(&self, zai: Zai) -> Option<f64> {
JEFF_ATOMIC_MASSES.get().get(&zai).copied()
}
}
#[derive(Debug)]
pub struct JendlAtomicMassLibrary;
impl AtomicMassLibrary for JendlAtomicMassLibrary {
fn get(&self, zai: Zai) -> Option<f64> {
JENDL_ATOMIC_MASSES.get().get(&zai).copied()
}
}
fn init_atomic_masses(source: &str) -> HashMap<Zai, f64> {
let mut table = HashMap::new();
for line in source.lines() {
let z: u32 = line[..3].trim().parse().unwrap();
let a: u32 = line[4..7].trim().parse().unwrap();
let i: u32 = line[8..9].trim().parse().unwrap();
let zai = Zai::new(z, a, i);
let mass: f64 = line[35..].trim().parse().unwrap();
table.insert(zai, mass);
}
table
}