initial commit

This commit is contained in:
kageru 2020-06-13 09:18:47 +02:00
parent 7a909cc540
commit 7bceb3afc8
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
5 changed files with 163 additions and 10 deletions

10
.gitignore vendored
View File

@ -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

12
Cargo.toml Normal file
View File

@ -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"] }

40
src/error.rs Normal file
View File

@ -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
}
}

105
src/main.rs Normal file
View File

@ -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);
}

6
src/response.pest Normal file
View File

@ -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) }