mod emitter;
mod parser;
use std::fmt;
pub use parser::YamlError;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Mapping {
entries: Vec<(Value, Value)>,
}
impl Mapping {
pub fn new() -> Self {
Mapping {
entries: Vec::new(),
}
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn get(&self, key: &str) -> Option<&Value> {
self.entries
.iter()
.find(|(k, _)| k.as_str() == Some(key))
.map(|(_, v)| v)
}
pub fn contains_key(&self, key: &str) -> bool {
self.get(key).is_some()
}
pub fn insert(&mut self, key: impl Into<String>, value: Value) -> Option<Value> {
let key = key.into();
if let Some(slot) = self
.entries
.iter_mut()
.find(|(k, _)| k.as_str() == Some(&key))
{
return Some(std::mem::replace(&mut slot.1, value));
}
self.entries.push((Value::String(key), value));
None
}
pub fn remove(&mut self, key: &str) -> Option<Value> {
let idx = self.entries.iter().position(|(k, _)| k.as_str() == Some(key))?;
Some(self.entries.remove(idx).1)
}
pub(crate) fn push_raw(&mut self, key: Value, value: Value) {
self.entries.push((key, value));
}
pub fn iter(&self) -> impl Iterator<Item = (&Value, &Value)> {
self.entries.iter().map(|(k, v)| (k, v))
}
pub fn keys(&self) -> impl Iterator<Item = &str> {
self.entries.iter().filter_map(|(k, _)| k.as_str())
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Null,
Bool(bool),
Int(i64),
Float(f64),
String(String),
Sequence(Vec<Value>),
Mapping(Mapping),
}
impl Value {
pub fn parse(text: &str) -> Result<Value, YamlError> {
parser::parse(text)
}
pub fn to_yaml_string(&self) -> String {
emitter::emit(self)
}
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_int(&self) -> Option<i64> {
match self {
Value::Int(i) => Some(*i),
_ => None,
}
}
pub fn as_sequence(&self) -> Option<&[Value]> {
match self {
Value::Sequence(s) => Some(s),
_ => None,
}
}
pub fn as_mapping(&self) -> Option<&Mapping> {
match self {
Value::Mapping(m) => Some(m),
_ => None,
}
}
pub fn is_empty_value(&self) -> bool {
match self {
Value::Null => true,
Value::String(s) => s.is_empty(),
Value::Sequence(s) => s.is_empty(),
Value::Mapping(m) => m.is_empty(),
Value::Bool(false) => true,
Value::Int(0) => true,
_ => false,
}
}
pub fn as_display_string(&self) -> Option<String> {
match self {
Value::String(s) => Some(s.clone()),
Value::Bool(b) => Some(b.to_string()),
Value::Int(i) => Some(i.to_string()),
Value::Float(f) => Some(format!("{f}")),
_ => None,
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_yaml_string())
}
}
impl From<&str> for Value {
fn from(s: &str) -> Self {
Value::String(s.to_string())
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Value::String(s)
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
Value::Bool(b)
}
}
impl From<i64> for Value {
fn from(i: i64) -> Self {
Value::Int(i)
}
}
impl<T: Into<Value>> From<Vec<T>> for Value {
fn from(v: Vec<T>) -> Self {
Value::Sequence(v.into_iter().map(Into::into).collect())
}
}
impl From<Mapping> for Value {
fn from(m: Mapping) -> Self {
Value::Mapping(m)
}
}