From d796f6762acb52cf2ab202d76382915064f0d534 Mon Sep 17 00:00:00 2001 From: alyx Date: Wed, 9 Aug 2023 00:44:10 -0400 Subject: API deserialization structs --- .gitignore | 4 ++ Cargo.toml | 8 +++ src/deserialize.rs | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/main.rs | 3 + 5 files changed, 189 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/deserialize.rs create mode 100644 src/lib.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e1193dd --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +*~ +.#* +\#* diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ab70ee6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "lfm_embed" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/deserialize.rs b/src/deserialize.rs new file mode 100644 index 0000000..4cedc9f --- /dev/null +++ b/src/deserialize.rs @@ -0,0 +1,173 @@ +use serde::{Deserialize, Deserializer, de}; +use serde_json::Value; + +use std::collections::HashMap; +use std::sync::Arc; + +fn str_num<'de, D, T>(d: D) -> Result where D: Deserializer<'de>, T: From { + struct Visitor; + impl<'v> de::Visitor<'v> for Visitor { + type Value = u64; + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "a value which can be interpreted as a uint") + } + fn visit_str(self, v: &str) -> Result + where + E: de::Error + { + v.parse().map_err(|_| de::Error::invalid_value(de::Unexpected::Str(v), &"a string which can be parsed as a uint")) + } + fn visit_u64(self, v: u64) -> Result + where + E: de::Error + { + Ok(v) + } + } + d.deserialize_any(Visitor).map(Into::into) +} +fn str_bool<'de, D, T>(d: D) -> Result where D: Deserializer<'de>, T: From{ + struct Visitor; + impl<'v> de::Visitor<'v> for Visitor { + type Value = bool; + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "a value which can be interpreted as a uint") + } + fn visit_str(self, v: &str) -> Result + where + E: de::Error + { + match v.to_ascii_lowercase().as_str() { + "true" | "1" => Ok(true), + "false" | "0" => Ok(false), + _ => Err(de::Error::invalid_value(de::Unexpected::Str(v), &"a string which can be parsed as a bool")) + } + } + fn visit_bool(self, v: bool) -> Result + where + E: de::Error + { + Ok(v) + } + } + d.deserialize_any(Visitor).map(Into::into) +} + + +#[derive(Deserialize, Debug)] +pub struct TimeStamp { + #[serde(alias = "unixtime")] + #[serde(alias = "uts")] + #[serde(deserialize_with = "str_num")] + pub unix_timestamp: u64, + #[serde(rename = "#text")] + pub text: Value +} + +#[derive(Deserialize, Debug)] +pub struct Artist { + #[serde(rename = "mbid")] + pub uuid: Arc, + #[serde(alias = "#text")] + pub name: Arc, + + #[serde(default)] + #[serde(rename = "image")] + pub images: Vec, + pub #[serde(default)] + url: Option> +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "lowercase")] +pub enum ImageSize { + Small, + Medium, + Large, + ExtraLarge +} + +#[derive(Deserialize, Debug)] +pub struct Image { + pub size: ImageSize, + #[serde(rename = "#text")] + pub url: Arc, +} + +#[derive(Deserialize, Debug)] +pub struct Album { + #[serde(rename = "mbid")] + pub uuid: Arc, + #[serde(rename = "#text")] + pub name: Arc, +} + +#[derive(Default, Deserialize, Debug)] +pub struct TrackAttr { + #[serde(default)] + #[serde(deserialize_with = "str_bool")] + pub nowplaying: bool, + #[serde(flatten)] + pub rest: HashMap, Value>, +} + +#[derive(Deserialize, Debug)] +pub struct Track { + pub artist: Artist, + #[serde(deserialize_with = "str_bool")] + pub streamable: bool, + #[serde(rename = "image")] + pub images: Vec, + #[serde(rename = "mbid")] + pub uuid: Arc, + pub album: Album, + pub name: Arc, + #[serde(rename = "@attr")] + #[serde(default)] + pub attr: TrackAttr, + pub url: Arc, + + #[serde(default)] + #[serde(deserialize_with = "str_bool")] + pub loved: Option, + #[serde(default)] + pub date: Option +} + +#[derive(Deserialize, Debug)] +pub struct RecentTracks { + pub track: Vec +} +#[derive(Deserialize, Debug)] +pub struct GetRecentTracks { + pub recenttracks: RecentTracks +} + +#[derive(Deserialize, Debug)] +pub struct User { + pub name: Arc, + #[serde(deserialize_with = "str_bool")] + pub subscriber: bool, + pub realname: Arc, + #[serde(deserialize_with = "str_num")] + pub playcount: u64, + #[serde(deserialize_with = "str_num")] + pub artist_count: u64, + #[serde(deserialize_with = "str_num")] + pub playlists: u64, + #[serde(deserialize_with = "str_num")] + pub track_count: u64, + #[serde(deserialize_with = "str_num")] + pub album_count: u64, + + #[serde(rename = "image")] + pub images: Vec, + + pub registered: TimeStamp, + pub url: Arc +} + +#[derive(Deserialize, Debug)] +pub struct GetUserInfo { + pub user: User +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..5d0a682 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +mod deserialize; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} -- cgit v1.2.3-70-g09d2