use crate::as_yaml::{AsYaml, YamlNode};
use crate::nodes::mapping::{Mapping, MappingEntry};
use crate::nodes::sequence::Sequence;
#[derive(Debug)]
pub enum Entry<'a, K: AsYaml> {
Occupied(OccupiedEntry<'a>),
Vacant(VacantEntry<'a, K>),
}
#[derive(Debug)]
pub struct OccupiedEntry<'a> {
pub(crate) mapping: &'a Mapping,
pub(crate) entry: MappingEntry,
}
#[derive(Debug)]
pub struct VacantEntry<'a, K: AsYaml> {
pub(crate) mapping: &'a Mapping,
pub(crate) key: K,
}
impl<'a, K: AsYaml> Entry<'a, K> {
pub fn or_insert(self, default: impl AsYaml) -> YamlNode {
match self {
Entry::Occupied(o) => o.into_value(),
Entry::Vacant(v) => v.insert(default),
}
}
pub fn or_insert_with<V, F>(self, default: F) -> YamlNode
where
V: AsYaml,
F: FnOnce() -> V,
{
match self {
Entry::Occupied(o) => o.into_value(),
Entry::Vacant(v) => v.insert(default()),
}
}
pub fn or_insert_mapping(self) -> Mapping {
match self {
Entry::Occupied(o) => {
if let Some(existing) = o.get_mapping() {
return existing;
}
o.set_value(Mapping::new());
o.get_mapping()
.expect("value was just replaced with a mapping")
}
Entry::Vacant(v) => {
let VacantEntry { mapping, key } = v;
mapping.set(&key, Mapping::new());
mapping
.get_mapping(&key)
.expect("mapping was just inserted")
}
}
}
pub fn or_insert_sequence(self) -> Sequence {
match self {
Entry::Occupied(o) => {
if let Some(existing) = o.get_sequence() {
return existing;
}
o.set_value(Sequence::new());
o.get_sequence()
.expect("value was just replaced with a sequence")
}
Entry::Vacant(v) => {
let VacantEntry { mapping, key } = v;
mapping.set(&key, Sequence::new());
mapping
.get_sequence(&key)
.expect("sequence was just inserted")
}
}
}
pub fn and_modify<F>(self, f: F) -> Self
where
F: FnOnce(&OccupiedEntry<'a>),
{
if let Entry::Occupied(ref o) = self {
f(o);
}
self
}
pub fn key(&self) -> Option<YamlNode> {
match self {
Entry::Occupied(o) => o.key(),
Entry::Vacant(v) => key_as_yaml_node(&v.key),
}
}
}
impl<'a> OccupiedEntry<'a> {
pub fn key(&self) -> Option<YamlNode> {
self.entry.key_node()
}
pub fn get(&self) -> Option<YamlNode> {
self.entry.value_node()
}
pub fn get_mapping(&self) -> Option<Mapping> {
self.get()?.mapping_content()
}
pub fn get_sequence(&self) -> Option<Sequence> {
self.get()?.sequence_content()
}
pub fn set_value(&self, value: impl AsYaml) {
let flow_context = self.mapping.is_flow_style();
self.entry.set_value(value, flow_context);
}
pub fn remove_entry(self) -> MappingEntry {
self.entry.clone().remove();
self.entry
}
fn into_value(self) -> YamlNode {
self.entry
.value_node()
.expect("occupied entry has no value node")
}
}
impl<'a, K: AsYaml> VacantEntry<'a, K> {
pub fn key(&self) -> &K {
&self.key
}
pub fn into_key(self) -> K {
self.key
}
pub fn insert(self, value: impl AsYaml) -> YamlNode {
self.mapping.set(&self.key, value);
self.mapping
.get(&self.key)
.expect("value just inserted must be retrievable")
}
}
fn key_as_yaml_node<K: AsYaml>(key: &K) -> Option<YamlNode> {
use crate::lex::SyntaxKind;
use rowan::GreenNodeBuilder;
if let Some(node) = key.value_node() {
return YamlNode::from_syntax(node);
}
let mut builder = GreenNodeBuilder::new();
builder.start_node(SyntaxKind::ROOT.into());
key.build_content(&mut builder, 0, false);
builder.finish_node();
let root = crate::nodes::SyntaxNode::new_root(builder.finish());
crate::nodes::held_node(&root)
}