use std::borrow::Cow;
use oneyaml_core::{Diagnostic, Path, Span};
use oneyaml_syntax::tree::{Node as TreeNode, SyntaxKind};
use super::key::{self, AsKey, KeyArg};
use super::lookup::KeyKind;
use super::path_arg::{self, IntoPath};
use super::{Document, EditError, NodeId};
use crate::construct::scalar::{is_merge_key, resolve, scalar_value};
use crate::construct::tree::yaml11_of;
use crate::error::Error;
use crate::resolve::{Resolved, Resolver};
use crate::value::Value;
pub(super) fn presented(n: TreeNode<'_>) -> TreeNode<'_> {
if !n.tree().has_errors() {
return n;
}
if n.kind() == SyntaxKind::Scalar && n.span().is_empty() {
if let Some(e) = n.prev_sibling().filter(|p| p.kind() == SyntaxKind::Error) {
return e;
}
}
n
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum NodeKind {
Mapping,
Sequence,
Scalar,
Alias,
Error,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ScalarStyle {
Plain,
SingleQuoted,
DoubleQuoted,
Literal,
Folded,
}
#[derive(Clone, Copy)]
pub struct NodeRef<'d> {
doc: &'d Document,
node: TreeNode<'d>,
}
impl core::fmt::Debug for NodeRef<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let s = self.span();
write!(f, "NodeRef({:?}@{}..{})", self.kind(), s.start, s.end)
}
}
impl PartialEq for NodeRef<'_> {
fn eq(&self, other: &Self) -> bool {
core::ptr::eq(self.doc, other.doc) && self.node == other.node
}
}
impl Eq for NodeRef<'_> {}
impl<'d> NodeRef<'d> {
pub(super) fn new(doc: &'d Document, node: TreeNode<'d>) -> Self {
Self { doc, node }
}
pub(super) fn tree_node(self) -> TreeNode<'d> {
self.node
}
pub(super) fn document(self) -> &'d Document {
self.doc
}
fn at(self, node: TreeNode<'d>) -> Self {
Self::new(self.doc, node)
}
pub(super) fn resolver(self) -> Resolver {
let yaml11 = self
.node
.ancestors()
.find(|a| a.kind() == SyntaxKind::Document)
.is_some_and(yaml11_of);
Resolver::for_document(self.doc.settings(), yaml11)
}
pub(super) fn is_merge_key(self) -> Result<bool, Error> {
let r = self.resolver();
if !r.merge_keys() {
return Ok(false);
}
self.as_scalar().map_or(Ok(false), |s| s.is_merge_key(&r))
}
pub(super) fn is_merge_source(self) -> Result<bool, Error> {
if !matches!(
self.node.kind(),
SyntaxKind::BlockMapping | SyntaxKind::FlowMapping | SyntaxKind::FlowPair
) {
return Ok(false);
}
let tag = self.doc.shared.tags.try_tag(self.node)?;
Ok(matches!(
self.resolver()
.resolve_collection(tag.input(), crate::resolve::CollectionKind::Mapping),
Ok(crate::resolve::ResolvedCollection::Plain)
))
}
pub fn deserialize<T: serde::de::DeserializeOwned>(self) -> Result<T, Error> {
let doc = self.doc;
if let Some(e) = doc.shared.pre_error(doc.index) {
return Err(e);
}
let tree = self.node.tree();
let document = self
.node
.ancestors()
.find(|a| a.kind() == SyntaxKind::Document);
let yaml11 = document.is_some_and(yaml11_of);
let node = self.node;
let before = move || document.map_or(0, |d| doc.nodes_before(d, node));
let source = || {
crate::construct::tree::NodeSource::new(
tree,
node,
Box::new(before),
yaml11,
self.outside_anchors(&before),
&doc.shared.tags,
)
};
let lines = Some(&doc.shared.lines);
crate::de::read_discarding::<_, T>(source, || doc.shared.text(), doc.settings(), lines)
}
fn outside_anchors(self, before: &dyn Fn() -> usize) -> Result<Vec<TreeNode<'d>>, Error> {
use std::collections::HashSet;
use crate::construct::tree::is_node_event;
let document = self
.node
.ancestors()
.find(|a| a.kind() == SyntaxKind::Document);
let root = self.node;
let root_at = root.preorder_index();
let tree = root.tree();
let anchors = self.doc.anchors();
let doc_at = document.map(TreeNode::preorder_index);
let target_in = |n: TreeNode<'d>| -> Option<TreeNode<'d>> {
let name = n.alias_name()?;
let id = anchors.nearest_before(tree, name, doc_at?, n.preorder_index())?;
tree.get(id).ok()
};
let limits = self.doc.settings().get_limits();
let mut own = 0usize;
let mut reached = 0usize;
let mut prefix: Option<usize> = None;
let flat = limits.get_alias_budget(0) == limits.get_alias_budget(usize::MAX);
let mut roots: Vec<TreeNode<'d>> = Vec::new();
let mut scanned: HashSet<usize> = HashSet::new();
let mut met: HashSet<usize> = HashSet::new();
let mut nested: HashSet<usize> = HashSet::new();
let mut queue: Vec<(TreeNode<'d>, bool)> = vec![(root, true)];
while let Some((sub, is_root)) = queue.pop() {
let mut stack = vec![sub];
while let Some(n) = stack.pop() {
let at = n.preorder_index();
if n != sub && scanned.contains(&at) {
nested.insert(at);
continue;
}
if is_node_event(n.kind()) {
if is_root {
own = own.saturating_add(1);
} else {
reached = reached.saturating_add(1);
let over =
|own: usize| limits.get_alias_budget(own).filter(|&b| reached > b);
if over(own).is_some() {
let upto = if flat {
own
} else {
own.saturating_add(*prefix.get_or_insert_with(before))
};
if let Some(budget) = over(upto) {
return Err(crate::construct::expand::alias_budget_exceeded(
budget,
upto,
Some(sub.span()),
));
}
}
if n.anchor().is_some() {
met.insert(at);
}
}
}
if n.kind() == SyntaxKind::Alias {
if let Some(t) = target_in(n) {
let t_at = t.preorder_index();
let known = scanned.contains(&t_at) || met.contains(&t_at);
if !known && t_at < root_at {
scanned.insert(t_at);
roots.push(t);
queue.push((t, false));
}
}
}
let mut child = n.first_child();
while let Some(c) = child {
stack.push(c);
child = c.next_sibling();
}
}
}
roots.retain(|r| !nested.contains(&r.preorder_index()));
roots.sort_by_key(|r| r.preorder_index());
Ok(roots)
}
#[must_use]
pub fn id(self) -> NodeId {
NodeId(self.node.id())
}
#[must_use]
pub fn kind(self) -> NodeKind {
match self.node.kind() {
SyntaxKind::BlockMapping | SyntaxKind::FlowMapping | SyntaxKind::FlowPair => {
NodeKind::Mapping
}
SyntaxKind::BlockSequence | SyntaxKind::FlowSequence => NodeKind::Sequence,
SyntaxKind::Scalar => NodeKind::Scalar,
SyntaxKind::Alias => NodeKind::Alias,
_ => NodeKind::Error,
}
}
#[must_use]
pub fn span(self) -> Span {
self.node.span()
}
#[must_use]
pub fn text(self) -> Cow<'d, str> {
self.node.text()
}
#[must_use]
pub fn anchor(self) -> Option<&'d str> {
self.node.anchor().map(|a| a.name)
}
pub fn tag(self) -> Result<Option<crate::Tag>, Error> {
self.doc.shared.tags.value_tag(self.node)
}
#[must_use]
pub fn alias_name(self) -> Option<&'d str> {
self.node.alias_name()
}
#[must_use]
pub fn alias_target(self) -> Option<NodeRef<'d>> {
let name = self.node.alias_name()?;
let doc = self
.node
.ancestors()
.find(|a| a.kind() == SyntaxKind::Document)?;
let tree = self.node.tree();
let id = self.doc.anchors().nearest_before(
tree,
name,
doc.preorder_index(),
self.node.preorder_index(),
)?;
tree.get(id).ok().map(|n| self.at(n))
}
#[must_use]
pub fn resolved(self) -> NodeRef<'d> {
self.alias_target().unwrap_or(self)
}
#[must_use]
pub fn diagnostic(self) -> Option<Cow<'d, Diagnostic>> {
let d = self.node.diagnostic()?;
if !oneyaml_syntax::tree::SyntaxTree::is_skeleton(&d) {
return Some(d);
}
let limit = self.doc.settings().get_limits().get_max_diagnostics();
Some(Cow::Owned(crate::diag_cap::filled(d.into_owned(), limit)))
}
#[must_use]
pub fn as_mapping(self) -> Option<MappingRef<'d>> {
let n = self.resolved();
(n.kind() == NodeKind::Mapping).then_some(MappingRef(n))
}
#[must_use]
pub fn as_sequence(self) -> Option<SequenceRef<'d>> {
let n = self.resolved();
(n.kind() == NodeKind::Sequence).then_some(SequenceRef(n))
}
#[must_use]
pub fn as_scalar(self) -> Option<ScalarRef<'d>> {
let n = self.resolved();
(n.kind() == NodeKind::Scalar).then_some(ScalarRef(n))
}
fn scalar_meaning(self) -> Option<Value> {
self.typed_scalar()?.resolved().ok()
}
fn typed_scalar(self) -> Option<ScalarRef<'d>> {
let s = self.as_scalar()?;
let holds_error = s.0.node.children().any(|c| c.kind() == SyntaxKind::Error);
(!holds_error).then_some(s)
}
#[must_use]
pub fn as_str(self) -> Option<Cow<'d, str>> {
self.typed_scalar()?.as_str()
}
#[must_use]
pub fn as_bool(self) -> Option<bool> {
self.scalar_meaning()?.as_bool()
}
#[must_use]
pub fn as_i64(self) -> Option<i64> {
self.scalar_meaning()?.as_i64()
}
#[must_use]
pub fn as_u64(self) -> Option<u64> {
self.scalar_meaning()?.as_u64()
}
#[must_use]
pub fn as_f64(self) -> Option<f64> {
self.scalar_meaning()?.as_f64()
}
#[must_use]
pub fn is_null(self) -> bool {
self.scalar_meaning().is_some_and(|v| v.is_null())
}
#[must_use]
pub fn get<K: AsKey>(self, key: K) -> Option<NodeRef<'d>> {
self.as_mapping()?.get(key)
}
#[must_use]
pub fn get_index(self, index: usize) -> Option<NodeRef<'d>> {
self.as_sequence()?.get(index)
}
#[must_use]
pub fn get_path<P: IntoPath>(self, path: P) -> Option<NodeRef<'d>> {
let path = path_arg::read(&path)?;
self.walk(&path).ok()
}
pub(super) fn walk(self, path: &Path) -> Result<NodeRef<'d>, EditError> {
let mut at = Path::new();
let mut node = self;
for segment in path.segments() {
if node.resolved().kind() == NodeKind::Error {
return Err(EditError::ErrorNode { at });
}
node = match segment {
oneyaml_core::PathSegment::Key(k) => {
let Some(m) = node.as_mapping() else {
return Err(EditError::NotAMapping { at });
};
at.push_key(k.clone());
m.get(k)
.ok_or_else(|| EditError::NotFound { at: at.clone() })?
}
oneyaml_core::PathSegment::Index(i) => {
let Some(s) = node.as_sequence() else {
return Err(EditError::NotASequence { at });
};
let Some(item) = s.get(*i) else {
let len = s.len();
return Err(EditError::IndexOutOfBounds { at, index: *i, len });
};
at.push_index(*i);
item
}
_ => return Err(EditError::NotFound { at }),
};
}
Ok(node)
}
fn items(self) -> impl Iterator<Item = NodeRef<'d>> + 'd {
let doc = self.doc;
self.node
.children()
.filter(|c| c.kind().is_yaml_node())
.map(move |c| NodeRef::new(doc, presented(c)))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MappingRef<'d>(NodeRef<'d>);
impl<'d> MappingRef<'d> {
#[must_use]
pub fn node(self) -> NodeRef<'d> {
self.0
}
pub fn iter(self) -> impl Iterator<Item = (NodeRef<'d>, NodeRef<'d>)> + 'd {
let mut items = self.0.items();
core::iter::from_fn(move || Some((items.next()?, items.next()?)))
}
#[must_use]
pub fn len(self) -> usize {
let indexed = self
.0
.doc
.with_lookup(self.0.node, false, |ix| Some(ix.len()));
indexed.unwrap_or_else(|| self.0.items().count() / 2)
}
#[must_use]
pub fn is_empty(self) -> bool {
self.0.items().next().is_none()
}
pub(super) fn entry(self, i: usize) -> Option<(NodeRef<'d>, NodeRef<'d>)> {
let (doc, tree) = (self.0.doc, self.0.node.tree());
let indexed = doc.with_lookup(self.0.node, false, |ix| {
if i >= ix.len() {
return Some(None);
}
let k = i.checked_mul(2)?;
let key = ix.item(k)?.node(tree)?;
let value = ix.item(k.checked_add(1)?)?.node(tree)?;
Some(Some((
NodeRef::new(doc, presented(key)),
NodeRef::new(doc, presented(value)),
)))
});
indexed.unwrap_or_else(|| self.iter().nth(i))
}
fn own_key(self, r: &Resolver, q: KeyQuery<'_>, linear: bool) -> Option<NodeRef<'d>> {
let (doc, tree) = (self.0.doc, self.0.node.tree());
let indexed = (!linear)
.then(|| {
doc.with_lookup(self.0.node, false, |ix| {
let digest = match q {
KeyQuery::Str(k) => ix.digest(&Value::String(k.to_owned())),
KeyQuery::Value(v) => ix.digest(v),
};
let mut best: Option<(usize, TreeNode<'d>)> = None;
for id in ix.bucket_rev(digest) {
let n = id.node(tree)?;
if q.matches(NodeRef::new(doc, n), r) {
best = Some((n.preorder_index(), n));
break;
}
}
for id in ix.aliases_rev() {
let n = id.node(tree)?;
if q.matches(NodeRef::new(doc, n), r) {
let at = n.preorder_index();
if best.is_none_or(|(b, _)| at > b) {
best = Some((at, n));
}
break;
}
}
Some(best.map(|(_, n)| NodeRef::new(doc, n)))
})
})
.flatten();
indexed.unwrap_or_else(|| {
let mut found = None;
for (k, _) in self.iter() {
if q.matches(k, r) {
found = Some(k);
}
}
found
})
}
fn last_merge(self, r: &Resolver, linear: bool) -> Option<NodeRef<'d>> {
if !r.merge_keys() {
return None;
}
let (doc, tree) = (self.0.doc, self.0.node.tree());
let is_merge =
|k: NodeRef<'_>| k.as_scalar().is_some_and(|s| lookup_hit(s.is_merge_key(r)));
let indexed = (!linear)
.then(|| {
doc.with_lookup(self.0.node, false, |ix| {
let mut best: Option<(usize, TreeNode<'d>)> = None;
for list in ix.merge_lists() {
for id in ix.rev(list) {
let n = id.node(tree)?;
if is_merge(NodeRef::new(doc, n)) {
let at = n.preorder_index();
if best.is_none_or(|(b, _)| at > b) {
best = Some((at, n));
}
break;
}
}
}
Some(best.map(|(_, n)| NodeRef::new(doc, n)))
})
})
.flatten();
indexed.unwrap_or_else(|| {
let mut found = None;
for (k, _) in self.iter() {
if is_merge(k) {
found = Some(k);
}
}
found
})
}
pub(super) fn has_key_value(self, key: &Value) -> bool {
let r = self.0.resolver();
self.own_key(&r, KeyQuery::Value(key), false).is_some()
}
pub(super) fn has_merge_key(self) -> Result<bool, Error> {
self.has_merge_key_in(false)
}
fn has_merge_key_in(self, linear: bool) -> Result<bool, Error> {
let (doc, tree) = (self.0.doc, self.0.node.tree());
let indexed = (!linear)
.then(|| {
doc.with_lookup(self.0.node, false, |ix| {
if ix.has_merges() {
return Some(Ok(true));
}
for id in ix.aliases_rev() {
match NodeRef::new(doc, id.node(tree)?).is_merge_key() {
Ok(false) => {}
found => return Some(found),
}
}
Some(Ok(false))
})
})
.flatten();
if let Some(found) = indexed {
return found;
}
for (k, _) in self.iter() {
if k.is_merge_key()? {
return Ok(true);
}
}
Ok(false)
}
pub(super) fn own_value(self, key: &str) -> Option<NodeRef<'d>> {
self.own_value_of(KeyQuery::Str(key))
}
pub(super) fn own_value_of(self, q: KeyQuery<'_>) -> Option<NodeRef<'d>> {
let r = self.0.resolver();
value_after(self.own_key(&r, q, false)?)
}
#[must_use]
pub fn get<K: AsKey>(self, key: K) -> Option<NodeRef<'d>> {
let k = key::arg(&key);
self.get_in(KeyQuery::of(&k), false)
}
fn get_in(self, key: KeyQuery<'_>, linear: bool) -> Option<NodeRef<'d>> {
let resolver = self.0.resolver();
let mut stack = vec![self];
let mut seen = std::collections::HashSet::new();
while let Some(m) = stack.pop() {
if !seen.insert(m.0.node.id()) {
continue;
}
let found = m.own_key(&resolver, key, linear).and_then(value_after);
if found.is_some() {
return found;
}
if let Some(v) = m.last_merge(&resolver, linear).and_then(value_after) {
match v.as_sequence() {
Some(seq) => {
let items: Vec<_> = seq.iter().filter_map(NodeRef::as_mapping).collect();
stack.extend(items.into_iter().rev());
}
None => stack.extend(v.as_mapping()),
}
}
}
None
}
}
#[derive(Clone, Copy)]
pub(super) enum KeyQuery<'a> {
Str(&'a str),
Value(&'a Value),
}
impl<'a> KeyQuery<'a> {
pub(super) fn of(k: &'a KeyArg<'_>) -> Self {
match k {
KeyArg::Str(s) => KeyQuery::Str(s),
KeyArg::Value(v) => KeyQuery::Value(v.as_ref()),
}
}
}
impl KeyQuery<'_> {
fn matches(self, k: NodeRef<'_>, r: &Resolver) -> bool {
k.as_scalar().is_some_and(|s| {
!(r.merge_keys() && lookup_hit(s.is_merge_key(r)))
&& match self {
KeyQuery::Str(key) => s.is_string(r, key),
KeyQuery::Value(Value::String(key)) => s.is_string(r, key),
KeyQuery::Value(v) => s.resolved_with(r).ok().as_ref() == Some(v),
}
})
}
}
fn lookup_hit(r: Result<bool, Error>) -> bool {
r.unwrap_or(false)
}
fn value_after(k: NodeRef<'_>) -> Option<NodeRef<'_>> {
let mut at = k.node.next_sibling();
while let Some(x) = at {
if x.kind().is_yaml_node() {
return Some(NodeRef::new(k.doc, presented(x)));
}
at = x.next_sibling();
}
None
}
pub(super) fn key_kind(k: NodeRef<'_>, r: &Resolver) -> KeyKind {
if k.node.kind() == SyntaxKind::Alias {
return KeyKind::Alias;
}
let Some(s) = k.as_scalar() else {
return KeyKind::Never;
};
match s.is_merge_key(r) {
Ok(true) if r.merge_keys() => return KeyKind::Merge,
Ok(_) => {}
Err(_) => return KeyKind::Never,
}
s.resolved_with(r).map_or(KeyKind::Never, KeyKind::Value)
}
#[cfg(feature = "__internal-checks")]
pub(super) fn check_against_linear(n: NodeRef<'_>) -> Result<(), String> {
match n.kind() {
NodeKind::Mapping => {
let m = MappingRef(n);
let linear: Vec<(NodeRef<'_>, NodeRef<'_>)> = m.iter().collect();
if m.len() != linear.len() {
return Err(format!("len {} vs {}", m.len(), linear.len()));
}
for (i, e) in linear.iter().enumerate() {
if m.entry(i) != Some(*e) {
return Err(format!("entry {i}: {:?} vs {e:?}", m.entry(i)));
}
}
if m.entry(linear.len()).is_some() {
return Err("an entry past the end".to_owned());
}
let r = n.resolver();
let mut strings: Vec<String> = vec!["<<".into(), "".into(), "missing key".into()];
let mut values = vec![Value::Null, Value::from(1)];
for (k, _) in &linear {
if let Some(s) = k.as_scalar() {
strings.push(s.value().into_owned());
values.extend(s.resolved_with(&r).ok());
}
}
for q in &strings {
let (a, b) = (
m.own_key(&r, KeyQuery::Str(q), false),
m.own_key(&r, KeyQuery::Str(q), true),
);
if a != b {
return Err(format!("own key {q:?}: {a:?} vs {b:?}"));
}
let (a, b) = (
m.get_in(KeyQuery::Str(q), false),
m.get_in(KeyQuery::Str(q), true),
);
if a != b {
return Err(format!("get {q:?}: {a:?} vs {b:?}"));
}
}
for v in &values {
let (a, b) = (
m.own_key(&r, KeyQuery::Value(v), false),
m.own_key(&r, KeyQuery::Value(v), true),
);
if a != b {
return Err(format!("key equal to {v:?}: {a:?} vs {b:?}"));
}
}
let (a, b) = (m.last_merge(&r, false), m.last_merge(&r, true));
if a != b {
return Err(format!("last merge key: {a:?} vs {b:?}"));
}
let (a, b) = (
m.has_merge_key_in(false).map_err(|e| e.code()),
m.has_merge_key_in(true).map_err(|e| e.code()),
);
if a != b {
return Err(format!("has a merge key: {a:?} vs {b:?}"));
}
Ok(())
}
NodeKind::Sequence => {
let s = SequenceRef(n);
let linear: Vec<NodeRef<'_>> = s.iter().collect();
if s.len() != linear.len() {
return Err(format!("len {} vs {}", s.len(), linear.len()));
}
for (i, x) in linear.iter().enumerate() {
if s.get(i) != Some(*x) {
return Err(format!("item {i}: {:?} vs {x:?}", s.get(i)));
}
}
if s.get(linear.len()).is_some() {
return Err("an item past the end".to_owned());
}
Ok(())
}
_ => Ok(()),
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SequenceRef<'d>(NodeRef<'d>);
impl<'d> SequenceRef<'d> {
#[must_use]
pub fn node(self) -> NodeRef<'d> {
self.0
}
pub fn iter(self) -> impl Iterator<Item = NodeRef<'d>> + 'd {
self.0.items()
}
#[must_use]
pub fn len(self) -> usize {
let indexed = self
.0
.doc
.with_lookup(self.0.node, false, |ix| Some(ix.len()));
indexed.unwrap_or_else(|| self.0.items().count())
}
#[must_use]
pub fn is_empty(self) -> bool {
self.0.items().next().is_none()
}
#[must_use]
pub fn get(self, index: usize) -> Option<NodeRef<'d>> {
let (doc, tree) = (self.0.doc, self.0.node.tree());
let indexed = doc.with_lookup(self.0.node, false, |ix| {
if index >= ix.len() {
return Some(None);
}
let n = ix.item(index)?.node(tree)?;
Some(Some(NodeRef::new(doc, presented(n))))
});
indexed.unwrap_or_else(|| self.0.items().nth(index))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ScalarRef<'d>(NodeRef<'d>);
impl<'d> ScalarRef<'d> {
#[must_use]
pub fn node(self) -> NodeRef<'d> {
self.0
}
#[must_use]
pub fn value(self) -> Cow<'d, str> {
self.0.node.value().unwrap_or(Cow::Borrowed(""))
}
#[must_use]
pub fn style(self) -> ScalarStyle {
match self.0.node.children().last().map(TreeNode::kind) {
Some(SyntaxKind::SingleQuotedScalar) => ScalarStyle::SingleQuoted,
Some(SyntaxKind::DoubleQuotedScalar) => ScalarStyle::DoubleQuoted,
Some(SyntaxKind::LiteralScalar) => ScalarStyle::Literal,
Some(SyntaxKind::FoldedScalar) => ScalarStyle::Folded,
_ => ScalarStyle::Plain,
}
}
pub fn resolved(self) -> Result<Value, Error> {
self.resolved_with(&self.0.resolver())
}
fn as_str(self) -> Option<Cow<'d, str>> {
let tag = self.0.doc.shared.tags.try_tag(self.0.node).ok()?;
let value = self.value();
let plain = self.style() == ScalarStyle::Plain;
match resolve(&self.0.resolver(), &tag, plain, &value, self.0.span()) {
Ok(Resolved::Str) => Some(value),
_ => None,
}
}
pub(super) fn resolved_with(self, r: &Resolver) -> Result<Value, Error> {
let tag = self.0.doc.shared.tags.try_tag(self.0.node)?;
let value = self.value();
let plain = self.style() == ScalarStyle::Plain;
let resolved = resolve(r, &tag, plain, &value, self.0.span())?;
Ok(scalar_value(resolved, value, &tag))
}
fn is_string(self, r: &Resolver, key: &str) -> bool {
let value = self.value();
if value != key {
return false;
}
let Ok(tag) = self.0.doc.shared.tags.try_tag(self.0.node) else {
return false;
};
let plain = self.style() == ScalarStyle::Plain;
matches!(
resolve(r, &tag, plain, &value, self.0.span()),
Ok(Resolved::Str)
)
}
pub(super) fn means_string(self, key: &str) -> bool {
if self.value() != key {
return false;
}
self.is_string(&self.0.resolver(), key)
}
fn is_merge_key(self, r: &Resolver) -> Result<bool, Error> {
let plain = self.style() == ScalarStyle::Plain;
let tag = self.0.doc.shared.tags.try_tag(self.0.node)?;
Ok(is_merge_key(r, &tag, plain, &self.value()))
}
}