1use std::{collections::BTreeMap, fmt};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
6#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
7#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
8pub struct Position {
9 pub line: usize,
10 pub column: usize,
11 pub offset: usize,
12}
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
17#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
18pub struct Diagnostic {
19 pub code: String,
20 pub message: String,
21 pub position: Position,
22}
23impl Diagnostic {
24 pub(crate) fn new(code: &str, message: impl Into<String>, position: Position) -> Self {
25 Self {
26 code: code.into(),
27 message: message.into(),
28 position,
29 }
30 }
31}
32impl fmt::Display for Diagnostic {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 write!(
35 f,
36 "{}:{}: {}: {}",
37 self.position.line, self.position.column, self.code, self.message
38 )
39 }
40}
41impl std::error::Error for Diagnostic {}
42
43#[derive(Debug, Clone, PartialEq, Eq, Default)]
45#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
46#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
47#[cfg_attr(feature = "json", serde(deny_unknown_fields))]
48pub struct Limits {
49 pub max_tokens: Option<u64>,
50 pub per_item: Option<u64>,
52 pub reason: Option<String>,
54 pub sig: Option<String>,
56}
57
58#[derive(Debug, Clone, PartialEq, Eq)]
60#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
61#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
62#[cfg_attr(
63 feature = "json",
64 serde(tag = "kind", rename_all = "lowercase", deny_unknown_fields)
65)]
66pub enum Node {
67 Text { value: String },
68 Section(Section),
69 Variable(Variable),
70}
71
72#[derive(Debug, Clone, PartialEq, Eq)]
74#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
75#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
76#[cfg_attr(feature = "json", serde(deny_unknown_fields))]
77pub struct Section {
78 pub id: Option<String>,
79 pub limits: Limits,
80 pub children: Vec<Node>,
81 pub position: Position,
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
91#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
92#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
93#[cfg_attr(feature = "json", serde(deny_unknown_fields))]
94pub struct Variable {
95 pub id: String,
96 pub position: Position,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq)]
101#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
102#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
103#[cfg_attr(feature = "json", serde(deny_unknown_fields))]
104pub struct Document {
105 pub version: String,
106 pub tokenizer: String,
107 pub limits: Limits,
108 pub children: Vec<Node>,
109 pub position: Position,
110}
111
112pub type Bindings = BTreeMap<String, String>;
114
115#[derive(Debug, Clone, Copy)]
118pub enum ElementRef<'a> {
119 Section(&'a Section),
120 Variable(&'a Variable),
121}
122
123fn lookup<'a>(nodes: &'a [Node], id: &str) -> Option<ElementRef<'a>> {
124 for node in nodes {
125 match node {
126 Node::Section(s) => {
127 if s.id.as_deref() == Some(id) {
128 return Some(ElementRef::Section(s));
129 }
130 if let Some(found) = lookup(&s.children, id) {
131 return Some(found);
132 }
133 }
134 Node::Variable(v) if v.id == id => return Some(ElementRef::Variable(v)),
135 _ => {}
136 }
137 }
138 None
139}
140fn sections(nodes: &[Node]) -> Vec<&Section> {
141 nodes
142 .iter()
143 .filter_map(|n| {
144 if let Node::Section(s) = n {
145 Some(s)
146 } else {
147 None
148 }
149 })
150 .collect()
151}
152fn display_nodes(nodes: &[Node], f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 for n in nodes {
154 match n {
155 Node::Text { value } => f.write_str(value)?,
156 Node::Section(s) => display_nodes(&s.children, f)?,
157 Node::Variable(v) => write!(f, "{{{{{}}}}}", v.id)?,
159 }
160 }
161 Ok(())
162}
163impl Document {
164 pub fn new(max_tokens: u64, reason: impl Into<String>, children: Vec<Node>) -> Self {
166 Self {
167 version: "0.2".into(),
168 tokenizer: "cl100k_base".into(),
169 limits: Limits {
170 max_tokens: Some(max_tokens),
171 per_item: None,
172 reason: Some(reason.into()),
173 sig: None,
174 },
175 children,
176 position: Position::default(),
177 }
178 }
179 pub fn get_element_by_id(&self, id: &str) -> Option<ElementRef<'_>> {
180 lookup(&self.children, id)
181 }
182 pub fn sections(&self) -> Vec<&Section> {
183 sections(&self.children)
184 }
185}
186impl Section {
187 pub fn new(id: impl Into<String>, children: Vec<Node>) -> Self {
188 Self {
189 id: Some(id.into()),
190 limits: Limits::default(),
191 children,
192 position: Position::default(),
193 }
194 }
195 pub fn get_element_by_id(&self, id: &str) -> Option<ElementRef<'_>> {
196 lookup(&self.children, id)
197 }
198 pub fn sections(&self) -> Vec<&Section> {
199 sections(&self.children)
200 }
201}
202impl Node {
203 pub fn text(value: impl Into<String>) -> Self {
204 Self::Text {
205 value: value.into(),
206 }
207 }
208}
209impl fmt::Display for Section {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 display_nodes(&self.children, f)
212 }
213}
214impl fmt::Display for Document {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 display_nodes(&self.children, f)
217 }
218}
219impl fmt::Display for ElementRef<'_> {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 match self {
222 Self::Section(s) => s.fmt(f),
223 Self::Variable(v) => write!(f, "{{{{{}}}}}", v.id),
224 }
225 }
226}
227
228#[derive(Debug, Clone)]
231#[cfg_attr(feature = "json", derive(serde::Serialize))]
232#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
233pub struct Measurement {
234 pub id: Option<String>,
235 pub tokens: Option<u64>,
236 pub limit: Option<u64>,
237 pub deferred: bool,
238 pub reason: Option<String>,
239}
240#[derive(Debug, Clone, Default)]
241#[cfg_attr(feature = "json", derive(serde::Serialize))]
242#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
243pub struct Report {
244 pub diagnostics: Vec<Diagnostic>,
245 pub measurements: Vec<Measurement>,
246}
247impl Report {
248 pub fn is_ok(&self) -> bool {
250 self.diagnostics.is_empty()
251 }
252}