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/
|
/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
|
**/*.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
Block a user