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",
|
"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]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.89"
|
version = "1.0.89"
|
||||||
|
@ -125,6 +134,12 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
@ -156,4 +171,5 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
|
"slotmap",
|
||||||
]
|
]
|
||||||
|
|
|
@ -23,6 +23,7 @@ test_buffer_small = ["test_buffer"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
atoi = "0.4"
|
atoi = "0.4"
|
||||||
bitflags = "1"
|
bitflags = "1"
|
||||||
|
slotmap = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1"
|
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 ~~~
|
# ~~~ Private recipes ~~~
|
||||||
|
|
||||||
# Run cargo test with the given suite, profile, features and selector (if any)
|
# 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" \
|
@$Say "Running tests" \
|
||||||
"${suite:+{{C_GREEN}}suite:{{C_YELLOW}}$suite{{C_RESET}}}" \
|
"${suite:+{{C_GREEN}}suite:{{C_YELLOW}}$suite{{C_RESET}}}" \
|
||||||
"${features:+{{C_GREEN}}features:{{C_YELLOW}}$features{{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
|
| xargs
|
||||||
@$Cargo test \
|
@$Cargo test \
|
||||||
${suite:+--$suite} \
|
${suite:+--$suite} \
|
||||||
|
|
10
src/error.rs
10
src/error.rs
|
@ -465,6 +465,12 @@ pub(crate) mod internal
|
||||||
/// # ^ MissingFlowMappingEntryOrEnd
|
/// # ^ MissingFlowMappingEntryOrEnd
|
||||||
/// ```
|
/// ```
|
||||||
MissingFlowMappingEntryOrEnd,
|
MissingFlowMappingEntryOrEnd,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ==== Node Errors ====
|
||||||
|
*/
|
||||||
|
/// A YAML alias was used but not defined
|
||||||
|
UndefinedAlias,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Heavy and/or external errors that can occur during
|
/// Heavy and/or external errors that can occur during
|
||||||
|
@ -643,7 +649,8 @@ pub(crate) mod internal
|
||||||
| MissingNode
|
| MissingNode
|
||||||
| MissingKey
|
| MissingKey
|
||||||
| MissingFlowSequenceEntryOrEnd
|
| MissingFlowSequenceEntryOrEnd
|
||||||
| MissingFlowMappingEntryOrEnd => Category::Syntax,
|
| MissingFlowMappingEntryOrEnd
|
||||||
|
| UndefinedAlias => Category::Syntax,
|
||||||
|
|
||||||
IntOverflow | CorruptStream => Category::Data,
|
IntOverflow | CorruptStream => Category::Data,
|
||||||
|
|
||||||
|
@ -713,6 +720,7 @@ pub(crate) mod internal
|
||||||
{
|
{
|
||||||
f.write_str("missing flow mapping delimiter ',' or '}'")
|
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
|
/// 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
|
self.inner
|
||||||
.parser
|
.parser
|
||||||
|
@ -357,7 +357,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process the next event
|
/// 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
|
self.inner
|
||||||
.parser
|
.parser
|
||||||
|
|
|
@ -24,7 +24,9 @@ pub use error::Error;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
pub mod reader;
|
pub mod reader;
|
||||||
|
pub mod value;
|
||||||
|
|
||||||
|
mod node;
|
||||||
mod queue;
|
mod queue;
|
||||||
mod scanner;
|
mod scanner;
|
||||||
mod token;
|
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
|
||||||
|
}
|
|
@ -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