use std::fs::OpenOptions;
use std::io::{BufWriter, Write};
use std::path::Path;
use std::any::TypeId;
pub use ts_rs_macros::TS;
#[doc(hidden)]
pub mod export;
pub trait TS: 'static {
fn decl() -> String {
panic!("{} cannot be declared", Self::name());
}
fn name() -> String;
fn inline(#[allow(unused_variables)] indent: usize) -> String {
panic!("{} cannot be inlined", Self::name());
}
fn inline_flattened(#[allow(unused_variables)] indent: usize) -> String {
panic!("{} cannot be flattened", Self::name())
}
fn dependencies() -> Vec<(TypeId, String)>;
fn transparent() -> bool;
fn dump(out: impl AsRef<Path>) -> std::io::Result<()> {
let out = out.as_ref();
let file = OpenOptions::new()
.append(true)
.create(true)
.truncate(false)
.open(out)?;
let mut writer = BufWriter::new(file);
writer.write_all(Self::decl().as_bytes())?;
writer.write_all(b"\n\n")?;
writer.flush()?;
Ok(())
}
}
macro_rules! impl_primitives {
($($($ty:ty),* => $l:literal),*) => { $($(
impl TS for $ty {
fn name() -> String {
$l.to_owned()
}
fn inline(_: usize) -> String {
$l.to_owned()
}
fn dependencies() -> Vec<(TypeId, String)> {
vec![]
}
fn transparent() -> bool {
false
}
}
)*)* };
}
macro_rules! impl_tuples {
( impl $($i:ident),* ) => {
impl<$($i: TS),*> TS for ($($i,)*) {
fn name() -> String {
format!(
"[{}]",
vec![$($i::name()),*].join(", ")
)
}
fn inline(indent: usize) -> String {
format!(
"[{}]",
vec![
$($i::inline(indent)),*
].join(", ")
)
}
fn dependencies() -> Vec<(TypeId, String)> {
vec![$((TypeId::of::<$i>(), $i::name())),*]
}
fn transparent() -> bool {
true
}
}
};
( $i2:ident $(, $i:ident)* ) => {
impl_tuples!(impl $i2 $(, $i)* );
impl_tuples!($($i),*);
};
() => {};
}
macro_rules! impl_proxy {
($($t:tt)*) => {
$($t)* {
fn name() -> String {
T::name()
}
fn inline(indent: usize) -> String {
T::inline(indent)
}
fn inline_flattened(indent: usize) -> String {
T::inline_flattened(indent)
}
fn dependencies() -> Vec<(TypeId, String)> {
T::dependencies()
}
fn transparent() -> bool {
true
}
}
};
}
impl_primitives! {
u8, i8, u16, i16, u32, i32, u64, i64, f32, f64 => "number",
u128, i128 => "bigint",
bool => "boolean",
String, &'static str => "string",
() => "null"
}
impl_tuples!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
impl_proxy!(impl<T: TS> TS for Box<T>);
impl_proxy!(impl<T: TS> TS for std::sync::Arc<T>);
impl_proxy!(impl<T: TS> TS for std::rc::Rc<T>);
impl_proxy!(impl<T: TS + ToOwned> TS for std::borrow::Cow<'static, T>);
impl_proxy!(impl<T: TS> TS for std::cell::Cell<T>);
impl_proxy!(impl<T: TS> TS for std::cell::RefCell<T>);
impl<T: TS> TS for Option<T> {
fn name() -> String {
format!("{} | null", T::name())
}
fn inline(indent: usize) -> String {
format!("{} | null", T::inline(indent))
}
fn dependencies() -> Vec<(TypeId, String)> {
vec![(TypeId::of::<T>(), T::name())]
}
fn transparent() -> bool {
true
}
}
impl<T: TS> TS for Vec<T> {
fn name() -> String {
format!("{}[]", T::name())
}
fn inline(indent: usize) -> String {
format!("{}[]", T::inline(indent))
}
fn dependencies() -> Vec<(TypeId, String)> {
vec![(TypeId::of::<T>(), T::name())]
}
fn transparent() -> bool {
true
}
}