Compare commits

...

17 Commits

Author SHA1 Message Date
Paul Stemmet 86a7364542
lib/value: placeholder public api for the Yaml type 2022-05-28 11:30:02 +00:00
Paul Stemmet f9df2bee09
node/visitor: stream_consumer module wip 2022-04-16 15:38:11 +00:00
Paul Stemmet 88a291e145
node/visitor: add GraphVisitor Visitor impl 2022-04-16 15:38:10 +00:00
Paul Stemmet 4d10d0e4b3
node/visitor: add transform module for handling Event->Node 2022-04-16 15:38:10 +00:00
Paul Stemmet da344ad3e8
node/visitor: add Visitor trait and related types 2022-04-16 15:38:10 +00:00
Paul Stemmet 5df8cf5cef
node/visitor: add module skeleton 2022-04-16 15:38:10 +00:00
Paul Stemmet 50be670043
node/error: add conversions between module error types 2022-04-16 15:38:10 +00:00
Paul Stemmet edea9a6c4a
lib/error: add UndefinedAlias variant for lib/node 2022-04-16 15:38:09 +00:00
Paul Stemmet ebe7890235
node/error: add module skeleton 2022-04-16 15:38:09 +00:00
Paul Stemmet 12271d1c88
nodes/scalar: add data(), data_mut() methods 2022-04-16 15:38:09 +00:00
Paul Stemmet f82dabae9d
node/graph: add Graph representation 2022-04-16 15:38:09 +00:00
Paul Stemmet 5581c28129
node/nodes: add skeleton types for graph nodes 2022-04-16 14:29:18 +00:00
Paul Stemmet cfb7c7bdbc
lib/node: create module skeleton 2022-04-16 14:03:34 +00:00
Paul Stemmet 9b3caee7e4
lib/event: make next_event() pub(crate)
So other modules may use the internal error type
2022-04-16 14:00:02 +00:00
Paul Stemmet 28131d9ad4
build: add deps.slotmap = 1 2022-04-16 14:00:02 +00:00
Paul Stemmet 31330b7734
build/justfile: fix _test Say for selectors 2022-04-16 14:00:02 +00:00
Paul Stemmet a4ce525c15
docs: add notes on yaml graph structure 2022-04-16 14:00:02 +00:00
20 changed files with 2007 additions and 5 deletions

16
Cargo.lock generated
View File

@ -108,6 +108,15 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "slotmap"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
dependencies = [
"version_check",
]
[[package]]
name = "syn"
version = "1.0.89"
@ -125,6 +134,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "winapi"
version = "0.3.9"
@ -156,4 +171,5 @@ dependencies = [
"bitflags",
"cfg-if",
"pretty_assertions",
"slotmap",
]

View File

@ -23,6 +23,7 @@ test_buffer_small = ["test_buffer"]
[dependencies]
atoi = "0.4"
bitflags = "1"
slotmap = "1"
[dev-dependencies]
anyhow = "1"

28
docs/graph-notes.md Normal file
View File

@ -0,0 +1,28 @@
```rust
/*
00) ---
01) &key1 { | A
02) name1: &val1 data1, | B C
03) name2: *key1, | D E
04) name3: *val1, | F G
05) name4: [ | H J
06) data2, | K
07) *key1, | L
08) *val1 | M
09) ],
10) }
*/
enum Node<'a>
{
// B:A C:A D:A F:A H:A K:J
Leaf(ScalarNode<'a>),
// A
Map(MappingNode),
// J:A
List(SequenceNode),
// E:A->A G:A->C L:J->A M:J->C
Alias(AliasNode),
}
```

View File

@ -126,11 +126,11 @@ bump-version to: (_bump-cargo-version "Cargo.toml" trim_start_match(to, "v")) ch
# ~~~ Private recipes ~~~
# Run cargo test with the given suite, profile, features and selector (if any)
_test $suite=None $profile=Profile $features=Features selector=None:
_test $suite=None $profile=Profile $features=Features $selector=None:
@$Say "Running tests" \
"${suite:+{{C_GREEN}}suite:{{C_YELLOW}}$suite{{C_RESET}}}" \
"${features:+{{C_GREEN}}features:{{C_YELLOW}}$features{{C_RESET}}}" \
{{ if selector != None { C_GREEN + "selector:" + C_YELLOW + selector + C_RESET } else { None } }} \
"${selector:+{{C_GREEN}}selector:{{C_YELLOW}}$selector{{C_RESET}}}" \
| xargs
@$Cargo test \
${suite:+--$suite} \

View File

@ -465,6 +465,12 @@ pub(crate) mod internal
/// # ^ MissingFlowMappingEntryOrEnd
/// ```
MissingFlowMappingEntryOrEnd,
/*
* ==== Node Errors ====
*/
/// A YAML alias was used but not defined
UndefinedAlias,
}
/// Heavy and/or external errors that can occur during
@ -643,7 +649,8 @@ pub(crate) mod internal
| MissingNode
| MissingKey
| MissingFlowSequenceEntryOrEnd
| MissingFlowMappingEntryOrEnd => Category::Syntax,
| MissingFlowMappingEntryOrEnd
| UndefinedAlias => Category::Syntax,
IntOverflow | CorruptStream => Category::Data,
@ -713,6 +720,7 @@ pub(crate) mod internal
{
f.write_str("missing flow mapping delimiter ',' or '}'")
},
UndefinedAlias => f.write_str("undefined node alias found"),
}
}
}

View File

