Skip to content

Commit

Permalink
Package styles, update CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
reknih committed Oct 23, 2023
1 parent d76576b commit 77a6b39
Show file tree
Hide file tree
Showing 14 changed files with 923 additions and 276 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ categories = ["template-engine", "value-formatting", "command-line-utilities"]
keywords = ["bibliography", "citation", "reference", "bibtex", "literature"]

[features]
default = ["biblatex"]
default = ["biblatex", "rkyv"]
cli = ["clap", "strum"]

[dependencies]
Expand All @@ -30,6 +30,7 @@ serde = { version = "1", features = ["derive"] }
indexmap = { version = "2.0.2", features = ["serde"] }
serde_yaml = "0.9.25"
numerals = "0.1.4"
rkyv = { version = "0.7.42", optional = true }

[[bin]]
name = "hayagriva"
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,5 @@ Hayagriva is licensed under a MIT / Apache 2.0 dual license.
Users and consumers of the library may choose which of those licenses they want
to apply whereas contributors have to accept that their code is in compliance
and distributed under the terms of both of these licenses.

Hayagriva includes CSL styles that are licensed as CC-BY-SA 3.0 International if the `rkyv` feature is enabled.
68 changes: 68 additions & 0 deletions src/csl/archive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//! Optional archive of included CSL styles.
use citationberg::{Locale, Style};
use rkyv::{AlignedBytes, Archive, Deserialize, Serialize};
use std::collections::HashMap;

const ARCHIVE: AlignedBytes<1693160> =
AlignedBytes(*include_bytes!("../../styles.cbor.rkyv"));

/// In-memory representation of a CSL archive.
#[derive(Debug, Clone, Archive, Serialize, Deserialize)]
pub struct Lookup {
/// Maps from a CSL style name to an index into the `styles` vector.
pub map: HashMap<String, usize>,
/// The CSL styles in the archive as CBOR-encoded bytes.
pub styles: Vec<Vec<u8>>,
/// The locales in the archive as CBOR-encoded bytes.
pub locales: Vec<Vec<u8>>,
}

/// Read an archive
unsafe fn read(buf: &[u8]) -> &<Lookup as Archive>::Archived {
rkyv::archived_root::<Lookup>(buf)
}

/// An archived CSL style.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ArchiveStyle {
/// Name of the style.
pub name: &'static str,
index: u32,
}

impl ArchiveStyle {
/// Whether a style is an alias of another style.
pub fn is_alias(self, other: Self) -> bool {
self.index == other.index
}
}

/// Retrieve a list of styles.
pub fn styles() -> Vec<ArchiveStyle> {
unsafe { read(&ARCHIVE.0) }
.map
.iter()
.map(|(k, v)| ArchiveStyle { name: k.as_str(), index: *v })
.collect()
}

/// Retrieve a style from the archive
pub fn style(s: ArchiveStyle) -> Style {
Style::from_cbor(&unsafe { read(&ARCHIVE.0) }.styles[s.index as usize]).unwrap()
}

/// Retrieve a style by name.
pub fn style_by_name(n: &str) -> Option<Style> {
let lookup = unsafe { read(&ARCHIVE.0) };
let idx = *lookup.map.get(n)?;
Some(Style::from_cbor(&lookup.styles[idx as usize]).unwrap())
}

/// Retrieve the locales.
pub fn locales() -> Vec<Locale> {
let lookup = unsafe { read(&ARCHIVE.0) };
let res: Result<Vec<_>, _> =
lookup.locales.iter().map(|l| Locale::from_cbor(l)).collect();
res.unwrap()
}
50 changes: 30 additions & 20 deletions src/csl/elem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,6 @@ impl Elem {
Ok(())
}

/// Write the element to a string.
pub fn to_string(&self, format: BufWriteFormat) -> String {
let mut buf = String::new();
self.write_buf(&mut buf, format).unwrap();
buf
}

