From 8a2afde9030bbd02ed2111d7afa732020e263937 Mon Sep 17 00:00:00 2001 From: Bruce D'Arcus Date: Fri, 9 Jun 2023 09:10:44 -0400 Subject: [PATCH] refactor: add csln-types crate Adapt a few ideas from Hayagriva, and separate out basic data types and formatting code from bibliography and processor. Signed-off-by: Bruce D'Arcus --- Cargo.toml | 2 +- types/Cargo.toml | 21 +++++++++++ types/src/lib.rs | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 types/Cargo.toml create mode 100644 types/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index e340f9d..1121ce7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = [ "cli", "bibliography", - "core", + "types", "citation", "style", "processor", diff --git a/types/Cargo.toml b/types/Cargo.toml new file mode 100644 index 0000000..db91da3 --- /dev/null +++ b/types/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "csl-types" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +edtf = "0.2.0" +icu = { version = "1.2.0", features = ["icu_datetime_experimental"] } +icu_datetime = "1.2.1" +icu_testdata = { version = "1.2.0", features = ["icu_datetime_experimental"] } +citation = { path = "../citation/", package = "csln-citation"} +bibliography = { path = "../bibliography", package = "csln-bibliography" } +style = { path = "../style", package = "csln-style" } +unic-langid = "0.9.1" +serde = { version = "1.0.164", features = ["derive"] } +serde_json = "1.0.96" +serde_yaml = "0.9.21" +schemars = { version = "0.8.12", features = ["url"] } +url = "2.4.0" diff --git a/types/src/lib.rs b/types/src/lib.rs new file mode 100644 index 0000000..ccd34db --- /dev/null +++ b/types/src/lib.rs @@ -0,0 +1,95 @@ +/* +This is a small module for defining basic data types and functions for formatting. + +Some of the ideas and code are adapted from the `typst-hayagriva` crate. + */ + +use std::fmt::{Display, Formatter}; +use serde::{Deserialize, Serialize}; +use schemars::JsonSchema; +use url::Url; +use unic_langid::LanguageIdentifier; +use bibliography::reference::Contributor; +use style::options::StyleOptions; + +/* +This section almost-completely adapted from HayaGriva. + +The primary differences: + +1. We use `serde` for serialization and deserialization. +2. A more general notion of Contributor. +3. Date is a string, not a struct; either EDTF or literal. +4. Use a different model for the `Entry` struct. + */ + +/// The data types that can possibly be held by the various fields of an +/// [`InputReference`]. +#[derive(Clone, Debug, Display, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(untagged)] +#[non_exhaustive] +pub enum Value { + /// A [Title] containing a canonical value and optionally translations and + /// shorthands, all of which are formattable. + Title(Title), + /// A [FmtString] with which the user can override various + /// automatic formatters. + FmtString(FmtString), + /// A string to be reproduced as-is. + Text(String), + /// An integer. + Integer(i64), + /// A date string, either EDTF or literal. + Date(Date), + /// A Contributor. The model allows single strings, a person names struct, or a list of either. + Contributor(Contributor), + /// This could be both an Integer or a Number. + IntegerOrText(NumOrStr), + /// A range between two integers. + Range(std::ops::Range), + /// A duration (of a song or an performance for example). + Duration(Duration), + /// A part of a period. + TimeRange(std::ops::Range), + /// An [URL, possibly with a date of when it has been consulted](QualifiedUrl). + Url(Url), + /// A [Unicode Language Identifier](LanguageIdentifier). + Language(LanguageIdentifier), +} + +/// A value that could be either a number or a string. +#[derive(Clone, Debug, Display, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(untagged)] +pub enum NumOrStr { + /// It's a number! + Number(i64), + /// It's a string! + Str(String), +} + +impl Display for NumOrStr { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + match self { + Self::Number(i) => write!(f, "{}", i), + Self::Str(s) => write!(f, "{}", s), + } + } +} + +impl From for String { + fn from(num: NumOrStr) -> Self { + num.to_string() + } +} + +impl From for i64 { + fn from(num: NumOrStr) -> Self { + match num { + NumOrStr::Number(i) => i, + NumOrStr::Str(s) => s.parse().unwrap_or(0), + } + } +} + + +