1#![doc = include_str!("../README.md")]
2mod builder;
8mod diagnostic;
9mod value;
10
11pub use builder::{BuildError, TreeBuilder};
12pub use diagnostic::ParseError;
13pub use styx_parse::{ParseErrorKind, ScalarKind, Span};
14pub use value::{Entry, Object, Payload, Scalar, Sequence, Tag, Value};
15
16pub fn parse(source: &str) -> Result<Value, BuildError> {
18 let mut parser = styx_parse::Parser::new(source);
19 let mut builder = TreeBuilder::new();
20 while let Some(event) = parser.next_event() {
21 builder.event(event);
22 }
23 builder.finish()
24}
25
26#[derive(Debug, Clone, PartialEq)]
28pub struct Document {
29 pub root: Object,
31 pub leading_comments: Vec<String>,
33}
34
35impl Document {
36 pub fn parse(source: &str) -> Result<Self, BuildError> {
38 let value = parse(source)?;
39 match value.payload {
40 Some(Payload::Object(root)) => Ok(Document {
41 root,
42 leading_comments: Vec::new(),
43 }),
44 _ => Err(BuildError::UnexpectedEvent(
45 "expected object at root".to_string(),
46 )),
47 }
48 }
49
50 pub fn get(&self, path: &str) -> Option<&Value> {
52 if path.is_empty() {
53 return None;
54 }
55
56 let (segment, rest) = split_path(path);
57 let value = self.root.get(segment)?;
58 if rest.is_empty() {
59 Some(value)
60 } else {
61 value.get(rest)
62 }
63 }
64}
65
66fn split_path(path: &str) -> (&str, &str) {
67 if path.starts_with('[')
68 && let Some(end) = path.find(']')
69 {
70 let segment = &path[..=end];
71 let rest = &path[end + 1..];
72 let rest = rest.strip_prefix('.').unwrap_or(rest);
73 return (segment, rest);
74 }
75
76 let dot_pos = path.find('.');
77 let bracket_pos = path.find('[');
78
79 match (dot_pos, bracket_pos) {
80 (Some(d), Some(b)) if b < d => (&path[..b], &path[b..]),
81 (Some(d), _) => (&path[..d], &path[d + 1..]),
82 (None, Some(b)) => (&path[..b], &path[b..]),
83 (None, None) => (path, ""),
84 }
85}
86
87#[cfg(test)]
88mod tests;