use serde::{
Serialize,
ser::{SerializeMap, Serializer},
};
use super::Block;
use super::anchor::Anchor;
use super::inlines::{CalloutRef, InlineNode};
use super::location::Location;
use super::metadata::BlockMetadata;
use super::title::Title;
pub type ListLevel = u8;
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum ListItemCheckedStatus {
Checked,
Unchecked,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct ListItem {
pub level: ListLevel,
pub marker: String,
pub checked: Option<ListItemCheckedStatus>,
pub principal: Vec<InlineNode>,
pub blocks: Vec<Block>,
pub location: Location,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct DescriptionList {
pub title: Title,
pub metadata: BlockMetadata,
pub items: Vec<DescriptionListItem>,
pub location: Location,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[non_exhaustive]
pub struct DescriptionListItem {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub anchors: Vec<Anchor>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub term: Vec<InlineNode>,
pub delimiter: String,
#[serde(skip)]
pub delimiter_location: Option<Location>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub principal_text: Vec<InlineNode>,
pub description: Vec<Block>,
pub location: Location,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct UnorderedList {
pub title: Title,
pub metadata: BlockMetadata,
pub items: Vec<ListItem>,
pub marker: String,
pub location: Location,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct OrderedList {
pub title: Title,
pub metadata: BlockMetadata,
pub items: Vec<ListItem>,
pub marker: String,
pub location: Location,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct CalloutList {
pub title: Title,
pub metadata: BlockMetadata,
pub items: Vec<CalloutListItem>,
pub location: Location,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct CalloutListItem {
pub callout: CalloutRef,
pub principal: Vec<InlineNode>,
pub blocks: Vec<Block>,
pub location: Location,
}
macro_rules! impl_list_serialize {
($type:ty, $variant:literal, with_marker) => {
impl Serialize for $type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_map(None)?;
state.serialize_entry("name", "list")?;
state.serialize_entry("type", "block")?;
state.serialize_entry("variant", $variant)?;
state.serialize_entry("marker", &self.marker)?;
if !self.title.is_empty() {
state.serialize_entry("title", &self.title)?;
}
if !self.metadata.is_default() {
state.serialize_entry("metadata", &self.metadata)?;
}
state.serialize_entry("items", &self.items)?;
state.serialize_entry("location", &self.location)?;
state.end()
}
}
};
($type:ty, $variant:literal) => {
impl Serialize for $type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_map(None)?;
state.serialize_entry("name", "list")?;
state.serialize_entry("type", "block")?;
state.serialize_entry("variant", $variant)?;
if !self.title.is_empty() {
state.serialize_entry("title", &self.title)?;
}
if !self.metadata.is_default() {
state.serialize_entry("metadata", &self.metadata)?;
}
state.serialize_entry("items", &self.items)?;
state.serialize_entry("location", &self.location)?;
state.end()
}
}
};
}
impl_list_serialize!(UnorderedList, "unordered", with_marker);
impl_list_serialize!(OrderedList, "ordered", with_marker);
impl_list_serialize!(CalloutList, "callout");
impl Serialize for DescriptionList {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_map(None)?;
state.serialize_entry("name", "dlist")?;
state.serialize_entry("type", "block")?;
if !self.title.is_empty() {
state.serialize_entry("title", &self.title)?;
}
if !self.metadata.is_default() {
state.serialize_entry("metadata", &self.metadata)?;
}
state.serialize_entry("items", &self.items)?;
state.serialize_entry("location", &self.location)?;
state.end()
}
}
impl Serialize for ListItem {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_map(None)?;
state.serialize_entry("name", "listItem")?;
state.serialize_entry("type", "block")?;
state.serialize_entry("marker", &self.marker)?;
if let Some(checked) = &self.checked {
state.serialize_entry("checked", checked)?;
}
state.serialize_entry("principal", &self.principal)?;
if !self.blocks.is_empty() {
state.serialize_entry("blocks", &self.blocks)?;
}
state.serialize_entry("location", &self.location)?;
state.end()
}
}
impl Serialize for ListItemCheckedStatus {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match &self {
ListItemCheckedStatus::Checked => serializer.serialize_bool(true),
ListItemCheckedStatus::Unchecked => serializer.serialize_bool(false),
}
}
}
impl Serialize for CalloutListItem {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_map(None)?;
state.serialize_entry("name", "listItem")?;
state.serialize_entry("type", "block")?;
state.serialize_entry("callout", &self.callout)?;
state.serialize_entry("principal", &self.principal)?;
if !self.blocks.is_empty() {
state.serialize_entry("blocks", &self.blocks)?;
}
state.serialize_entry("location", &self.location)?;
state.end()
}
}