zeph_bench/dataset.rs
1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4/// The on-disk format used by a dataset's data files.
5///
6/// The format determines how a [`crate::DatasetLoader`] reads the file:
7/// `Jsonl` loaders iterate line-by-line, while `Json` loaders parse the
8/// entire file as a single JSON value.
9///
10/// # Examples
11///
12/// ```
13/// use zeph_bench::DatasetFormat;
14///
15/// assert_ne!(DatasetFormat::Jsonl, DatasetFormat::Json);
16/// ```
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum DatasetFormat {
19 /// New-line–delimited JSON: one JSON object per line.
20 Jsonl,
21 /// A single JSON document (object or array) spanning the entire file.
22 Json,
23}
24
25/// Static metadata describing a benchmark dataset.
26///
27/// Instances are stored in [`DatasetRegistry`] and can be retrieved by name.
28/// The `url` field points to the canonical source so users know where to
29/// download the data.
30///
31/// # Examples
32///
33/// ```
34/// use zeph_bench::{DatasetMeta, DatasetFormat};
35///
36/// let meta = DatasetMeta {
37/// name: "example",
38/// description: "An example dataset",
39/// url: "https://example.com/dataset",
40/// format: DatasetFormat::Jsonl,
41/// };
42/// assert_eq!(meta.name, "example");
43/// ```
44#[derive(Debug, Clone)]
45pub struct DatasetMeta {
46 /// Short identifier used in CLI arguments (e.g. `"gaia"`).
47 pub name: &'static str,
48 /// One-line human-readable description.
49 pub description: &'static str,
50 /// Canonical download URL (`HuggingFace`, GitHub, etc.).
51 pub url: &'static str,
52 /// File format expected by the corresponding [`crate::DatasetLoader`].
53 pub format: DatasetFormat,
54}
55
56/// Registry of all datasets that `zeph-bench` knows about.
57///
58/// The registry is pre-populated with five built-in datasets on construction and
59/// provides case-insensitive lookup by name. It is the authoritative source for
60/// the `bench list` CLI subcommand.
61///
62/// # Built-in Datasets
63///
64/// | Name | Format | Source |
65/// |------|--------|--------|
66/// | `longmemeval` | JSONL | `HuggingFace` xiaowu0162/longmemeval |
67/// | `locomo` | JSON | `HuggingFace` lmlab/locomo |
68/// | `frames` | JSONL | `HuggingFace` google/frames-benchmark |
69/// | `tau-bench` | JSON | GitHub sierra-research/tau-bench |
70/// | `gaia` | JSONL | `HuggingFace` gaia-benchmark/GAIA |
71///
72/// # Examples
73///
74/// ```
75/// use zeph_bench::DatasetRegistry;
76///
77/// let registry = DatasetRegistry::new();
78///
79/// // List all datasets.
80/// assert_eq!(registry.list().len(), 5);
81///
82/// // Lookup is case-insensitive.
83/// assert!(registry.get("GAIA").is_some());
84/// assert!(registry.get("unknown").is_none());
85/// ```
86pub struct DatasetRegistry {
87 datasets: Vec<DatasetMeta>,
88}
89
90impl DatasetRegistry {
91 /// Create a registry pre-populated with all built-in datasets.
92 ///
93 /// # Examples
94 ///
95 /// ```
96 /// use zeph_bench::DatasetRegistry;
97 ///
98 /// let registry = DatasetRegistry::new();
99 /// assert!(!registry.list().is_empty());
100 /// ```
101 #[must_use]
102 pub fn new() -> Self {
103 Self {
104 datasets: vec![
105 DatasetMeta {
106 name: "longmemeval",
107 description: "LongMemEval: long-term memory evaluation benchmark",
108 url: "https://huggingface.co/datasets/xiaowu0162/longmemeval",
109 format: DatasetFormat::Jsonl,
110 },
111 DatasetMeta {
112 name: "locomo",
113 description: "LOCOMO: long-context conversational memory benchmark",
114 url: "https://huggingface.co/datasets/lmlab/locomo",
115 format: DatasetFormat::Json,
116 },
117 DatasetMeta {
118 name: "frames",
119 description: "FRAMES: factual reasoning and multi-step evaluation",
120 url: "https://huggingface.co/datasets/google/frames-benchmark",
121 format: DatasetFormat::Jsonl,
122 },
123 DatasetMeta {
124 name: "tau-bench",
125 description: "tau-bench: tool-augmented user simulation benchmark",
126 url: "https://github.com/sierra-research/tau-bench",
127 format: DatasetFormat::Json,
128 },
129 DatasetMeta {
130 name: "gaia",
131 description: "GAIA: general AI assistants benchmark",
132 url: "https://huggingface.co/datasets/gaia-benchmark/GAIA",
133 format: DatasetFormat::Jsonl,
134 },
135 ],
136 }
137 }
138
139 /// Return a slice of all registered datasets.
140 ///
141 /// # Examples
142 ///
143 /// ```
144 /// use zeph_bench::DatasetRegistry;
145 ///
146 /// let registry = DatasetRegistry::new();
147 /// for meta in registry.list() {
148 /// println!("{}: {}", meta.name, meta.url);
149 /// }
150 /// ```
151 #[must_use]
152 pub fn list(&self) -> &[DatasetMeta] {
153 &self.datasets
154 }
155
156 /// Look up a dataset by name using case-insensitive ASCII comparison.
157 ///
158 /// Returns `None` when no dataset with the given name is registered.
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// use zeph_bench::DatasetRegistry;
164 ///
165 /// let registry = DatasetRegistry::new();
166 /// let meta = registry.get("locomo").expect("locomo is built-in");
167 /// assert_eq!(meta.name, "locomo");
168 ///
169 /// // Case-insensitive.
170 /// assert!(registry.get("LOCOMO").is_some());
171 ///
172 /// // Unknown dataset.
173 /// assert!(registry.get("does-not-exist").is_none());
174 /// ```
175 #[must_use]
176 pub fn get(&self, name: &str) -> Option<&DatasetMeta> {
177 self.datasets
178 .iter()
179 .find(|d| d.name.eq_ignore_ascii_case(name))
180 }
181}
182
183impl Default for DatasetRegistry {
184 fn default() -> Self {
185 Self::new()
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn registry_contains_five_datasets() {
195 let reg = DatasetRegistry::new();
196 assert_eq!(reg.list().len(), 5);
197 }
198
199 #[test]
200 fn registry_get_returns_correct_dataset() {
201 let reg = DatasetRegistry::new();
202 let ds = reg.get("gaia").unwrap();
203 assert_eq!(ds.name, "gaia");
204 }
205
206 #[test]
207 fn registry_get_case_insensitive() {
208 let reg = DatasetRegistry::new();
209 assert!(reg.get("LOCOMO").is_some());
210 }
211
212 #[test]
213 fn registry_get_unknown_returns_none() {
214 let reg = DatasetRegistry::new();
215 assert!(reg.get("unknown-dataset").is_none());
216 }
217}