tml/src/args.rs

85 lines
2.1 KiB
Rust

use std::str::FromStr;
use crate::ast::{ParseErrorKind, ParseResult, Value, ValueKind};
use crate::source::WithSource;
#[derive(Clone, Debug, Default)]
pub struct Args(Vec<Arg>);
impl Args {
pub fn new() -> Self {
Self(Vec::new())
}
pub fn contains(&mut self, name: &str) -> bool {
self.0.iter().find(|arg| arg.name.inner == name).is_some()
}
pub fn get(&mut self, name: &str) -> Option<Arg> {
let idx = self.0.iter().position(|old| old.name.inner == name);
idx.map(|idx| self.0.remove(idx))
}
pub fn insert(&mut self, arg: Arg) -> Option<Arg> {
let existing = self
.0
.iter()
.position(|old| old.name.inner == arg.name.inner);
self.0.push(arg);
existing.map(|idx| self.0.remove(idx))
}
}
#[derive(Clone, Debug)]
pub struct Arg {
pub name: WithSource<String>,
pub val: Value,
}
pub trait ParseArgs: Sized {
fn parse_args(args: &mut Args) -> ParseResult<Self>;
}
pub trait ParseValue: Sized {
fn parse_value(val: &Value) -> ParseResult<Self>;
}
pub trait ParseScoped: Sized {
type Default;
fn parse_scoped(args: &mut Args, scope: &str, default: Self::Default) -> ParseResult<Self>;
}
impl ParseValue for usize {
fn parse_value(val: &Value) -> ParseResult<Self> {
match val.inner {
ValueKind::Number(num) => Ok(num as Self),
_ => Err(val.map(ParseErrorKind::InvalidValue)),
}
}
}
impl<T: ParseValue> ParseValue for Option<T> {
fn parse_value(val: &Value) -> ParseResult<Self> {
if let ValueKind::Symbol(symbol) = &val.inner {
if symbol.to_lowercase() == "none" {
return Ok(None);
}
}
T::parse_value(val).map(|t| Some(t))
}
}
pub(crate) trait ParseSymbol: FromStr {}
impl<T: ParseSymbol> ParseValue for T {
fn parse_value(val: &Value) -> ParseResult<Self> {
match &val.inner {
ValueKind::Symbol(symbol) => {
T::from_str(&symbol).map_err(|_| val.map(ParseErrorKind::InvalidValue))
}
_ => Err(val.map(ParseErrorKind::InvalidValue)),
}
}
}