use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use std::collections::BTreeMap;
use crate::author::AuthorRef;
use crate::scope::{LocusId, VaultId};
use crate::section::Section;
use crate::status::NoteStatus;
use crate::tag::Tag;
pub type SchemaVersion = u32;
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ExtraFields(pub Option<Box<BTreeMap<String, toml::Value>>>);
impl ExtraFields {
pub fn is_empty(&self) -> bool {
self.0.as_ref().is_none_or(|m| m.is_empty())
}
pub fn empty() -> Self {
Self(None)
}
pub fn insert(&mut self, k: String, v: toml::Value) {
self.0.get_or_insert_with(Default::default).insert(k, v);
}
pub fn get(&self, k: &str) -> Option<&toml::Value> {
self.0.as_ref().and_then(|m| m.get(k))
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Frontmatter {
pub schema_version: SchemaVersion,
pub vault_id: VaultId,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub locus: Option<LocusId>,
pub section: Section,
pub status: NoteStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub status_reason: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub status_changed: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "SmallVec::is_empty")]
pub tags: SmallVec<[Tag; 4]>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub author: Option<AuthorRef>,
pub created: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub updated: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "ExtraFields::is_empty")]
pub extra: ExtraFields,
}