@ -315,7 +315,7 @@ where
}
/// Process the next event
fn next_event(&mut self) -> ParseResult<Option<Event<'de>>>
pub(crate) fn next_event(&mut self) -> ParseResult<Option<Event<'de>>>
{
self.inner
.parser
@ -357,7 +357,7 @@ where
}
/// Process the next event
fn next_event(&mut self) -> ParseResult<Option<Event<'de>>>
pub(crate) fn next_event(&mut self) -> ParseResult<Option<Event<'de>>>
{
self.inner
.parser

View File

@ -24,7 +24,9 @@ pub use error::Error;
pub mod error;
pub mod event;
pub mod reader;
pub mod value;
mod node;
mod queue;
mod scanner;
mod token;

92
src/node/error.rs Normal file
View File

@ -0,0 +1,92 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
//! This module contains the errors that may surface while
//! parsing a YAML event stream into memory.
use std::fmt::{self, Debug};
use crate::{
error::{
internal::{ErrorCode, ErrorKind},
mkError,
},
event::error::ParseError,
scanner::error::ScanError,
};
/// Result type returned by [`yary::node`](super)
pub(crate) type NodeResult<T> = std::result::Result<T, NodeError>;
/// Possible errors that can be encountered while parsing
/// YAML graph structures.
#[derive(Debug)]
pub(crate) enum NodeError
{
UndefinedAlias,
Parser(ParseError),
Scanner(ScanError),
}
impl From<ParseError> for NodeError
{
fn from(err: ParseError) -> Self
{
Self::Parser(err)
}
}
impl From<ScanError> for NodeError
{
fn from(err: ScanError) -> Self
{
Self::Scanner(err)
}
}
impl fmt::Display for NodeError
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
Debug::fmt(self, f)
}
}
impl std::error::Error for NodeError
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)>
{
match self
{
Self::Parser(e) => Some(e),
_ => None,
}
}
}
impl From<NodeError> for ErrorKind
{
fn from(err: NodeError) -> Self
{
use ErrorCode::*;
match err
{
NodeError::UndefinedAlias => UndefinedAlias.into(),
NodeError::Parser(e) => e.into(),
NodeError::Scanner(e) => ErrorCode::from(e).into(),
}
}
}
impl From<NodeError> for crate::error::Error
{
fn from(err: NodeError) -> Self
{
mkError!(err, KIND)
}
}

100
src/node/graph.rs Normal file
View File

