use std::collections::BTreeMap;
use serde::de::DeserializeOwned;
use crate::ts_codegen::TsCollector;
pub type DecodeFn<T> =
fn(&mut dyn erased_serde::Deserializer<'_>) -> Result<Option<T>, erased_serde::Error>;
#[derive(Clone, Copy)]
pub(crate) enum TsSource {
Type {
name: fn() -> String,
collect: fn(&mut TsCollector),
},
Keywords {
keywords: &'static [&'static str],
kind: &'static str,
},
Literal(&'static str),
}
pub struct Codec<T: 'static> {
pub(crate) decode: DecodeFn<T>,
pub(crate) ts: TsSource,
}
impl<T: DeserializeOwned> Codec<T> {
pub const fn serde() -> Self
where
T: ts_rs::TS,
{
Self {
decode: decode_serde::<T>,
ts: TsSource::Type {
name: crate::ts_codegen::ts_name::<T>,
collect: crate::ts_codegen::ts_collect::<T>,
},
}
}
pub const fn serde_as(ts: &'static str) -> Self {
Self {
decode: decode_serde::<T>,
ts: TsSource::Literal(ts),
}
}
}
impl<T> Codec<T> {
pub const fn keyword(table: &'static KeywordTable<T>) -> Self {
Self {
decode: table.decode,
ts: TsSource::Keywords {
keywords: table.keywords,
kind: table.kind,
},
}
}
pub const fn custom(decode: DecodeFn<T>, ts: &'static str) -> Self {
Self {
decode,
ts: TsSource::Literal(ts),
}
}
pub(crate) fn decode(
&self,
d: &mut dyn erased_serde::Deserializer<'_>,
) -> Result<Option<T>, erased_serde::Error> {
(self.decode)(d)
}
pub(crate) fn ts_type(&self) -> String {
match self.ts {
TsSource::Type { name, .. } => name(),
TsSource::Keywords { keywords, .. } => keywords
.iter()
.map(|k| format!("{k:?}"))
.collect::<Vec<_>>()
.join(" | "),
TsSource::Literal(s) => s.to_owned(),
}
}
pub(crate) fn ts_decls(&self, decls: &mut BTreeMap<String, String>) {
if let TsSource::Type { collect, .. } = self.ts {
let mut collector = TsCollector::default();
collect(&mut collector);
decls.extend(collector.decls);
}
}
pub(crate) fn keyword_kind(&self) -> Option<&'static str> {
match self.ts {
TsSource::Keywords { kind, .. } => Some(kind),
_ => None,
}
}
}
pub struct KeywordTable<T: 'static> {
pub kind: &'static str,
pub keywords: &'static [&'static str],
pub decode: DecodeFn<T>,
}
fn decode_serde<T: DeserializeOwned>(
d: &mut dyn erased_serde::Deserializer<'_>,
) -> Result<Option<T>, erased_serde::Error> {
erased_serde::deserialize::<Option<T>>(d)
}