Skip to main content

haystack_core/codecs/
mod.rs

1//! Haystack wire format codecs for serialization and deserialization.
2//!
3//! Provides the [`Codec`] trait and five built-in implementations:
4//!
5//! | MIME Type | Module | Description |
6//! |----------|--------|-------------|
7//! | `text/zinc` | [`zinc`] | Zinc — the default Haystack text format (fastest encode/decode) |
8//! | `text/trio` | [`trio`] | Trio — tag-oriented format for defining entities and defs |
9//! | `application/json` | [`json`] (v4) | Haystack JSON v4 — standard JSON encoding |
10//! | `application/json;v=3` | [`json`] (v3) | Haystack JSON v3 — legacy JSON encoding |
11//! | `text/csv` | [`csv`] | CSV — comma-separated values for spreadsheet interop |
12//!
13//! Additional output-only codecs:
14//!
15//! | Module | Description |
16//! |--------|-------------|
17//! | [`rdf`] | RDF serialization in Turtle and JSON-LD formats |
18//!
19//! Use [`codec_for()`] to look up a codec by MIME type:
20//!
21//! ```rust
22//! use haystack_core::codecs::codec_for;
23//!
24//! let zinc = codec_for("text/zinc").unwrap();
25//! let grid = zinc.decode_grid("ver:\"3.0\"\nempty\n").unwrap();
26//! let encoded = zinc.encode_grid(&grid).unwrap();
27//! ```
28//!
29//! The [`shared`] submodule provides common encoding/decoding helper functions
30//! used by multiple codec implementations.
31
32pub mod csv;
33pub mod json;
34pub mod rdf;
35pub mod shared;
36pub mod trio;
37pub mod zinc;
38
39use crate::data::HGrid;
40use crate::kinds::Kind;
41
42/// Errors that can occur during encoding or decoding.
43#[derive(Debug, thiserror::Error)]
44pub enum CodecError {
45    #[error("parse error at position {pos}: {message}")]
46    Parse { pos: usize, message: String },
47    #[error("encoding error: {0}")]
48    Encode(String),
49    #[error("unsupported kind for this codec")]
50    UnsupportedKind,
51}
52
53/// Trait for Haystack wire format codecs.
54pub trait Codec: Send + Sync {
55    /// The MIME type for this codec (e.g. `"text/zinc"`).
56    fn mime_type(&self) -> &str;
57
58    /// Encode an HGrid to a string.
59    fn encode_grid(&self, grid: &HGrid) -> Result<String, CodecError>;
60
61    /// Decode a string to an HGrid.
62    fn decode_grid(&self, input: &str) -> Result<HGrid, CodecError>;
63
64    /// Encode a single scalar Kind value to a string.
65    fn encode_scalar(&self, val: &Kind) -> Result<String, CodecError>;
66
67    /// Decode a string to a single scalar Kind value.
68    fn decode_scalar(&self, input: &str) -> Result<Kind, CodecError>;
69}
70
71static ZINC: zinc::ZincCodec = zinc::ZincCodec;
72static TRIO: trio::TrioCodec = trio::TrioCodec;
73static JSON4: json::Json4Codec = json::Json4Codec;
74static JSON3: json::Json3Codec = json::Json3Codec;
75static CSV: csv::CsvCodec = csv::CsvCodec;
76
77/// Look up a codec by MIME type.
78///
79/// Returns a static codec reference for the given MIME type, or `None` if
80/// the MIME type is not supported.
81pub fn codec_for(mime_type: &str) -> Option<&'static dyn Codec> {
82    match mime_type {
83        "text/zinc" => Some(&ZINC),
84        "text/trio" => Some(&TRIO),
85        "application/json" => Some(&JSON4),
86        "application/json;v=3" => Some(&JSON3),
87        "text/csv" => Some(&CSV),
88        _ => None,
89    }
90}