use rust_decimal::prelude::ToPrimitive;
use rust_decimal::Decimal;
use std::borrow::Cow;
use crate::parse::token::{
Comment as ParsedComment, Field as ParsedField, InlineComment as ParsedInlineComment,
Value as ParsedValue,
};
#[derive(Clone, PartialEq, Debug)]
pub enum Token<'a> {
Field(Field<'a>),
Comment {
is_inline: bool,
inner: Cow<'a, str>,
},
}
impl<'input> From<&ParsedField<'input>> for Token<'input> {
fn from(field: &ParsedField<'input>) -> Self {
Self::Field(field.into())
}
}
impl<'a, 'input: 'a> From<&'a ParsedInlineComment<'input>> for Token<'input> {
fn from(comment: &'a ParsedInlineComment<'input>) -> Self {
Self::Comment {
is_inline: true,
inner: Cow::Borrowed(
comment
.inner
.strip_prefix('(')
.unwrap()
.strip_suffix(')')
.unwrap(),
),
}
}
}
impl<'input> From<&ParsedComment<'input>> for Token<'input> {
fn from(comment: &ParsedComment<'input>) -> Self {
Self::Comment {
is_inline: false,
inner: Cow::Borrowed(comment.inner.strip_prefix(';').unwrap()),
}
}
}
#[derive(Clone, PartialEq, Debug)]
pub struct Field<'a> {
pub letters: Cow<'a, str>,
pub value: Value<'a>,
}
impl<'input> From<&ParsedField<'input>> for Field<'input> {
fn from(field: &ParsedField<'input>) -> Self {
Self {
letters: field.letters.into(),
value: Value::from(&field.value),
}
}
}
impl<'a> From<Field<'a>> for Token<'a> {
fn from(field: Field<'a>) -> Token<'a> {
Self::Field(field)
}
}
impl<'a> Field<'a> {
pub fn into_owned(self) -> Field<'static> {
Field {
letters: self.letters.into_owned().into(),
value: self.value.into_owned(),
}
}
}
#[derive(Clone, PartialEq, Debug)]
pub enum Value<'a> {
Rational(Decimal),
Float(f64),
Integer(usize),
String(Cow<'a, str>),
}
impl Value<'_> {
pub fn as_f64(&self) -> Option<f64> {
match self {
Self::Rational(r) => r.to_f64(),
Self::Integer(i) => Some(*i as f64),
Self::Float(f) => Some(*f),
Self::String(_) => None,
}
}
pub fn into_owned(self) -> Value<'static> {
match self {
Self::String(s) => Value::String(s.into_owned().into()),
Self::Rational(r) => Value::Rational(r),
Self::Integer(i) => Value::Integer(i),
Self::Float(f) => Value::Float(f),
}
}
}
impl<'input> From<&ParsedValue<'input>> for Value<'input> {
fn from(val: &ParsedValue<'input>) -> Self {
use ParsedValue::*;
match val {
Rational(r) => Self::Rational(*r),
Integer(i) => Self::Integer(*i),
String(s) => {
Self::String(Cow::Borrowed(
s.strip_prefix('"').unwrap().strip_suffix('"').unwrap(),
))
}
}
}
}