@ -0,0 +1,100 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
use slotmap::{SecondaryMap, SlotMap};
use super::nodes::{Node, NodeData, NodeIndex};
struct Graph<'a>
{
store: Storage<'a>,
head: Option<NodeIndex>,
}
impl<'a> Graph<'a>
{
/// Create a new, empty Graph
pub fn new() -> Self
{
Self {
store: Storage::new(),
head: None,
}
}
pub fn insert<F>(&mut self, f: F, data: NodeData<'a>) -> NodeIndex
where
F: FnOnce(NodeIndex) -> Node<'a>,
{
self.store.insert(f, data)
}
pub fn nodes(&self) -> &SlotMap<NodeIndex, Node<'a>>
{
self.store.nodes()
}
pub fn nodes_mut(&mut self) -> &mut SlotMap<NodeIndex, Node<'a>>
{
self.store.nodes_mut()
}
pub fn node_data(&self) -> &SecondaryMap<NodeIndex, NodeData<'a>>
{
self.store.node_data()
}
pub fn node_data_mut(&mut self) -> &mut SecondaryMap<NodeIndex, NodeData<'a>>
{
self.store.node_data_mut()
}
}
#[derive(Default)]
pub(in crate::node) struct Storage<'a>
{
nodes: SlotMap<NodeIndex, Node<'a>>,
node_data: SecondaryMap<NodeIndex, NodeData<'a>>,
}
impl<'a> Storage<'a>
{
pub fn new() -> Self
{
Self::default()
}
pub fn nodes(&self) -> &SlotMap<NodeIndex, Node<'a>>
{
&self.nodes
}
pub fn nodes_mut(&mut self) -> &mut SlotMap<NodeIndex, Node<'a>>
{
&mut self.nodes
}
pub fn node_data(&self) -> &SecondaryMap<NodeIndex, NodeData<'a>>
{
&self.node_data
}
pub fn node_data_mut(&mut self) -> &mut SecondaryMap<NodeIndex, NodeData<'a>>
{
&mut self.node_data
}
pub fn insert<F>(&mut self, f: F, data: NodeData<'a>) -> NodeIndex
where
F: FnOnce(NodeIndex) -> Node<'a>,
{
let id = self.nodes_mut().insert_with_key(f);
self.node_data_mut().insert(id, data);
id
}
}

15
src/node/mod.rs Normal file
View File

@ -0,0 +1,15 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
//! This module contains the basis for storing arbitrary
//! YAML documents as an in memory graph.
use crate::event::types::Slice;
pub(crate) mod error;
mod graph;
mod nodes;
mod visitor;

61
src/node/nodes/alias.rs Normal file
View File

@ -0,0 +1,61 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
use crate::node::nodes::{NodeIndex, NodeSpecific};
pub(in crate::node) struct AliasNode
{
parent: NodeIndex,
id: NodeIndex,
points_to: NodeIndex,
}
impl AliasNode
{
pub fn new(id: NodeIndex, parent: NodeIndex, points_to: NodeIndex) -> Self
{
Self::with_parent(id, parent, points_to)
}
pub fn new_with_data(
parent: NodeIndex,
points_to: NodeIndex,
) -> impl FnOnce(NodeIndex) -> AliasNode
{
move |id| Self::new(id, parent, points_to)
}
pub fn id(&self) -> NodeIndex
{
self.id
}
pub fn parent(&self) -> Option<NodeIndex>
{
Some(self.parent)
}
fn with_parent(id: NodeIndex, parent: NodeIndex, points_to: NodeIndex) -> Self
{
Self {
parent,
id,
points_to,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(in crate::node) struct AliasData;
impl AliasData
{
pub fn opaque(self) -> NodeSpecific
{
self.into()
}
}

72
src/node/nodes/mapping.rs Normal file
View File

@ -0,0 +1,72 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
use std::collections::HashMap;
use crate::node::nodes::{NodeIndex, NodeSpecific};
pub(in crate::node) type Children = HashMap<NodeIndex, Option<NodeIndex>>;
pub(in crate::node) struct MappingNode
{
parent: Option<NodeIndex>,
id: NodeIndex,
children: Children,
}
impl MappingNode
{
pub fn root(id: NodeIndex) -> Self
{
Self::with_parent(id, None)
}
pub fn new(id: NodeIndex, parent: NodeIndex) -> Self
{
Self::with_parent(id, Some(parent))
}
pub fn root_with() -> impl FnOnce(NodeIndex) -> MappingNode
{
move |id| Self::root(id)
}
pub fn new_with(parent: NodeIndex) -> impl FnOnce(NodeIndex) -> MappingNode
{
move |id| Self::new(id, parent)
}
pub fn children(&self) -> &Children
{
&self.children
}
pub fn children_mut(&mut self) -> &mut Children
{
&mut self.children
}
fn with_parent(id: NodeIndex, parent: Option<NodeIndex>) -> Self
{
Self {
parent,
id,
children: Default::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(in crate::node) struct MappingData;
impl MappingData
{
pub fn opaque(self) -> NodeSpecific
{
self.into()
}
}

253
src/node/nodes/mod.rs Normal file
View File

@ -0,0 +1,253 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
use slotmap::new_key_type;
use crate::node::{
nodes::{
alias::{AliasData, AliasNode},
mapping::{MappingData, MappingNode},
scalar::{ScalarData, ScalarNode},
sequence::{SequenceData, SequenceNode},
},
Slice,
};
pub(in crate::node) mod alias;
pub(in crate::node) mod mapping;
pub(in crate::node) mod scalar;
pub(in crate::node) mod sequence;
new_key_type! {
/// Identifier used for locating [Node]s in a graph.
///
/// An invariant of this type is that one should never use
/// [NodeIndex]s as indexes into graphs that did not generate
/// the [NodeIndex]. Behavior is safe and cannot cause UB,
/// but is unspecified, and never what you want.
pub(in crate::node) struct NodeIndex;
}
/// Possible nodes one can encounter while traversing a
/// graph.
///
/// Importantly, only `LeafNode`s contain data, all other
/// variants deal with the structure of the graph and can be
/// considered internal nodes.
pub(in crate::node) enum Node<'de>
{
/// Data container, storing a single scalar node
Leaf(ScalarNode<'de>),
/// Mapping node, storing key value node pairs
Map(MappingNode),
/// List node, storing a sequence of nodes
List(SequenceNode),
/// Alias node pointing to a previously seen node
Alias(AliasNode),
}
impl<'de> Node<'de>
{
/// Wrap the new scalar node produced by f
pub fn scalar<F>(f: F) -> impl FnOnce(NodeIndex) -> Node<'de>
where
F: FnOnce(NodeIndex) -> ScalarNode<'de>,
{
|id| Node::Leaf(f(id))
}
/// Wrap the new mapping node produced by f
pub fn mapping<F>(f: F) -> impl FnOnce(NodeIndex) -> Node<'de>
where
F: FnOnce(NodeIndex) -> MappingNode,
{
|id| Node::Map(f(id))
}
/// Wrap the new sequence node produced by f
pub fn sequence<F>(f: F) -> impl FnOnce(NodeIndex) -> Node<'de>
where
F: FnOnce(NodeIndex) -> SequenceNode,
{
|id| Node::List(f(id))
}
/// Wrap the new alias node produced by f
pub fn alias<F>(f: F) -> impl FnOnce(NodeIndex) -> Node<'de>
where
F: FnOnce(NodeIndex) -> AliasNode,
{
|id| Node::Alias(f(id))
}
}
#[derive(Debug, Clone)]
pub(in crate::node) struct NodeData<'de>
{
anchor: Option<Slice<'de>>,
tag: Option<Tag<'de>>,
context: NodeContext,
mark: NodeMark,
node_specific: NodeSpecific,
}
impl<'de> NodeData<'de>
{
pub fn new(
anchor: Option<Slice<'de>>,
tag: Option<Tag<'de>>,
context: NodeContext,
mark: NodeMark,
ns: NodeSpecific,
) -> Self
{
Self {
anchor,
tag,
context,
mark,
node_specific: ns,
}
}
pub fn anchor(&self) -> Option<&Slice<'de>>
{
self.anchor.as_ref()
}
pub fn tag(&self) -> Option<&Tag<'de>>
{
self.tag.as_ref()
}
pub fn context(&self) -> NodeContext
{
self.context
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(in crate::node) struct Tag<'de>
{
handle: Slice<'de>,
prefix: Slice<'de>,
suffix: Slice<'de>,
}
impl<'de> Tag<'de>
{
pub fn new(handle: Slice<'de>, prefix: Slice<'de>, suffix: Slice<'de>) -> Self
{
Self {
handle,
prefix,
suffix,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(in crate::node) enum NodeContext
{
Block,
Flow,
}
impl NodeContext
{
pub const fn is_block(self) -> bool
{
matches!(self, Self::Block)
}
pub const fn is_flow(self) -> bool
{
!self.is_block()
}
}
impl Default for NodeContext
{
fn default() -> Self
{
Self::Block
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(in crate::node) struct NodeMark
{
start: usize,
end: usize,
}
impl NodeMark
{
pub const fn new(start: usize, end: usize) -> Self
{
Self { start, end }
}
pub const fn start(&self) -> usize
{
self.start
}
pub const fn end(&self) -> usize
{
self.end
}
}
impl From<(usize, usize)> for NodeMark
{
fn from((start, end): (usize, usize)) -> Self
{
Self::new(start, end)
}
}
#[derive(Debug, Clone)]
pub(in crate::node) enum NodeSpecific
{
Mapping(MappingData),
Sequence(SequenceData),
Alias(AliasData),
Scalar(ScalarData),
}
impl From<ScalarData> for NodeSpecific
{
fn from(data: ScalarData) -> Self
{
Self::Scalar(data)
}
}
impl From<AliasData> for NodeSpecific
{
fn from(data: AliasData) -> Self
{
Self::Alias(data)
}
}
impl From<MappingData> for NodeSpecific
{
fn from(data: MappingData) -> Self
{
Self::Mapping(data)
}
}
impl From<SequenceData> for NodeSpecific
{
fn from(data: SequenceData) -> Self
{
Self::Sequence(data)
}
}

200
src/node/nodes/scalar.rs Normal file
View File

@ -0,0 +1,200 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
use crate::{
node::{
graph::Storage,
nodes::{NodeContext, NodeData, NodeIndex, NodeMark, NodeSpecific, Tag},
},
token::{ScalarStyle, Slice},
};
pub(in crate::node) struct ScalarNode<'de>
{
parent: Option<NodeIndex>,
id: NodeIndex,
scalar: Slice<'de>,
}
impl<'de> ScalarNode<'de>
{
pub fn root(id: NodeIndex, data: Slice<'de>) -> Self
{
Self::with_parent(id, data, None)
}
pub fn new(id: NodeIndex, parent: NodeIndex, data: Slice<'de>) -> Self
{
Self::with_parent(id, data, Some(parent))
}
pub fn root_with_data(data: Slice<'de>) -> impl FnOnce(NodeIndex) -> ScalarNode<'de>
{
move |id| Self::root(id, data)
}
pub fn new_with_data(
parent: NodeIndex,
data: Slice<'de>,
) -> impl FnOnce(NodeIndex) -> ScalarNode<'de>
{
move |id| Self::new(id, parent, data)
}
pub fn id(&self) -> NodeIndex
{
self.id
}
pub fn parent(&self) -> Option<NodeIndex>
{
self.parent
}
pub fn data<'a>(&self, g: &'a Storage<'de>) -> ScalarDataRef<'a, 'de>
{
let data = &g.node_data()[self.id];
ScalarDataRef::new(data)
}
pub fn data_mut<'a>(&self, g: &'a mut Storage<'de>) -> ScalarDataMut<'a, 'de>
{
let data = &mut g.node_data_mut()[self.id];
ScalarDataMut::new(data)
}
fn with_parent(id: NodeIndex, scalar: Slice<'de>, parent: Option<NodeIndex>) -> Self
{
Self { parent, id, scalar }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(in crate::node) struct ScalarData
{
style: ScalarStyle,
}
impl ScalarData
{
pub const fn new(style: ScalarStyle) -> Self
{
Self { style }
}
pub fn opaque(self) -> NodeSpecific
{
self.into()
}
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub(in crate::node) struct ScalarDataRef<'a, 'de>
{
data: &'a NodeData<'de>,
}
impl<'a, 'de> ScalarDataRef<'a, 'de>
{
fn new(data: &'a NodeData<'de>) -> Self
{
Self { data }
}
pub const fn anchor(&self) -> Option<&Slice<'de>>
{
self.data.anchor.as_ref()
}
pub const fn tag(&self) -> Option<&Tag<'de>>
{
self.data.tag.as_ref()
}
pub const fn context(&self) -> &NodeContext
{
&self.data.context
}
pub const fn mark(&self) -> &NodeMark
{
&self.data.mark
}
pub fn style(&self) -> &ScalarStyle
{
&self.scalar().style
}
fn scalar(&self) -> &ScalarData
{
use NodeSpecific::Scalar;
match self.data.node_specific
{
Scalar(ref s) => s,
_ => unreachable!(),
}
}
}
#[derive(Debug)]
#[repr(transparent)]
pub(in crate::node) struct ScalarDataMut<'a, 'de>
{
data: &'a mut NodeData<'de>,
}
impl<'a, 'de> ScalarDataMut<'a, 'de>
{
fn new(data: &'a mut NodeData<'de>) -> Self
{
let mut this = Self { data };
let _assert = this.scalar();
this
}
pub fn anchor(&mut self) -> Option<&mut Slice<'de>>
{
self.data.anchor.as_mut()
}
pub fn tag(&mut self) -> Option<&mut Tag<'de>>
{
self.data.tag.as_mut()
}
pub fn context(&mut self) -> &mut NodeContext
{
&mut self.data.context
}
pub fn mark(&mut self) -> &mut NodeMark
{
&mut self.data.mark
}
pub fn style(&mut self) -> &mut ScalarStyle
{
&mut self.scalar().style
}
fn scalar(&mut self) -> &mut ScalarData
{
use NodeSpecific::Scalar;
match self.data.node_specific
{
Scalar(ref mut s) => s,
_ => unreachable!(),
}
}
}

View File

@ -0,0 +1,80 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
use crate::node::nodes::{NodeIndex, NodeSpecific};
pub(in crate::node) type Children = Vec<NodeIndex>;
pub(in crate::node) struct SequenceNode
{
parent: Option<NodeIndex>,
id: NodeIndex,
children: Children,
}
impl SequenceNode
{
pub fn root(id: NodeIndex) -> Self
{
Self::with_parent(id, None)
}
pub fn new(id: NodeIndex, parent: NodeIndex) -> Self
{
Self::with_parent(id, Some(parent))
}
pub fn root_with() -> impl FnOnce(NodeIndex) -> SequenceNode
{
move |id| Self::root(id)
}
pub fn new_with(parent: NodeIndex) -> impl FnOnce(NodeIndex) -> SequenceNode
{
move |id| Self::new(id, parent)
}
pub fn id(&self) -> NodeIndex
{
self.id
}
pub fn parent(&self) -> Option<NodeIndex>
{
self.parent
}
pub fn children(&self) -> &Children
{
&self.children
}
pub fn children_mut(&mut self) -> &mut Children
{
&mut self.children
}
fn with_parent(id: NodeIndex, parent: Option<NodeIndex>) -> Self
{
Self {
parent,
id,
children: Default::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(in crate::node) struct SequenceData;
impl SequenceData
{
pub fn opaque(self) -> NodeSpecific
{
self.into()
}
}

View File

@ -0,0 +1,215 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
use crate::node::{
error::{NodeError, NodeResult as Result},
graph::Storage,
nodes::{
alias::AliasNode, mapping::MappingNode, scalar::ScalarNode, sequence::SequenceNode, Node,
NodeData, NodeIndex,
},
visitor::{
transform::{TransformAlias, TransformLeaf, TransformMapping, TransformSequence},
Context, VisitAlias, VisitLeaf, VisitMapping, VisitSequence, Visitor,
},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(in crate::node) struct GraphVisitor;
impl Visitor for GraphVisitor
{
fn visit_leaf<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
mut node: VisitLeaf<'de>,
) -> Result<NodeIndex>
{
let (scalar, data) = TransformLeaf::new(cxt, &mut node).consume()?;
let id = match cxt.current
{
Some(parent) =>
{
let init = ScalarNode::new_with_data(parent, scalar);
graph.insert(Node::scalar(init), data)
},
None =>
{
let init = ScalarNode::root_with_data(scalar);
graph.insert(Node::scalar(init), data)
},
};
update_context_from_node_data(cxt, &*graph, id)?;
connect_node_index(cxt, graph, id)?;
Ok(id)
}
fn visit_alias<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
mut node: VisitAlias<'de>,
) -> Result<NodeIndex>
{
let (alias, data) = TransformAlias::new(&*cxt, &mut node).consume()?;
// Alias nodes *cannot* be root nodes
let parent = cxt.current.ok_or(NodeError::UndefinedAlias)?;
let init = AliasNode::new_with_data(parent, alias);
let id = graph.insert(Node::alias(init), data);
update_context_from_node_data(cxt, &*graph, id)?;
connect_node_index(cxt, graph, id)?;
Ok(id)
}
fn visit_sequence<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
mut node: VisitSequence<'de>,
) -> Result<NodeIndex>
{
let data = TransformSequence::new(&*cxt, &mut node).consume()?;
let id = match cxt.current
{
Some(parent) =>
{
let init = SequenceNode::new_with(parent);
graph.insert(Node::sequence(init), data)
},
None =>
{
let init = SequenceNode::root_with();
graph.insert(Node::sequence(init), data)
},
};
update_context_from_node_data(cxt, &*graph, id)?;
connect_node_index(cxt, graph, id)?;
Ok(id)
}
fn visit_mapping<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
mut node: VisitMapping<'de>,
) -> Result<NodeIndex>
{
let data = TransformMapping::new(&*cxt, &mut node).consume()?;
let id = match cxt.current
{
Some(parent) =>
{
let init = MappingNode::new_with(parent);
graph.insert(Node::mapping(init), data)
},
None =>
{
let init = MappingNode::root_with();
graph.insert(Node::mapping(init), data)
},
};
update_context_from_node_data(cxt, &*graph, id)?;
connect_node_index(cxt, graph, id)?;
Ok(id)
}
}
/// Update the current context with any additional state
/// that should be stored from the given node_id's data.
///
/// ## Panics
///
/// The given node_id should point to a valid live node
/// in the given Graph. It is considered programmer
/// error to not provide such a node_id, and this
/// function may panic.
fn update_context_from_node_data<'de>(
cxt: &mut Context<'de>,
graph: &Storage<'de>,
node_id: NodeIndex,
) -> Result<()>
{
let node_data = graph.node_data().get(node_id);
// It is a logic error to pass a node_id who's data has been
// deleted
debug_assert!(node_data.is_some());
// Add the node's anchor to our context, replacing the
// existing anchor if one exists.
if let Some(anchor) = node_data.and_then(NodeData::anchor)
{
cxt.aliases.insert(anchor.clone(), node_id);
}
Ok(())
}
/// Connect the given node_id into the provided graph,
/// situating it in the current parent node.
///
/// ## Panics
///
/// It is a logic error to call this function if the
/// current parent node is not either a mapping or
/// sequence node, as they are the only kinds of nodes
/// that _can_ have children. Do so will result in a
/// panic, as is considered programmer error.
fn connect_node_index<'de>(
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
node_id: NodeIndex,
) -> Result<()>
{
if let Some(parent) = cxt.current
{
match graph.nodes_mut()[parent]
{
// If we're a child of a mapping node, we need to add ourselves to either the
// key or value position
Node::Map(ref mut map) => match cxt.mapping_last_node.take()
{
// Found a key stored, so we're a value node, insert ourselves
Some(key_id) =>
{
map.children_mut().insert(key_id, Some(node_id));
},
// No key found, so we're a key node then; insert ourselves into the
// map, and prime the context for later
None =>
{
map.children_mut().insert(node_id, None);
cxt.mapping_last_node = Some(node_id);
},
},
// Push the node onto the sequence node's children stack
Node::List(ref mut list) => list.children_mut().push(node_id),
// Leaf and Alias nodes are never parent nodes
Node::Leaf(_) | Node::Alias(_) => unreachable!(),
}
}
Ok(())
}

161
src/node/visitor/mod.rs Normal file
View File

@ -0,0 +1,161 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
use std::collections::HashMap;
use crate::{
event::types::{TagDirectives, VersionDirective, DEFAULT_VERSION},
node::{error::NodeResult as Result, graph::Storage, nodes::NodeIndex},
token::Slice,
};
mod graph_visitor;
mod stream_consumer;
mod transform;
pub(in crate::node) trait Visitor
{
fn visit_leaf<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
node: VisitLeaf<'de>,
) -> Result<NodeIndex>;
fn visit_alias<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
node: VisitAlias<'de>,
) -> Result<NodeIndex>;
fn visit_sequence<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
node: VisitSequence<'de>,
) -> Result<NodeIndex>;
fn visit_mapping<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
node: VisitMapping<'de>,
) -> Result<NodeIndex>;
}
#[derive(Debug, Clone)]
pub(in crate::node) struct Context<'de>
{
current: Option<NodeIndex>,
aliases: HashMap<Slice<'de>, NodeIndex>,
version_directive: VersionDirective,
tag_directives: TagDirectives<'de>,
mapping_last_node: Option<NodeIndex>,
}
impl<'de> Context<'de>
{
pub fn new() -> Self
{
Self {
current: None,
aliases: Default::default(),
version_directive: DEFAULT_VERSION,
tag_directives: Default::default(),
mapping_last_node: None,
}
}
}
#[derive(Debug, Clone)]
pub(in crate::node) struct VisitLeaf<'de>
{
start: usize,
end: usize,
node: ScalarEvent<'de>,
}
impl<'de> VisitLeaf<'de>
{
pub fn from_scalar_event(start: usize, end: usize, s: ScalarEvent<'de>) -> Self
{
Self {
start,
end,
node: s,
}
}
}
#[derive(Debug, Clone)]
pub(in crate::node) struct VisitAlias<'de>
{
start: usize,
end: usize,
alias: Slice<'de>,
}
impl<'de> VisitAlias<'de>
{
pub fn from_alias_event(start: usize, end: usize, a: AliasEvent<'de>) -> Self
{
let alias = a.name;
Self { start, end, alias }
}
}
#[derive(Debug, Clone)]
pub(in crate::node) struct VisitSequence<'de>
{
start: usize,
end: usize,
node: SequenceEvent<'de>,
}
impl<'de> VisitSequence<'de>
{
pub fn from_sequence_event(start: usize, end: usize, s: SequenceEvent<'de>) -> Self
{
Self {
start,
end,
node: s,
}
}
}
#[derive(Debug, Clone)]
pub(in crate::node) struct VisitMapping<'de>
{
start: usize,
end: usize,
node: MappingEvent<'de>,
}
impl<'de> VisitMapping<'de>
{
pub fn from_mapping_event(start: usize, end: usize, m: MappingEvent<'de>) -> Self
{
Self {
start,
end,
node: m,
}
}
}
type ScalarEvent<'a> = crate::event::types::Node<'a, crate::event::types::ScalarLike<'a>>;
type SequenceEvent<'a> = crate::event::types::Node<'a, crate::event::types::Sequence>;
type MappingEvent<'a> = crate::event::types::Node<'a, crate::event::types::Mapping>;
type AliasEvent<'a> = crate::event::types::Alias<'a>;

View File

@ -0,0 +1,301 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
use crate::{
event::{
self,
types::{DocumentStart, Event, EventData},
Events,
},
node::{
error::NodeResult as Result,
graph::Storage,
nodes::NodeIndex,
visitor::{
AliasEvent, Context, MappingEvent, ScalarEvent, SequenceEvent, VisitAlias, VisitLeaf,
VisitMapping, VisitSequence, Visitor,
},
},
reader::Read,
};
pub(in crate::node) struct StreamConsumer<'de, R, V>
{
events: EventIter<'de, R>,
graph: Storage<'de>,
visitor: V,
context: Context<'de>,
context_stack: Vec<SavedContext>,
}
impl<'de, R, V> StreamConsumer<'de, R, V>
where
V: Visitor,
R: Read,
{
pub fn new(events: Events<'de, R>, visitor: V) -> Self
{
Self {
events: EventIter::new(events),
graph: Storage::new(),
visitor,
context: Context::new(),
context_stack: Default::default(),
}
}
pub fn from_src(src: &'de R, visitor: V) -> Self
{
let events = event::from_reader(src);
Self::new(events, visitor)
}
/// Consumes the internal event stream until the next
/// node has been stored, or an error is encountered.
///
/// Returns the id from the node, or None if the event
/// stream is finished.
fn next_node(&mut self) -> Result<Option<NodeIndex>>
{
let mut node_id = None;
while let Some(mut event) = self.events.next().transpose()?
{
let (start, end) = (event.start(), event.end());
let node = match take_event_data(event.data_mut())
{
EventData::StreamStart(_) => self.init_context(),
EventData::DocumentStart(doc) => self.set_doc_context(doc),
EventData::DocumentEnd(_) => self.clear_doc_context(),
EventData::Alias(alias) => self.insert_alias(start, end, alias).map(Some)?,
EventData::Scalar(scalar) => self.insert_scalar(start, end, scalar).map(Some)?,
EventData::MappingStart(mapping) =>
{
self.insert_mapping(start, end, mapping).map(Some)?
},
EventData::SequenceStart(sequence) =>
{
self.insert_sequence(start, end, sequence).map(Some)?
},
EventData::MappingEnd | EventData::SequenceEnd => self.decrement_context_level(),
EventData::StreamEnd => break,
};
if let Some(id) = node
{
node_id = Some(id);
break;
}
}
Ok(node_id)
}
fn init_context(&mut self) -> Option<NodeIndex>
{
None
}
fn set_doc_context(&mut self, doc: DocumentStart<'de>) -> Option<NodeIndex>
{
self.context.version_directive = doc.directives.version;
self.context.tag_directives = doc.directives.tags;
None
}
fn clear_doc_context(&mut self) -> Option<NodeIndex>
{
let aliases = &mut self.context.aliases;
let tags = &mut self.context.tag_directives;
aliases.clear();
aliases.shrink_to_fit();
tags.clear();
tags.shrink_to_fit();
None
}
fn insert_alias(&mut self, start: usize, end: usize, node: AliasEvent<'de>)
-> Result<NodeIndex>
{
let v_alias = VisitAlias::from_alias_event(start, end, node);
let id = self
.visitor
.visit_alias(&mut self.context, &mut self.graph, v_alias)?;
Ok(id)
}
fn insert_scalar(
&mut self,
start: usize,
end: usize,
node: ScalarEvent<'de>,
) -> Result<NodeIndex>
{
let v_leaf = VisitLeaf::from_scalar_event(start, end, node);
let id = self
.visitor
.visit_leaf(&mut self.context, &mut self.graph, v_leaf)?;
Ok(id)
}
fn insert_sequence(
&mut self,
start: usize,
end: usize,
node: SequenceEvent<'de>,
) -> Result<NodeIndex>
{
let v_sequence = VisitSequence::from_sequence_event(start, end, node);
self.increment_context_level();
let id = self
.visitor
.visit_sequence(&mut self.context, &mut self.graph, v_sequence)?;
Ok(id)
}
fn insert_mapping(
&mut self,
start: usize,
end: usize,
node: MappingEvent<'de>,
) -> Result<NodeIndex>
{
let v_mapping = VisitMapping::from_mapping_event(start, end, node);
self.increment_context_level();
let id = self
.visitor
.visit_mapping(&mut self.context, &mut self.graph, v_mapping)?;
Ok(id)
}
fn increment_context_level(&mut self) -> Option<NodeIndex>
{
let save = SavedContext::save(&mut self.context);
self.context_stack.push(save);
None
}
fn decrement_context_level(&mut self) -> Option<NodeIndex>
{
if let Some(saved) = self.context_stack.pop()
{
saved.unsave(&mut self.context)
}
None
}
}
struct SavedContext
{
current: Option<NodeIndex>,
mapping_last_node: Option<NodeIndex>,
}
impl SavedContext
{
fn save(cxt: &mut Context) -> Self
{
let current = cxt.current.take();
let mln = cxt.mapping_last_node.take();
Self::new(current, mln)
}
fn unsave(self, cxt: &mut Context)
{
cxt.current = self.current;
cxt.mapping_last_node = self.mapping_last_node;
}
fn new(current_node: Option<NodeIndex>, mapping_last_node: Option<NodeIndex>) -> Self
{
Self {
current: current_node,
mapping_last_node,
}
}
}
#[derive(Debug)]
struct EventIter<'de, R>
{
inner: Events<'de, R>,
done: bool,
}
impl<'de, R> EventIter<'de, R>
where
R: Read,
{
fn new(events: Events<'de, R>) -> Self
{
Self {
inner: events,
done: false,
}
}
fn into_inner(self) -> Events<'de, R>
{
self.inner
}
}
impl<'de, R> Iterator for EventIter<'de, R>
where
R: Read,
{
type Item = Result<Event<'de>>;
fn next(&mut self) -> Option<Self::Item>
{
if self.done
{
return None;
}
let event = self
.inner
.iter()
.next_event()
.map_err(Into::into)
.transpose();
event.is_none().then(|| self.done = true);
event
}
}
impl<'de, R> std::iter::FusedIterator for EventIter<'de, R> where R: Read {}
fn take_event_data<'de>(event: &mut EventData<'de>) -> EventData<'de>
{
std::mem::replace(event, EventData::StreamEnd)
}

View File

@ -0,0 +1,245 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
//! This module contains structures for transforming various
//! visitable node types into formats that our Graph
//! representation can consume
use std::mem::take;
use crate::{
event::types::Scalar,
node::{
error::{NodeError, NodeResult as Result},
nodes::{
alias::AliasData, mapping::MappingData, scalar::ScalarData, sequence::SequenceData,
NodeContext, NodeData, NodeIndex, Tag,
},
visitor::{Context, VisitAlias, VisitLeaf, VisitMapping, VisitSequence},
},
token::Slice,
};
/// Transforms a visited leaf node into a (scalar, data)
/// tuple, which can mapped into a graph structure
pub(super) struct TransformLeaf<'a, 'b, 'de>
{
cxt: &'a Context<'de>,
node: &'b mut VisitLeaf<'de>,
}
impl<'a, 'b, 'de> TransformLeaf<'a, 'b, 'de>
{
/// Instantiate a new [TransformLeaf] for the given
/// context and node.
pub fn new(cxt: &'a Context<'de>, node: &'b mut VisitLeaf<'de>) -> Self
{
Self { cxt, node }
}
/// Consume the node, returning a (scalar, data) tuple
///
/// This operation is destructive. Running it more than
/// once on a single node may return faulty data or
/// panic.
pub fn consume(mut self) -> Result<(Slice<'de>, NodeData<'de>)>
{
let mut scalar = self.take_scalar()?;
let data = self.take_data(&scalar);
let slice = take(scalar.data_mut());
Ok((slice, data))
}
/// Retrieves the scalar part of the node.
///
/// This function is only safe to call once, future
/// calls will return unspecified results.
fn take_scalar(&mut self) -> Result<Scalar<'de>>
{
take(&mut self.node.node.content)
.evaluate_scalar()
.map_err(Into::into)
}
/// Retrieves the data part of the node.
///
/// This function is only safe to call once, future
/// calls will return unspecified results.
fn take_data(&mut self, scalar: &Scalar<'de>) -> NodeData<'de>
{
let mark = (self.node.start, self.node.end).into();
let ns = ScalarData::new(scalar.style()).into();
let tag = new_tag_from_context(&*self.cxt, take(&mut self.node.node.tag));
let anchor = take(&mut self.node.node.anchor);
let context = new_node_context();
NodeData::new(anchor, tag, context, mark, ns)
}
}
/// Transforms a visited alias node returning an (alias,
/// data) tuple, which can mapped into a graph structure
pub(super) struct TransformAlias<'a, 'b, 'de>
{
cxt: &'a Context<'de>,
node: &'b mut VisitAlias<'de>,
}
impl<'a, 'b, 'de> TransformAlias<'a, 'b, 'de>
{
/// Instantiate a new [TransformAlias] for the given
/// context and node.
pub fn new(cxt: &'a Context<'de>, node: &'b mut VisitAlias<'de>) -> Self
{
Self { cxt, node }
}
/// Consume the node, returning a (alias, data) tuple
///
/// This operation is destructive. Running it more than
/// once on a single node may return faulty data or
/// panic.
pub fn consume(mut self) -> Result<(NodeIndex, NodeData<'de>)>
{
let alias = self.deference_alias()?;
let data = self.take_data();
Ok((alias, data))
}
/// Retrieve the aliased node by name from the current
/// context, returning an error if the lookup failed.
fn deference_alias(&mut self) -> Result<NodeIndex>
{
self.cxt
.aliases
.get(&self.node.alias)
.copied()
.ok_or(NodeError::UndefinedAlias)
}
/// Retrieves the data part of the node.
///
/// This function is only safe to call once, future
/// calls will return unspecified results.
fn take_data(&mut self) -> NodeData<'de>
{
let mark = (self.node.start, self.node.end).into();
let ns = AliasData.into();
let context = new_node_context();
NodeData::new(None, None, context, mark, ns)
}
}
/// Transforms a visited sequence node returning the data
/// which can mapped into a graph structure
pub(super) struct TransformSequence<'a, 'b, 'de>
{
cxt: &'a Context<'de>,
node: &'b mut VisitSequence<'de>,
}
impl<'a, 'b, 'de> TransformSequence<'a, 'b, 'de>
{
/// Instantiate a new [TransformSequence] for the given
/// context and node.
pub fn new(cxt: &'a Context<'de>, node: &'b mut VisitSequence<'de>) -> Self
{
Self { cxt, node }
}
/// Consume the node, returning the data attached
///
/// This operation is destructive. Running it more than
/// once on a single node may return faulty data or
/// panic.
pub fn consume(mut self) -> Result<NodeData<'de>>
{
Ok(self.take_data())
}
/// Retrieves the data part of the node.
///
/// This function is only safe to call once, future
/// calls will return unspecified results.
fn take_data(&mut self) -> NodeData<'de>
{
let mark = (self.node.start, self.node.end).into();
let tag = new_tag_from_context(&*self.cxt, take(&mut self.node.node.tag));
let anchor = take(&mut self.node.node.anchor);
let context = new_node_context();
NodeData::new(anchor, tag, context, mark, SequenceData.into())
}
}
/// Transforms a visited mapping node returning the data
/// which can mapped into a graph structure
pub(super) struct TransformMapping<'a, 'b, 'de>
{
cxt: &'a Context<'de>,
node: &'b mut VisitMapping<'de>,
}
impl<'a, 'b, 'de> TransformMapping<'a, 'b, 'de>
{
/// Instantiate a new [TransformMapping] for the given
/// context and node.
pub fn new(cxt: &'a Context<'de>, node: &'b mut VisitMapping<'de>) -> Self
{
Self { cxt, node }
}
/// Consume the node, returning the data attached
///
/// This operation is destructive. Running it more than
/// once on a single node may return faulty data or
/// panic.
pub fn consume(mut self) -> Result<NodeData<'de>>
{
Ok(self.take_data())
}
/// Retrieves the data part of the node.
///
/// This function is only safe to call once, future
/// calls will return unspecified results.
fn take_data(&mut self) -> NodeData<'de>
{
let mark = (self.node.start, self.node.end).into();
let tag = new_tag_from_context(&*self.cxt, take(&mut self.node.node.tag));
let anchor = take(&mut self.node.node.anchor);
let context = new_node_context();
NodeData::new(anchor, tag, context, mark, MappingData.into())
}
}
/// Generate a [Tag] from the given (handle, suffix) tuple,
/// looking up the prefix from the current context; if the
/// tuple is some.
fn new_tag_from_context<'de>(
cxt: &Context<'de>,
tag: Option<(Slice<'de>, Slice<'de>)>,
) -> Option<Tag<'de>>
{
let tags = &cxt.tag_directives;
let (handle, suffix) = tag?;
let prefix = tags.get(&handle)?.clone();
Tag::new(handle, prefix, suffix).into()
}
// TODO: Actually return the node context once it is present
// in the EventData
/// Placeholder function for retrieving a node's context
fn new_node_context() -> NodeContext
{
NodeContext::Block
}

152
src/value.rs Normal file
View File

@ -0,0 +1,152 @@
#![allow(missing_docs)]
use std::{marker::PhantomData, sync::Arc};
use crate::{error::Result, reader::Read};
pub struct Yaml<Ty = Eager>
{
inner: Option<Arc<Node>>,
_mkr: PhantomData<Ty>,
}
impl Yaml<Eager>
{
pub fn load<R>(src: R) -> Result<Self>
where
R: Read,
{
todo!()
}
/// Fetch a scalar datum from the given .path
///
/// May return an empty scalar (`len==0`,`style=Plain`)
/// if the scalar does not exist
pub fn scalar<P>(&self, path: P) -> Scalar<'_>
where
P: AsPath,
{
todo!()
}
/// Fetch a scalar datum from the given .path
///
/// May return `None` if the scalar does not exist
pub fn get_scalar<P>(&self, path: P) -> Option<Scalar<'_>>
where
P: AsPath,
{
todo!()
}
/// Fetch a scalar datum from the given .path
///
/// May return an error explaining what went wrong
pub fn try_scalar<P>(&self, path: P) -> Result<Scalar<'_>>
where
P: AsPath,
{
todo!()
}
/// Create a new [`Yaml`] view using the node at .path
/// as the new root
///
/// The returned view may be empty if the node does not
/// exist
pub fn node<P>(&self, path: P) -> Yaml
where
P: AsPath,
{
todo!()
}
/*
* use YARY::path as p;
* let yaml = ...;
* let vec = yaml.node(~["name", 5, "name"]);
*
* vec.scalar(1)
*/
/// Create a new [`Yaml`] view using the node at .path
/// as the new root
///
/// May return `None` if the node does not exist
pub fn get_node<P>(&self, path: P) -> Option<Yaml>
where
P: AsPath,
{
todo!()
}
/// Create a new [`Yaml`] view using the node at .path
/// as the new root
///
/// May return an error explaining what went wrong
pub fn try_node<P>(&self, path: P) -> Result<Yaml>
where
P: AsPath,
{
todo!()
}
}
impl Yaml<Lazy>
{
pub fn lazy<R>(src: R) -> Self
where
R: Read,
{
todo!()
}
pub fn load(self) -> Result<Yaml>
{
todo!()
}
pub fn node_at<P>(&mut self, path: P) -> Result<NodeRef<'_>>
where
P: AsPath,
{
todo!()
}
pub fn touch<P>(&mut self, path: P) -> Result<bool>
where
P: AsPath,
{
todo!()
}
pub fn freeze(&mut self) -> Yaml
{
todo!()
}
pub fn freeze_at<P>(&mut self, path: P) -> Result<Yaml>
where
P: AsPath,
{
todo!()
}
}
pub struct Scalar<'a>
{
s: &'a str,
}
pub struct NodeRef<'a>
{
_mkr: &'a str,
}
pub trait AsPath {}
struct Node;
pub struct Eager;
pub struct Lazy;