use crate::{Map, models::kaikki::Tag};
use serde::ser::{SerializeTuple, Serializer};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Clone)]
#[serde(untagged)]
pub enum YomitanEntry {
TermBank(TermBank), TermBankSimplified(TermBankSimplified), TermBankMeta(TermBankMeta), }
impl YomitanEntry {
pub const fn file_prefix(&self) -> &str {
match self {
Self::TermBank(_) | Self::TermBankSimplified(_) => "term_bank",
Self::TermBankMeta(_) => "term_meta_bank",
}
}
}
#[derive(Debug, Clone)]
pub struct TermBank(
pub String, pub String, pub String, pub String, pub Vec<DetailedDefinition>, );
impl Serialize for TermBank {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut tup = serializer.serialize_tuple(8)?;
tup.serialize_element(&self.0)?;
tup.serialize_element(&self.1)?;
tup.serialize_element(&self.2)?;
tup.serialize_element(&self.3)?;
tup.serialize_element(&0u8)?;
tup.serialize_element(&self.4)?;
tup.serialize_element(&0u8)?;
tup.serialize_element(&"")?;
tup.end()
}
}
#[derive(Debug, Clone)]
pub struct TermBankSimplified(
pub String, pub String, pub String, pub Vec<DetailedDefinition>, );
impl Serialize for TermBankSimplified {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut tup = serializer.serialize_tuple(8)?;
tup.serialize_element(&self.0)?;
tup.serialize_element(&self.1)?;
tup.serialize_element(&"non-lemma")?;
tup.serialize_element(&self.2)?;
tup.serialize_element(&0u8)?;
tup.serialize_element(&self.3)?;
tup.serialize_element(&0u8)?;
tup.serialize_element(&"")?;
tup.end()
}
}
#[derive(Debug, Serialize, Clone)]
#[serde(untagged)]
pub enum TermBankMeta {
TermPhoneticTranscription(TermPhoneticTranscription),
}
#[derive(Debug, Clone)]
pub struct TermPhoneticTranscription(
pub String, pub PhoneticTranscription, );
impl Serialize for TermPhoneticTranscription {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut tup = serializer.serialize_tuple(3)?;
tup.serialize_element(&self.0)?;
tup.serialize_element(&"ipa")?;
tup.serialize_element(&self.1)?;
tup.end()
}
}
#[derive(Debug, Serialize, Clone, PartialEq, Eq, Hash, Default)]
pub struct PhoneticTranscription {
pub reading: String,
pub transcriptions: Vec<Ipa>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[serde(default)]
pub struct Ipa {
pub ipa: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub tags: Vec<Tag>,
}
#[derive(Debug, Serialize, Clone)]
#[serde(untagged)]
pub enum Node {
Text(String), Array(Vec<Node>), Generic(Box<GenericNode>), Backlink(BacklinkContent), }
impl Node {
pub fn push(&mut self, node: Self) {
match self {
Self::Array(boxed_vec) => boxed_vec.push(node),
_ => panic!("Error: called 'push' with a non Node::Array"),
}
}
pub const fn new_array() -> Self {
Self::Array(vec![])
}
#[must_use]
pub fn into_array_node(self) -> Self {
Self::Array(vec![self])
}
}
#[derive(Debug, Serialize, Clone)]
pub struct NodeData(pub Map<String, String>);
impl<K, V> FromIterator<(K, V)> for NodeData
where
K: Into<String>,
V: Into<String>,
{
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let inner = iter
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect();
Self(inner)
}
}
#[derive(Debug, Serialize, Clone, Copy)]
#[serde(rename_all = "lowercase")]
pub enum NTag {
Span,
Div,
Ol,
Ul,
Li,
Details,
Summary,
}
#[derive(Debug, Serialize, Clone)]
pub struct GenericNode {
pub tag: NTag,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<NodeData>,
pub content: Node,
}
impl GenericNode {
pub fn into_node(self) -> Node {
Node::Generic(Box::new(self))
}
}
#[derive(Debug, Clone)]
pub enum BacklinkContentKind {
Wiktionary,
Kaikki,
}
#[derive(Debug, Clone)]
pub struct BacklinkContent {
pub href: String,
pub content: BacklinkContentKind,
}
impl BacklinkContent {
pub const fn new(href: String, content: BacklinkContentKind) -> Self {
Self { href, content }
}
}
impl Serialize for BacklinkContent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStruct;
let mut state = serializer.serialize_struct("BacklinkContent", 3)?;
state.serialize_field("tag", "a")?;
state.serialize_field("href", &self.href)?;
state.serialize_field(
"content",
match &self.content {
BacklinkContentKind::Wiktionary => "Wiktionary",
BacklinkContentKind::Kaikki => "Kaikki",
},
)?;
state.end()
}
}
#[derive(Debug, Serialize, Clone)]
#[serde(untagged)]
pub enum DetailedDefinition {
Text(String),
StructuredContent(StructuredContent),
Inflection((String, Vec<String>)),
}
impl DetailedDefinition {
pub fn structured(content: Node) -> Self {
Self::StructuredContent(StructuredContent {
ty: "structured-content".to_string(),
content,
})
}
}
#[derive(Debug, Serialize, Clone)]
pub struct StructuredContent {
#[serde(rename = "type")]
pub ty: String, pub content: Node,
}
pub fn wrap(tag: NTag, content_ty: &str, content: Node) -> Node {
GenericNode {
tag,
title: None, data: match content_ty {
"" => None,
_ => Some(NodeData::from_iter([("content", content_ty)])),
},
content,
}
.into_node()
}
#[derive(Debug, PartialEq, Eq)]
pub struct TagInformation {
pub short_tag: String, pub category: String,
pub sort_order: i32, pub long_tag: String, pub popularity_score: i32,
}
impl TagInformation {
pub fn new(entry: &(&str, &str, i32, &[&str], i32)) -> Self {
debug_assert!(!entry.0.contains(' '));
Self {
short_tag: entry.0.into(),
category: entry.1.into(),
sort_order: entry.2,
long_tag: entry.3[0].into(), popularity_score: entry.4,
}
}
}
impl Serialize for TagInformation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut tup = serializer.serialize_tuple(5)?;
tup.serialize_element(&self.short_tag)?;
tup.serialize_element(&self.category)?;
tup.serialize_element(&self.sort_order)?;
tup.serialize_element(&self.long_tag)?;
tup.serialize_element(&self.popularity_score)?;
tup.end()
}
}