pub(super) fn is_empty(&self) -> bool {
if self.children.is_empty() {
true
Expand All @@ -93,6 +86,16 @@ impl Elem {
}
}

impl fmt::Display for Elem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
self.write_buf(f, BufWriteFormat::Plain)
} else {
self.write_buf(f, BufWriteFormat::VT100)
}
}
}

/// Merge adjacent text nodes with the same formatting.
pub(super) fn simplify_children(children: ElemChildren) -> ElemChildren {
ElemChildren(children.0.into_iter().fold(Vec::new(), |mut acc, child| {
Expand Down Expand Up @@ -221,12 +224,15 @@ impl ElemChildren {
}
Ok(())
}
}

/// Write the children to a string.
pub fn to_string(&self, format: BufWriteFormat) -> String {
let mut buf = String::new();
self.write_buf(&mut buf, format).unwrap();
buf
impl fmt::Display for ElemChildren {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
self.write_buf(f, BufWriteFormat::Plain)
} else {
self.write_buf(f, BufWriteFormat::VT100)
}
}
}

Expand All @@ -249,7 +255,8 @@ pub enum ElemChild {
}

impl ElemChild {
pub(super) fn write_buf(
/// Write the child to a buffer.
pub fn write_buf(
&self,
w: &mut impl fmt::Write,
format: BufWriteFormat,
Expand Down Expand Up @@ -280,13 +287,6 @@ impl ElemChild {
}
}

/// Write the element to a string.
pub fn to_string(&self, format: BufWriteFormat) -> String {
let mut buf = String::new();
self.write_buf(&mut buf, format).unwrap();
buf
}

pub(super) fn str_len(&self) -> usize {
match self {
ElemChild::Text(t) => t.text.len(),
Expand Down Expand Up @@ -317,6 +317,16 @@ impl ElemChild {
}
}

impl fmt::Display for ElemChild {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
self.write_buf(f, BufWriteFormat::Plain)
} else {
self.write_buf(f, BufWriteFormat::VT100)
}
}
}

impl From<Elem> for ElemChild {
fn from(e: Elem) -> Self {
ElemChild::Elem(e)
Expand Down
10 changes: 6 additions & 4 deletions src/csl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub use self::elem::{
BufWriteFormat, Elem, ElemChild, ElemChildren, ElemMeta, Formatted, Formatting,
};

#[cfg(feature = "rkyv")]
pub mod archive;
mod elem;
mod rendering;
mod sort;
Expand Down Expand Up @@ -267,7 +269,7 @@ impl<'a> BibliographyDriver<'a> {
let Some(name_elem) = cite.items[i]
.rendered
.get_meta(ElemMeta::Names)
.map(|e| e.to_string(BufWriteFormat::Plain))
.map(|e| format!("{:?}", e))
else {
continue;
};
Expand Down Expand Up @@ -685,7 +687,7 @@ fn find_ambiguous_sets(cites: &[SpeculativeCiteRender]) -> Vec<AmbiguousGroup> {
continue;
}

let buf = item.rendered.to_string(BufWriteFormat::Plain);
let buf = format!("{:?}", item.rendered);
match map.entry(buf) {
HmEntry::Occupied(entry) => match *entry.get() {
PotentialDisambiguation::Single(pos) => {
Expand Down Expand Up @@ -2213,10 +2215,10 @@ mod tests {

#[test]
fn test_csl() {
let en_locale = fs::read_to_string("tests/locales-en-US.xml").unwrap();
let en_locale = fs::read_to_string("tests/data/locales-en-US.xml").unwrap();
let en_locale = LocaleFile::from_xml(&en_locale).unwrap();

let yaml = fs::read_to_string("tests/basic.yml").unwrap();
let yaml = fs::read_to_string("tests/data/basic.yml").unwrap();
let bib = from_yaml_str(&yaml).unwrap();
let en_locale = [en_locale.into()];

Expand Down
6 changes: 3 additions & 3 deletions src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl std::fmt::Display for BibLaTeXError {

/// Parse a bibliography from a BibLaTeX source string.
#[cfg(feature = "biblatex")]
pub fn from_biblatex_str(biblatex: &str) -> Result<Vec<Entry>, Vec<BibLaTeXError>> {
pub fn from_biblatex_str(biblatex: &str) -> Result<Library, Vec<BibLaTeXError>> {
let bibliography =
Bibliography::parse(biblatex).map_err(|e| vec![BibLaTeXError::Parse(e)])?;

Expand All @@ -63,7 +63,7 @@ pub fn from_biblatex_str(biblatex: &str) -> Result<Vec<Entry>, Vec<BibLaTeXError

/// Parse a bibliography from a BibLaTeX [`Bibliography`].
#[cfg(feature = "biblatex")]
pub fn from_biblatex(bibliography: &Bibliography) -> Result<Vec<Entry>, Vec<TypeError>> {
pub fn from_biblatex(bibliography: &Bibliography) -> Result<Library, Vec<TypeError>> {
let res: Vec<Result<Entry, TypeError>> =
bibliography.iter().map(TryInto::try_into).collect();
let errors: Vec<TypeError> = res
Expand All @@ -88,7 +88,7 @@ mod tests {

#[test]
fn roundtrip() {
let contents = fs::read_to_string("tests/basic.yml").unwrap();
let contents = fs::read_to_string("tests/data/basic.yml").unwrap();
let entries = from_yaml_str(&contents).unwrap();
let yaml = to_yaml_str(&entries).unwrap();
println!("{}", &yaml);
Expand Down
18 changes: 13 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ use hayagriva::{
CitationItem, CitationRequest, LocaleFile, IndependentStyle
};
let en_locale = fs::read_to_string("tests/locales-en-US.xml").unwrap();
let en_locale = fs::read_to_string("tests/data/locales-en-US.xml").unwrap();
let locales = [LocaleFile::from_xml(&en_locale).unwrap().into()];
let style = fs::read_to_string("tests/art-history.csl").unwrap();
let style = fs::read_to_string("tests/data/art-history.csl").unwrap();
let style = IndependentStyle::from_xml(&style).unwrap();
let mut driver = BibliographyDriver::new();
Expand All @@ -62,7 +62,7 @@ let result = driver.finish(BibliographyRequest {
});
for cite in result.citations {
println!("{}", cite.citation.to_string(BufWriteFormat::Plain))
println!("{}", cite.citation.to_string())
}
```
Expand Down Expand Up @@ -149,6 +149,8 @@ mod util;

use std::collections::BTreeMap;

#[cfg(feature = "rkyv")]
pub use crate::csl::archive;
pub use citationberg::{IndependentStyle, LocaleFile, LongShortForm};
pub use csl::{
standalone_citation, BibliographyDriver, BibliographyRequest, Brackets,
Expand Down Expand Up @@ -240,6 +242,12 @@ impl IntoIterator for Library {
}
}

impl FromIterator<Entry> for Library {
fn from_iter<T: IntoIterator<Item = Entry>>(iter: T) -> Self {
Self(iter.into_iter().map(|e| (e.key().to_string(), e)).collect())
}
}

macro_rules! entry {
($(
$(#[doc = $doc:literal])*
Expand Down Expand Up @@ -868,7 +876,7 @@ mod tests {

#[test]
fn selectors() {
let contents = fs::read_to_string("tests/basic.yml").unwrap();
let contents = fs::read_to_string("tests/data/basic.yml").unwrap();
let entries = from_yaml_str(&contents).unwrap();

select_all!("article > proceedings", entries, ["zygos"]);
Expand Down Expand Up @@ -931,7 +939,7 @@ mod tests {

#[test]
fn selector_bindings() {
let contents = fs::read_to_string("tests/basic.yml").unwrap();
let contents = fs::read_to_string("tests/data/basic.yml").unwrap();
let entries = from_yaml_str(&contents).unwrap();

select!(
Expand Down
Loading

0 comments on commit 77a6b39

Please sign in to comment.