mirror of
https://codeberg.org/icewind/vdf-reader.git
synced 2026-06-03 18:14:07 +02:00
event/entry parsing
This commit is contained in:
parent
909cd4a18d
commit
26c9b82b8e
6 changed files with 172 additions and 51 deletions
109
src/entry/mod.rs
109
src/entry/mod.rs
|
|
@ -1,4 +1,16 @@
|
||||||
|
mod array;
|
||||||
|
mod statement;
|
||||||
|
mod table;
|
||||||
|
mod value;
|
||||||
|
|
||||||
|
use crate::error::{ParseEntryError, ParseItemError};
|
||||||
|
use crate::Item;
|
||||||
|
pub use array::Array;
|
||||||
|
pub use statement::Statement;
|
||||||
|
use std::any::type_name;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
pub use table::Table;
|
||||||
|
pub use value::Value;
|
||||||
|
|
||||||
/// The kinds of entry.
|
/// The kinds of entry.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
|
||||||
|
|
@ -57,12 +69,8 @@ impl Entry {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to convert the entry to the given type.
|
/// Try to convert the entry to the given type.
|
||||||
pub fn to<T: Parse>(&self) -> Option<T> {
|
pub fn to<T: ParseItem>(self) -> Result<T, ParseEntryError> {
|
||||||
if let Entry::Value(value) = self {
|
T::from_entry(self)
|
||||||
value.to::<T>()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to take the entry as a table.
|
/// Try to take the entry as a table.
|
||||||
|
|
@ -114,9 +122,12 @@ impl Entry {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parsable types.
|
/// Parsable types.
|
||||||
pub trait Parse: Sized {
|
pub trait ParseItem: Sized {
|
||||||
/// Try to parse the string.
|
/// Try to cast the entry into a concrete type
|
||||||
fn parse(string: &str) -> Option<Self>;
|
fn from_entry(entry: Entry) -> Result<Self, ParseEntryError>;
|
||||||
|
|
||||||
|
/// Try to cast the item into a concrete type
|
||||||
|
fn from_item(item: Item) -> Result<Self, ParseItemError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! from_str {
|
macro_rules! from_str {
|
||||||
|
|
@ -128,10 +139,20 @@ macro_rules! from_str {
|
||||||
);
|
);
|
||||||
|
|
||||||
($ty:ident) => (
|
($ty:ident) => (
|
||||||
impl Parse for $ty {
|
impl ParseItem for $ty {
|
||||||
fn parse(string: &str) -> Option<Self> {
|
fn from_entry(entry: Entry) -> Result<Self, ParseEntryError> {
|
||||||
string.parse::<$ty>().ok()
|
let string = match entry.as_str() {
|
||||||
|
Some(string) => string,
|
||||||
|
None => {
|
||||||
|
return Err(ParseEntryError::new(type_name::<Self>(), entry));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
string.parse::<$ty>().map_err(|_| ParseEntryError::new(type_name::<Self>(), entry))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_item(item: Item) -> Result<Self, ParseItemError> {
|
||||||
|
item.as_str().parse::<$ty>().map_err(|_| ParseItemError::new(type_name::<Self>(), item))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -141,25 +162,61 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV
|
||||||
from_str!(for IpAddr Ipv4Addr Ipv6Addr SocketAddr SocketAddrV4 SocketAddrV6);
|
from_str!(for IpAddr Ipv4Addr Ipv6Addr SocketAddr SocketAddrV4 SocketAddrV6);
|
||||||
from_str!(for i8 i16 i32 i64 isize u8 u16 u32 u64 usize f32 f64);
|
from_str!(for i8 i16 i32 i64 isize u8 u16 u32 u64 usize f32 f64);
|
||||||
|
|
||||||
impl Parse for bool {
|
impl ParseItem for bool {
|
||||||
fn parse(string: &str) -> Option<Self> {
|
fn from_entry(entry: Entry) -> Result<Self, ParseEntryError> {
|
||||||
|
let string = match entry.as_str() {
|
||||||
|
Some(string) => string,
|
||||||
|
None => {
|
||||||
|
return Err(ParseEntryError::new(type_name::<Self>(), entry));
|
||||||
|
}
|
||||||
|
};
|
||||||
match string {
|
match string {
|
||||||
"0" => Some(false),
|
"0" => Ok(false),
|
||||||
"1" => Some(true),
|
"1" => Ok(true),
|
||||||
v => v.parse::<bool>().ok(),
|
v => v
|
||||||
|
.parse::<bool>()
|
||||||
|
.map_err(|_| ParseEntryError::new(type_name::<Self>(), entry)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_item(item: Item) -> Result<Self, ParseItemError> {
|
||||||
|
match item.as_str() {
|
||||||
|
"0" => Ok(false),
|
||||||
|
"1" => Ok(true),
|
||||||
|
v => v
|
||||||
|
.parse::<bool>()
|
||||||
|
.map_err(|_| ParseItemError::new(type_name::<Self>(), item)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod table;
|
impl ParseItem for String {
|
||||||
pub use table::Table;
|
fn from_entry(entry: Entry) -> Result<Self, ParseEntryError> {
|
||||||
|
match entry {
|
||||||
|
Entry::Table(entry) => Err(ParseEntryError::new(
|
||||||
|
type_name::<Self>(),
|
||||||
|
Entry::Table(entry),
|
||||||
|
)),
|
||||||
|
Entry::Array(entry) => Err(ParseEntryError::new(
|
||||||
|
type_name::<Self>(),
|
||||||
|
Entry::Array(entry),
|
||||||
|
)),
|
||||||
|
Entry::Statement(statement) => Ok(statement.into()),
|
||||||
|
Entry::Value(value) => Ok(value.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod array;
|
fn from_item(item: Item) -> Result<Self, ParseItemError> {
|
||||||
pub use array::Array;
|
Ok(item.into_content().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod statement;
|
impl<T: ParseItem> ParseItem for Option<T> {
|
||||||
pub use statement::Statement;
|
fn from_entry(entry: Entry) -> Result<Self, ParseEntryError> {
|
||||||
|
T::from_entry(entry).map(Some)
|
||||||
|
}
|
||||||
|
|
||||||
mod value;
|
fn from_item(item: Item) -> Result<Self, ParseItemError> {
|
||||||
use crate::Item;
|
T::from_item(item).map(Some)
|
||||||
pub use value::Value;
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,12 @@ impl From<Statement> for Entry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Statement> for String {
|
||||||
|
fn from(value: Statement) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Deref for Statement {
|
impl Deref for Statement {
|
||||||
type Target = str;
|
type Target = str;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Entry, Parse};
|
use super::Entry;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
@ -18,6 +18,12 @@ impl From<Value> for Entry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Value> for String {
|
||||||
|
fn from(value: Value) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Deref for Value {
|
impl Deref for Value {
|
||||||
type Target = str;
|
type Target = str;
|
||||||
|
|
||||||
|
|
@ -25,10 +31,3 @@ impl Deref for Value {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
|
||||||
/// Try to convert the value to the given type.
|
|
||||||
pub fn to<T: Parse>(&self) -> Option<T> {
|
|
||||||
T::parse(&self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
56
src/error.rs
56
src/error.rs
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{Event, Token};
|
use crate::entry::Entry;
|
||||||
|
use crate::{Event, Item, Token};
|
||||||
use miette::{Diagnostic, SourceSpan};
|
use miette::{Diagnostic, SourceSpan};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
@ -19,6 +20,14 @@ pub enum VdfError {
|
||||||
#[diagnostic(transparent)]
|
#[diagnostic(transparent)]
|
||||||
/// Wrong event to for conversion
|
/// Wrong event to for conversion
|
||||||
WrongEntryType(#[from] WrongEventTypeError),
|
WrongEntryType(#[from] WrongEventTypeError),
|
||||||
|
#[error(transparent)]
|
||||||
|
#[diagnostic(transparent)]
|
||||||
|
/// Failed to parse entry into type
|
||||||
|
ParseEntry(#[from] ParseEntryError),
|
||||||
|
#[error(transparent)]
|
||||||
|
#[diagnostic(transparent)]
|
||||||
|
/// Failed to parse item into type
|
||||||
|
ParseItem(#[from] ParseItemError),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExpectedTokens<'a>(&'a [Token]);
|
struct ExpectedTokens<'a>(&'a [Token]);
|
||||||
|
|
@ -134,8 +143,53 @@ impl WrongEventTypeError {
|
||||||
src: String::new(),
|
src: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn new_with_source(
|
||||||
|
event: Event,
|
||||||
|
expected: &'static str,
|
||||||
|
got: &'static str,
|
||||||
|
src: String,
|
||||||
|
) -> Self {
|
||||||
|
WrongEventTypeError {
|
||||||
|
err_span: event.span().into(),
|
||||||
|
event: event.into_owned(),
|
||||||
|
expected,
|
||||||
|
got,
|
||||||
|
src,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_source(self, src: String) -> Self {
|
pub fn with_source(self, src: String) -> Self {
|
||||||
WrongEventTypeError { src, ..self }
|
WrongEventTypeError { src, ..self }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Error, Diagnostic)]
|
||||||
|
#[error("Can't parse entry {value:?} as {ty}")]
|
||||||
|
#[diagnostic(code(vmt_parser::eof))]
|
||||||
|
pub struct ParseEntryError {
|
||||||
|
pub ty: &'static str,
|
||||||
|
pub value: Entry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParseEntryError {
|
||||||
|
pub fn new(ty: &'static str, value: Entry) -> Self {
|
||||||
|
ParseEntryError { ty, value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Error, Diagnostic)]
|
||||||
|
#[error("Can't parse entry {value:?} as {ty}")]
|
||||||
|
#[diagnostic(code(vmt_parser::eof))]
|
||||||
|
pub struct ParseItemError {
|
||||||
|
pub ty: &'static str,
|
||||||
|
pub value: Item<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParseItemError {
|
||||||
|
pub fn new(ty: &'static str, value: Item) -> Self {
|
||||||
|
ParseItemError {
|
||||||
|
ty,
|
||||||
|
value: value.into_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
35
src/event.rs
35
src/event.rs
|
|
@ -13,21 +13,6 @@ pub enum Item<'a> {
|
||||||
Item { content: Cow<'a, str>, span: Span },
|
Item { content: Cow<'a, str>, span: Span },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item<'_> {
|
|
||||||
pub fn into_owned(self) -> Item<'static> {
|
|
||||||
match self {
|
|
||||||
Item::Statement { content, span } => Item::Statement {
|
|
||||||
content: content.into_owned().into(),
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
Item::Item { content, span } => Item::Item {
|
|
||||||
content: content.into_owned().into(),
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Item<'a> {
|
impl<'a> Item<'a> {
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -42,6 +27,26 @@ impl<'a> Item<'a> {
|
||||||
Item::Item { content, .. } => content,
|
Item::Item { content, .. } => content,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Item::Statement { content, .. } => content.as_ref(),
|
||||||
|
Item::Item { content, .. } => content.as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_owned(self) -> Item<'static> {
|
||||||
|
match self {
|
||||||
|
Item::Statement { content, span } => Item::Statement {
|
||||||
|
content: content.into_owned().into(),
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
Item::Item { content, span } => Item::Item {
|
||||||
|
content: content.into_owned().into(),
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reader event.
|
/// Reader event.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
pub mod entry;
|
pub mod entry;
|
||||||
mod error;
|
pub mod error;
|
||||||
mod event;
|
mod event;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod reader;
|
mod reader;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue