convert to library
This commit is contained in:
parent
000eb9945a
commit
8253e4b5de
|
@ -0,0 +1,73 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "envy"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f938a4abd5b75fe3737902dbc2e79ca142cc1526827a9e40b829a086758531a9"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mparsed"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"envy",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
|
@ -4,9 +4,9 @@ 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]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
#itertools = "0.9"
|
||||
envy = "0.4"
|
||||
|
||||
[lib]
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
newline_style = "Unix"
|
||||
max_width = 140
|
||||
tab_spaces = 2
|
||||
imports_layout = "Horizontal"
|
||||
merge_imports = true
|
||||
struct_field_align_threshold = 25
|
||||
where_single_line = true
|
||||
edition = "2018"
|
|
@ -0,0 +1,102 @@
|
|||
use serde::{de, de::value::MapDeserializer, forward_to_deserialize_any};
|
||||
use std::collections::HashMap;
|
||||
mod error;
|
||||
use error::{Error, MpdResult};
|
||||
mod structs;
|
||||
pub use structs::Track;
|
||||
|
||||
/// some unprintable character to separate repeated keys
|
||||
const SEPARATOR: char = '\x02';
|
||||
|
||||
struct MPDeserializer<'de, Iter: Iterator<Item = (&'de str, &'de str)>> {
|
||||
inner: MapDeserializer<'de, Iter, Error>,
|
||||
}
|
||||
|
||||
impl<'de, Iter: Iterator<Item = (&'de str, &'de str)>> de::Deserializer<'de> for MPDeserializer<'de, Iter> {
|
||||
type 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
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_response<'a, I: Iterator<Item = &'a str>, T: de::Deserialize<'a>>(input: I) -> Result<Track, Error> {
|
||||
let mut map: HashMap<String, String> = HashMap::new();
|
||||
for line in input {
|
||||
if line.starts_with("OK") {
|
||||
break;
|
||||
} else if let Some(message) = line.strip_prefix("ACK") {
|
||||
return Err(Error::from_str(message.trim()));
|
||||
}
|
||||
let mut fields = line.splitn(2, ": ");
|
||||
match (fields.next(), fields.next()) {
|
||||
(Some(k), Some(v)) => {
|
||||
if let Some(existing) = map.get_mut(k) {
|
||||
existing.push(SEPARATOR);
|
||||
existing.push_str(v);
|
||||
} else {
|
||||
map.insert(k.to_string(), v.to_string());
|
||||
}
|
||||
}
|
||||
_ => panic!("invalid response line: {:?}", line),
|
||||
}
|
||||
}
|
||||
return Ok(envy::from_iter(map).unwrap());
|
||||
// Eventually, I’d like to use my own deserializer instead of envy
|
||||
// let deser = MPDeserializer {
|
||||
// inner: MapDeserializer::new(map.into_iter()),
|
||||
// };
|
||||
// Song::deserialize(deser)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn track_de_test() {
|
||||
let input_str = "file: American Pie.flac
|
||||
Last-Modified: 2019-12-16T21:38:54Z
|
||||
Album: American Pie
|
||||
Artist: Don McLean
|
||||
Date: 1979
|
||||
Genre: Rock
|
||||
Title: American Pie
|
||||
Track: 1
|
||||
Time: 512
|
||||
duration: 512.380
|
||||
Pos: 1367
|
||||
Id: 1368
|
||||
OK";
|
||||
let t = deserialize_response::<'_, _, Track>(input_str.lines()).unwrap();
|
||||
assert_eq!(
|
||||
t,
|
||||
Track {
|
||||
file: "American Pie.flac".to_string(),
|
||||
last_modified: Some("2019-12-16T21:38:54Z".to_string()),
|
||||
album: Some("American Pie".to_string()),
|
||||
artist: Some("Don McLean".to_string()),
|
||||
date: Some(1979),
|
||||
genre: Some("Rock".to_string()),
|
||||
title: Some("American Pie".to_string()),
|
||||
track: Some(1),
|
||||
duration: std::time::Duration::from_secs_f64(512.380),
|
||||
pos: 1367,
|
||||
id: 1368,
|
||||
..Track::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
87
src/main.rs
87
src/main.rs
|
@ -1,87 +0,0 @@
|
|||
use serde::de;
|
||||
use serde::de::value::MapDeserializer;
|
||||
use serde::forward_to_deserialize_any;
|
||||
use std::collections::HashMap;
|
||||
mod error;
|
||||
use error::{Error, MpdResult};
|
||||
mod structs;
|
||||
pub use structs::Track;
|
||||
|
||||
/// some unprintable character to separate repeated keys
|
||||
const SEPARATOR: char = '\x02';
|
||||
|
||||
struct MPDeserializer<'de, Iter: Iterator<Item = (&'de str, &'de str)>> {
|
||||
inner: MapDeserializer<'de, Iter, Error>,
|
||||
}
|
||||
|
||||
impl<'de, Iter: Iterator<Item = (&'de str, &'de str)>> de::Deserializer<'de>
|
||||
for MPDeserializer<'de, Iter>
|
||||
{
|
||||
type 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
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_response<'a, I: Iterator<Item = &'a str>>(input: I) -> Result<Track, Error> {
|
||||
let mut map: HashMap<String, String> = HashMap::new();
|
||||
for line in input {
|
||||
if line.starts_with("OK") {
|
||||
break;
|
||||
} else if let Some(message) = line.strip_prefix("ACK") {
|
||||
return Err(Error::from_str(message.trim()));
|
||||
}
|
||||
let mut fields = line.splitn(2, ": ");
|
||||
match (fields.next(), fields.next()) {
|
||||
(Some(k), Some(v)) => {
|
||||
if let Some(existing) = map.get_mut(k) {
|
||||
existing.push(SEPARATOR);
|
||||
existing.push_str(v);
|
||||
} else {
|
||||
map.insert(k.to_string(), v.to_string());
|
||||
}
|
||||
}
|
||||
_ => panic!("invalid response line: {:?}", line),
|
||||
}
|
||||
}
|
||||
return Ok(envy::from_iter(map).unwrap());
|
||||
// Eventually, I’d like to use my own deserializer instead of envy
|
||||
// let deser = MPDeserializer {
|
||||
// inner: MapDeserializer::new(map.into_iter()),
|
||||
// };
|
||||
// Song::deserialize(deser)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let input_str = "file: Youtube Rip/VVVVVV Medley.flac
|
||||
Last-Modified: 2018-03-07T13:18:01Z
|
||||
Album: VVVVVV OST / PPPPPP
|
||||
Artist: FamilyJules7x
|
||||
Composer: Magnus Pålsson
|
||||
Date: 2014
|
||||
Genre: Video Game Music
|
||||
Title: VVVVVV Medley
|
||||
Time: 433
|
||||
duration: 432.727
|
||||
Pos: 1548
|
||||
Id: 1549";
|
||||
let s = deserialize_response(input_str.lines());
|
||||
println!("{:?}", s);
|
||||
}
|
|
@ -2,7 +2,7 @@ use helpers::*;
|
|||
use serde::Deserialize;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
#[derive(Deserialize, Clone, Debug, Default, PartialEq)]
|
||||
pub struct Track {
|
||||
pub file: String,
|
||||
pub artist_sort: Option<String>,
|
||||
|
@ -18,18 +18,20 @@ pub struct Track {
|
|||
pub track: Option<u32>,
|
||||
pub album: Option<String>,
|
||||
pub artist: Option<String>,
|
||||
pub pos: Option<u32>,
|
||||
pub id: Option<u32>,
|
||||
pub pos: u32,
|
||||
pub id: u32,
|
||||
// TODO: use proper time here
|
||||
#[serde(rename = "last-modified")]
|
||||
pub last_modified: Option<String>,
|
||||
pub original_date: Option<String>,
|
||||
pub time: Option<String>,
|
||||
pub original_date: Option<u16>,
|
||||
// probably not needed. it’s just the duration but as an int
|
||||
// pub time: u16,
|
||||
pub format: Option<String>,
|
||||
#[serde(deserialize_with = "de_time_float")]
|
||||
pub duration: Duration,
|
||||
pub label: Option<String>,
|
||||
pub date: Option<String>,
|
||||
pub disc: Option<u32>,
|
||||
pub date: Option<u16>,
|
||||
pub disc: Option<u16>,
|
||||
pub musicbraiz_trackid: Option<String>,
|
||||
pub musicbrainz_albumid: Option<String>,
|
||||
pub musicbrainz_albumartistid: Option<String>,
|
||||
|
|
Loading…
Reference in New Issue
Block a user