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 {
#[must_use]
pub const fn new() -> Self {
Self {
entries: Vec::new(),
}
}
#[must_use]
pub const fn len(&self) -> usize {
self.entries.len()
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.entries.is_empty()
}
#[must_use]
pub fn get(&self, key: &str) -> Option<&Value> {
self.entries
.iter()
.find(|(k, _)| k.as_str() == Some(key))
.map(|(_, v)| v)
}
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
self.entries
.iter_mut()
.find(|(k, _)| k.as_str() == Some(key))
.map(|(_, v)| v)
}
#[must_use]
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 iter_mut(&mut self) -> impl Iterator<Item = (&mut Value, &mut Value)> {
self.entries.iter_mut().map(|(k, v)| (k, v))
}
pub fn keys(&self) -> impl Iterator<Item = &str> {
self.entries.iter().filter_map(|(k, _)| k.as_str())
}
pub fn values(&self) -> impl Iterator<Item = &Value> {
self.entries.iter().map(|(_, v)| v)
}
#[must_use]
pub fn entries(&self) -> &[(Value, Value)] {
&self.entries
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Null,
Bool(bool),
Int(i64),
Float(f64),
String(String),
Sequence(Vec<Self>),
Mapping(Mapping),
}
impl Value {
pub fn parse(text: &str) -> Result<Self, YamlError> {
parser::parse(text)
}
#[must_use]
pub fn to_yaml_string(&self) -> String {
emitter::emit(self)
}
#[must_use]
pub fn as_str(&self) -> Option<&str> {
match self {
Self::String(s) => Some(s),
_ => None,
}
}
#[must_use]
pub const fn as_bool(&self) -> Option<bool> {
match self {
Self::Bool(b) => Some(*b),
_ => None,
}
}
#[must_use]
pub const fn as_int(&self) -> Option<i64> {
match self {
Self::Int(i) => Some(*i),
_ => None,
}
}
#[must_use]
pub const fn as_float(&self) -> Option<f64> {
match self {
Self::Float(f) => Some(*f),
_ => None,
}
}
#[must_use]
pub fn as_sequence(&self) -> Option<&[Self]> {
match self {
Self::Sequence(s) => Some(s),
_ => None,
}
}
#[must_use]
pub const fn as_mapping(&self) -> Option<&Mapping> {
match self {
Self::Mapping(m) => Some(m),
_ => None,
}
}
#[must_use]
pub const fn is_empty_value(&self) -> bool {
match self {
Self::Null | Self::Bool(false) | Self::Int(0) => true,
Self::String(s) => s.is_empty(),
Self::Sequence(s) => s.is_empty(),
Self::Mapping(m) => m.is_empty(),
_ => false,
}
}
#[must_use]
pub fn as_display_string(&self) -> Option<String> {
match self {
Self::String(s) => Some(s.clone()),
Self::Bool(b) => Some(b.to_string()),
Self::Int(i) => Some(i.to_string()),
Self::Float(f) => Some(format!("{f}")),
_ => None,
}
}
#[must_use]
pub fn as_display_str(&self) -> Option<std::borrow::Cow<'_, str>> {
match self {
Self::String(s) => Some(std::borrow::Cow::Borrowed(s)),
Self::Bool(b) => Some(std::borrow::Cow::Owned(b.to_string())),
Self::Int(i) => Some(std::borrow::Cow::Owned(i.to_string())),
Self::Float(f) => Some(std::borrow::Cow::Owned(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 {
Self::String(s.to_string())
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Self::String(s)
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
Self::Bool(b)
}
}
impl From<i64> for Value {
fn from(i: i64) -> Self {
Self::Int(i)
}
}
impl<T: Into<Self>> From<Vec<T>> for Value {
fn from(v: Vec<T>) -> Self {
Self::Sequence(v.into_iter().map(Into::into).collect())
}
}
impl From<Mapping> for Value {
fn from(m: Mapping) -> Self {
Self::Mapping(m)
}
}
impl std::str::FromStr for Value {
type Err = YamlError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl From<i32> for Value {
fn from(i: i32) -> Self {
Self::Int(i64::from(i))
}
}
impl From<i16> for Value {
fn from(i: i16) -> Self {
Self::Int(i64::from(i))
}
}
impl From<i8> for Value {
fn from(i: i8) -> Self {
Self::Int(i64::from(i))
}
}
impl From<u32> for Value {
fn from(u: u32) -> Self {
Self::Int(i64::from(u))
}
}
impl From<u16> for Value {
fn from(u: u16) -> Self {
Self::Int(i64::from(u))
}
}
impl From<u8> for Value {
fn from(u: u8) -> Self {
Self::Int(i64::from(u))
}
}
impl From<u64> for Value {
fn from(u: u64) -> Self {
Self::Int(i64::try_from(u).unwrap_or(i64::MAX))
}
}
impl From<usize> for Value {
fn from(u: usize) -> Self {
Self::Int(i64::try_from(u).unwrap_or(i64::MAX))
}
}
impl From<f64> for Value {
fn from(f: f64) -> Self {
Self::Float(f)
}
}
impl From<f32> for Value {
fn from(f: f32) -> Self {
Self::Float(f64::from(f))
}
}
impl From<&String> for Value {
fn from(s: &String) -> Self {
Self::String(s.clone())
}
}
impl From<std::borrow::Cow<'_, str>> for Value {
fn from(s: std::borrow::Cow<'_, str>) -> Self {
Self::String(s.into_owned())
}
}
impl From<()> for Value {
fn from((): ()) -> Self {
Self::Null
}
}
impl<T: Into<Self>> From<Option<T>> for Value {
fn from(opt: Option<T>) -> Self {
opt.map_or(Self::Null, Into::into)
}
}
impl fmt::Display for Mapping {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&Value::Mapping(self.clone()).to_yaml_string())
}
}
impl IntoIterator for Mapping {
type Item = (Value, Value);
type IntoIter = std::vec::IntoIter<(Value, Value)>;
fn into_iter(self) -> Self::IntoIter {
self.entries.into_iter()
}
}
impl<'a> IntoIterator for &'a Mapping {
type Item = (&'a Value, &'a Value);
type IntoIter = std::iter::Map<
std::slice::Iter<'a, (Value, Value)>,
fn(&(Value, Value)) -> (&Value, &Value),
>;
fn into_iter(self) -> Self::IntoIter {
const fn map_ref(entry: &(Value, Value)) -> (&Value, &Value) {
(&entry.0, &entry.1)
}
self.entries.iter().map(map_ref)
}
}
impl<'a> IntoIterator for &'a mut Mapping {
type Item = (&'a mut Value, &'a mut Value);
type IntoIter = std::iter::Map<
std::slice::IterMut<'a, (Value, Value)>,
fn(&mut (Value, Value)) -> (&mut Value, &mut Value),
>;
fn into_iter(self) -> Self::IntoIter {
const fn map_mut(entry: &mut (Value, Value)) -> (&mut Value, &mut Value) {
(&mut entry.0, &mut entry.1)
}
self.entries.iter_mut().map(map_mut)
}
}
impl FromIterator<(Value, Value)> for Mapping {
fn from_iter<T: IntoIterator<Item = (Value, Value)>>(iter: T) -> Self {
Self {
entries: iter.into_iter().collect(),
}
}
}
impl FromIterator<(String, Value)> for Mapping {
fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
let mut map = Self::new();
for (k, v) in iter {
map.insert(k, v);
}
map
}
}
impl<'a> FromIterator<(&'a str, Value)> for Mapping {
fn from_iter<T: IntoIterator<Item = (&'a str, Value)>>(iter: T) -> Self {
let mut map = Self::new();
for (k, v) in iter {
map.insert(k, v);
}
map
}
}
impl Extend<(Value, Value)> for Mapping {
fn extend<T: IntoIterator<Item = (Value, Value)>>(&mut self, iter: T) {
self.entries.extend(iter);
}
}
impl Extend<(String, Value)> for Mapping {
fn extend<T: IntoIterator<Item = (String, Value)>>(&mut self, iter: T) {
for (k, v) in iter {
self.insert(k, v);
}
}
}
impl<'a> Extend<(&'a str, Value)> for Mapping {
fn extend<T: IntoIterator<Item = (&'a str, Value)>>(&mut self, iter: T) {
for (k, v) in iter {
self.insert(k, v);
}
}
}