initial commit
This commit is contained in:
parent
7a909cc540
commit
7bceb3afc8
|
@ -1,12 +1,2 @@
|
|||
# ---> Rust
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "mparsed"
|
||||
version = "0.1.0"
|
||||
authors = ["kageru <kageru@encode.moe>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
pest = "2.1"
|
||||
pest_derive = "2.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
|
@ -0,0 +1,40 @@
|
|||
use pest;
|
||||
use serde::de;
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use crate::Rule;
|
||||
|
||||
pub type MpdResult<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Error {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl From<pest::error::Error<Rule>> for Error {
|
||||
fn from(err: pest::error::Error<Rule>) -> Self {
|
||||
Error {
|
||||
message: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Error for Error {
|
||||
fn custom<T: Display>(msg: T) -> Self {
|
||||
Error {
|
||||
message: msg.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str(&self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
&self.message
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
#[macro_use]
|
||||
extern crate pest_derive;
|
||||
use pest::iterators::Pair;
|
||||
use pest::Parser;
|
||||
use serde::de;
|
||||
use serde::de::value::MapDeserializer;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::forward_to_deserialize_any;
|
||||
use serde::Deserialize;
|
||||
mod error;
|
||||
use error::MpdResult;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[grammar = "response.pest"]
|
||||
struct MpdParser;
|
||||
|
||||
struct MPDeserializer<'de, Iter: Iterator<Item = (String, String)>> {
|
||||
inner: MapDeserializer<'de, Iter, error::Error>,
|
||||
}
|
||||
|
||||
impl<'de, Iter: Iterator<Item = (String, String)>> de::Deserializer<'de>
|
||||
for MPDeserializer<'de, Iter>
|
||||
{
|
||||
type Error = error::Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> MpdResult<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_map(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_map<V>(self, visitor: V) -> MpdResult<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_map(self.inner)
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool char str string bytes byte_buf unit unit_struct seq
|
||||
tuple tuple_struct struct identifier ignored_any
|
||||
i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 option newtype_struct enum
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Song {
|
||||
Title: String,
|
||||
Artist: String,
|
||||
}
|
||||
|
||||
const input_var: &str = "Title: A song 星
|
||||
Artist: A name
|
||||
OK mpd 0.21.23";
|
||||
|
||||
fn main() {
|
||||
/*
|
||||
let parsed = MpdParser::parse(Rule::response, input)
|
||||
.expect("invalid response")
|
||||
.next()
|
||||
.unwrap();
|
||||
let last = parsed.into_inner().last().unwrap();
|
||||
match last.as_rule() {
|
||||
Rule::ok => println!("response was ok"),
|
||||
Rule::err => println!("response was an error"),
|
||||
_ => unreachable!("Last response line should always be a status"),
|
||||
}
|
||||
let mut deser = MPDeserializer::from_str(
|
||||
"Title: A song 星
|
||||
Artist: A name
|
||||
OK mpd 0.21.23",
|
||||
)
|
||||
.expect("broken deser");
|
||||
let d = Song::deserialize(&mut deser);
|
||||
println!("{:?}", d);
|
||||
*/
|
||||
let mut map = std::collections::HashMap::new();
|
||||
let parser = MpdParser::parse(Rule::response, input_var)
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap();
|
||||
for pair in parser.into_inner() {
|
||||
let rule = pair.as_rule();
|
||||
match rule {
|
||||
Rule::kv => {
|
||||
let mut fields = pair.into_inner();
|
||||
map.insert(
|
||||
fields.next().unwrap().as_str().to_string(),
|
||||
fields.next().unwrap().as_str().to_string(),
|
||||
);
|
||||
}
|
||||
Rule::ok => (),
|
||||
Rule::err => panic!("received error response"),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
// ::<'_, _, Song>
|
||||
dbg!(&map);
|
||||
let deser = MPDeserializer {
|
||||
inner: serde::de::value::MapDeserializer::new(map.into_iter()),
|
||||
};
|
||||
let s = Song::deserialize(deser);
|
||||
println!("{:?}", s);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
key = { ('a'..'z' | 'A'..'Z')+ }
|
||||
val = { (!"\n" ~ ANY)* }
|
||||
kv = { key ~ ": " ~ val ~ "\n" }
|
||||
ok = { "OK" ~ " "? ~ val? }
|
||||
err = {"ACK" ~ " "? ~ val? }
|
||||
response = { kv* ~ (ok | err) }
|
Loading…
Reference in New Issue