use std::iter::FromIterator;
use std::str::FromStr;
use toml_datetime::{Date, Datetime, Time};
use crate::key::Key;
use crate::repr::{Decor, Formatted};
use crate::{Array, InlineTable, InternalString, RawString};
#[derive(Debug, Clone)]
pub enum Value {
String(Formatted<String>),
Integer(Formatted<i64>),
Float(Formatted<f64>),
Boolean(Formatted<bool>),
Datetime(Formatted<Datetime>),
Array(Array),
InlineTable(InlineTable),
}
impl Value {
pub fn type_name(&self) -> &'static str {
match self {
Value::String(..) => "string",
Value::Integer(..) => "integer",
Value::Float(..) => "float",
Value::Boolean(..) => "boolean",
Value::Datetime(..) => "datetime",
Value::Array(..) => "array",
Value::InlineTable(..) => "inline table",
}
}
pub fn as_str(&self) -> Option<&str> {
match *self {
Value::String(ref value) => Some(value.value()),
_ => None,
}
}
pub fn is_str(&self) -> bool {
self.as_str().is_some()
}
pub fn as_integer(&self) -> Option<i64> {
match *self {
Value::Integer(ref value) => Some(*value.value()),
_ => None,
}
}
pub fn is_integer(&self) -> bool {
self.as_integer().is_some()
}
pub fn as_float(&self) -> Option<f64> {
match *self {
Value::Float(ref value) => Some(*value.value()),
_ => None,
}
}
pub fn is_float(&self) -> bool {
self.as_float().is_some()
}
pub fn as_bool(&self) -> Option<bool> {
match *self {
Value::Boolean(ref value) => Some(*value.value()),
_ => None,
}
}
pub fn is_bool(&self) -> bool {
self.as_bool().is_some()
}
pub fn as_datetime(&self) -> Option<&Datetime> {
match *self {
Value::Datetime(ref value) => Some(value.value()),
_ => None,
}
}
pub fn is_datetime(&self) -> bool {
self.as_datetime().is_some()
}
pub fn as_array(&self) -> Option<&Array> {
match *self {
Value::Array(ref value) => Some(value),
_ => None,
}
}
pub fn as_array_mut(&mut self) -> Option<&mut Array> {
match *self {
Value::Array(ref mut value) => Some(value),
_ => None,
}
}
pub fn is_array(&self) -> bool {
self.as_array().is_some()
}
pub fn as_inline_table(&self) -> Option<&InlineTable> {
match *self {
Value::InlineTable(ref value) => Some(value),
_ => None,
}
}
pub fn as_inline_table_mut(&mut self) -> Option<&mut InlineTable> {
match *self {
Value::InlineTable(ref mut value) => Some(value),
_ => None,
}
}
pub fn is_inline_table(&self) -> bool {
self.as_inline_table().is_some()
}
}
impl Value {
pub fn decor_mut(&mut self) -> &mut Decor {
match self {
Value::String(f) => f.decor_mut(),
Value::Integer(f) => f.decor_mut(),
Value::Float(f) => f.decor_mut(),
Value::Boolean(f) => f.decor_mut(),
Value::Datetime(f) => f.decor_mut(),
Value::Array(a) => a.decor_mut(),
Value::InlineTable(t) => t.decor_mut(),
}
}
pub fn decor(&self) -> &Decor {
match *self {
Value::String(ref f) => f.decor(),
Value::Integer(ref f) => f.decor(),
Value::Float(ref f) => f.decor(),
Value::Boolean(ref f) => f.decor(),
Value::Datetime(ref f) => f.decor(),
Value::Array(ref a) => a.decor(),
Value::InlineTable(ref t) => t.decor(),
}
}
pub fn decorated(mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>) -> Self {
self.decorate(prefix, suffix);
self
}
pub(crate) fn decorate(&mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>) {
let decor = self.decor_mut();
*decor = Decor::new(prefix, suffix);
}
pub fn span(&self) -> Option<std::ops::Range<usize>> {
match self {
Value::String(f) => f.span(),
Value::Integer(f) => f.span(),
Value::Float(f) => f.span(),
Value::Boolean(f) => f.span(),
Value::Datetime(f) => f.span(),
Value::Array(a) => a.span(),
Value::InlineTable(t) => t.span(),
}
}
pub(crate) fn despan(&mut self, input: &str) {
match self {
Value::String(f) => f.despan(input),
Value::Integer(f) => f.despan(input),
Value::Float(f) => f.despan(input),
Value::Boolean(f) => f.despan(input),
Value::Datetime(f) => f.despan(input),
Value::Array(a) => a.despan(input),
Value::InlineTable(t) => t.despan(input),
}
}
}
#[cfg(feature = "parse")]
impl FromStr for Value {
type Err = crate::TomlError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
crate::parser::parse_value(s)
}
}
impl<'b> From<&'b Value> for Value {
fn from(s: &'b Value) -> Self {
s.clone()
}
}
impl<'b> From<&'b str> for Value {
fn from(s: &'b str) -> Self {
s.to_owned().into()
}
}
impl<'b> From<&'b String> for Value {
fn from(s: &'b String) -> Self {
s.to_owned().into()
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Value::String(Formatted::new(s))
}
}
impl<'b> From<&'b InternalString> for Value {
fn from(s: &'b InternalString) -> Self {
s.as_str().into()
}
}
impl From<InternalString> for Value {
fn from(s: InternalString) -> Self {
s.as_str().into()
}
}
impl From<i64> for Value {
fn from(i: i64) -> Self {
Value::Integer(Formatted::new(i))
}
}
impl From<f64> for Value {
fn from(f: f64) -> Self {
Value::Float(Formatted::new(f))
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
Value::Boolean(Formatted::new(b))
}
}
impl From<Datetime> for Value {
fn from(d: Datetime) -> Self {
Value::Datetime(Formatted::new(d))
}
}
impl From<Date> for Value {
fn from(d: Date) -> Self {
let d: Datetime = d.into();
d.into()
}
}
impl From<Time> for Value {
fn from(d: Time) -> Self {
let d: Datetime = d.into();
d.into()
}
}
impl From<Array> for Value {
fn from(array: Array) -> Self {
Value::Array(array)
}
}
impl From<InlineTable> for Value {
fn from(table: InlineTable) -> Self {
Value::InlineTable(table)
}
}
impl<V: Into<Value>> FromIterator<V> for Value {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = V>,
{
let array: Array = iter.into_iter().collect();
Value::Array(array)
}
}
impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for Value {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
{
let table: InlineTable = iter.into_iter().collect();
Value::InlineTable(table)
}
}
#[cfg(feature = "display")]
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
crate::encode::encode_value(self, f, None, ("", ""))
}
}
pub(crate) const DEFAULT_VALUE_DECOR: (&str, &str) = (" ", "");
pub(crate) const DEFAULT_TRAILING_VALUE_DECOR: (&str, &str) = (" ", " ");
pub(crate) const DEFAULT_LEADING_VALUE_DECOR: (&str, &str) = ("", "");
#[cfg(test)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
mod tests {
use super::*;
#[test]
fn from_iter_formatting() {
let features = ["node".to_owned(), "mouth".to_owned()];
let features: Value = features.iter().cloned().collect();
assert_eq!(features.to_string(), r#"["node", "mouth"]"#);
}
}
#[test]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
fn string_roundtrip() {
Value::from("hello").to_string().parse::<Value>().unwrap();
}