Compare commits
17 Commits
master
...
feature/ya
Author | SHA1 | Date |
---|---|---|
Paul Stemmet | 86a7364542 | |
Paul Stemmet | f9df2bee09 | |
Paul Stemmet | 88a291e145 | |
Paul Stemmet | 4d10d0e4b3 | |
Paul Stemmet | da344ad3e8 | |
Paul Stemmet | 5df8cf5cef | |
Paul Stemmet | 50be670043 | |
Paul Stemmet | edea9a6c4a | |
Paul Stemmet | ebe7890235 | |
Paul Stemmet | 12271d1c88 | |
Paul Stemmet | f82dabae9d | |
Paul Stemmet | 5581c28129 | |
Paul Stemmet | cfb7c7bdbc | |
Paul Stemmet | 9b3caee7e4 | |
Paul Stemmet | 28131d9ad4 | |
Paul Stemmet | 31330b7734 | |
Paul Stemmet | a4ce525c15 |
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -23,6 +23,7 @@ test_buffer_small = ["test_buffer"]
|
|||
[dependencies]
|
||||
atoi = "0.4"
|
||||
bitflags = "1"
|
||||
slotmap = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1"
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
```
|
4
justfile
4
justfile
|
@ -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} \
|
||||
|
|
10
src/error.rs
10
src/error.rs
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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(())
|
||||
}
|
|
@ -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>;
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -139,8 +139,8 @@ impl Scanner
|
|||
self.expire_stale_saved_key()?;
|
||||
|
||||
// Handle indentation unrolling
|
||||
self.unroll_indent(tokens, self.stats.column)?;
|
||||
self.pop_zero_indent_sequence(*base, tokens)?;
|
||||
self.unroll_indent(tokens, self.stats.column)?;
|
||||
|
||||
// Is it the end of a stream?
|
||||
if base.is_empty() || self.state == StreamState::Done
|
||||
|
|
|
@ -185,137 +185,3 @@ fn plain()
|
|||
@ None
|
||||
);
|
||||
}
|
||||
|
||||
/// Check we handle zero indented indents that could be
|
||||
/// incorrectly coalesced with normal indentation levels
|
||||
#[test]
|
||||
fn zero_indent_multilevel_coalesce()
|
||||
{
|
||||
let data = r#"
|
||||
Objs:
|
||||
- UnitConfigName: Enemy_Lizalfos_Dark
|
||||
HashId: 0x43ef248b
|
||||
- UnitConfigName: Item_Fish_21
|
||||
HashId: 0x453cc5d0 # Last Ok
|
||||
Rails: # Error at the beginning of this line
|
||||
- Blah: SomeRail
|
||||
HashId: 0x24f8f8f8
|
||||
"#;
|
||||
|
||||
let mut s = ScanIter::new(data);
|
||||
|
||||
tokens!(s =>
|
||||
| StreamStart(StreamEncoding::UTF8),
|
||||
| BlockMappingStart,
|
||||
| Key,
|
||||
| Scalar(cow!("Objs"), Plain),
|
||||
| Value,
|
||||
| BlockSequenceStart,
|
||||
| BlockEntry,
|
||||
| BlockMappingStart,
|
||||
| Key,
|
||||
| Scalar(cow!("UnitConfigName"), Plain),
|
||||
| Value,
|
||||
| Scalar(cow!("Enemy_Lizalfos_Dark"), Plain),
|
||||
| Key,
|
||||
| Scalar(cow!("HashId"), Plain),
|
||||
| Value,
|
||||
| Scalar(cow!("0x43ef248b"), Plain),
|
||||
| BlockEnd,
|
||||
| BlockEntry,
|
||||
| BlockMappingStart,
|
||||
| Key,
|
||||
| Scalar(cow!("UnitConfigName"), Plain),
|
||||
| Value,
|
||||
| Scalar(cow!("Item_Fish_21"), Plain),
|
||||
| Key,
|
||||
| Scalar(cow!("HashId"), Plain),
|
||||
| Value,
|
||||
| Scalar(cow!("0x453cc5d0"), Plain),
|
||||
| BlockEnd => "expected END of 'UnitConfigName: Item_Fish_21' map",
|
||||
| BlockEnd => "expected END of 'Objs' zero indented sequence",
|
||||
| Key,
|
||||
| Scalar(cow!("Rails"), Plain),
|
||||
| Value,
|
||||
| BlockSequenceStart,
|
||||
| BlockEntry,
|
||||
| BlockMappingStart,
|
||||
| Key,
|
||||
| Scalar(cow!("Blah"), Plain),
|
||||
| Value,
|
||||
| Scalar(cow!("SomeRail"), Plain),
|
||||
| Key,
|
||||
| Scalar(cow!("HashId"), Plain),
|
||||
| Value,
|
||||
| Scalar(cow!("0x24f8f8f8"), Plain),
|
||||
| BlockEnd,
|
||||
| BlockEnd,
|
||||
| BlockEnd,
|
||||
| StreamEnd,
|
||||
@ None
|
||||
);
|
||||
}
|
||||
|
||||
/// This test ensures that we catch zero indents on both
|
||||
/// sides of a normal indentation decrease
|
||||
#[test]
|
||||
fn zero_indent_multilevel()
|
||||
{
|
||||
let data = r#"
|
||||
Z1:
|
||||
- Z2:
|
||||
- N1:
|
||||
- N2:
|
||||
- Z3:
|
||||
- end
|
||||
"#;
|
||||
|
||||
let mut s = ScanIter::new(data);
|
||||
|
||||
tokens!(s =>
|
||||
| StreamStart(StreamEncoding::UTF8),
|
||||
| BlockMappingStart => "expected START of Z1 mapping",
|
||||
| Key,
|
||||
| Scalar(cow!("Z1"), Plain),
|
||||
| Value,
|
||||
| BlockSequenceStart => "expected START of zero indent sequence 1",
|
||||
| BlockEntry,
|
||||
| BlockMappingStart => "expected START of Z2 mapping",
|
||||
| Key,
|
||||
| Scalar(cow!("Z2"), Plain),
|
||||
| Value,
|
||||
| BlockSequenceStart => "expected START of zero indent sequence 2",
|
||||
| BlockEntry,
|
||||
| BlockMappingStart => "expected START of N1 mapping",
|
||||
| Key,
|
||||
| Scalar(cow!("N1"), Plain),
|
||||
| Value,
|
||||
| BlockSequenceStart => "expected START of normal indent sequence 1",
|
||||
| BlockEntry,
|
||||
| BlockMappingStart => "expected START of N2 mapping",
|
||||
| Key,
|
||||
| Scalar(cow!("N2"), Plain),
|
||||
| Value,
|
||||
| BlockSequenceStart => "expected START of normal indent sequence 2",
|
||||
| BlockEntry,
|
||||
| BlockMappingStart => "expected START of Z3 mapping",
|
||||
| Key,
|
||||
| Scalar(cow!("Z3"), Plain),
|
||||
| Value,
|
||||
| BlockSequenceStart => "expected START of zero indent sequence 3",
|
||||
| BlockEntry,
|
||||
| Scalar(cow!("end"), Plain),
|
||||
| BlockEnd => "expected END of zero indent sequence 3",
|
||||
| BlockEnd => "expected END of Z3 mapping",
|
||||
| BlockEnd => "expected END of normal indent sequence 2",
|
||||
| BlockEnd => "expected END of N2 mapping",
|
||||
| BlockEnd => "expected END of normal indent sequence 1",
|
||||
| BlockEnd => "expected END of N1 mapping",
|
||||
| BlockEnd => "expected END of zero indent sequence 2",
|
||||
| BlockEnd => "expected END of Z2 mapping",
|
||||
| BlockEnd => "expected END of zero indent sequence 1",
|
||||
| BlockEnd => "expected END of Z1 mapping",
|
||||
| StreamEnd,
|
||||
@ None
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
Loading…
Reference in New Issue