Do not implement deserialize for core types
This commit is contained in:
parent
76173e0468
commit
0e97f26b6e
170
src/external/musicbrainz/mod.rs
vendored
170
src/external/musicbrainz/mod.rs
vendored
@ -119,7 +119,8 @@ impl<Http: IMusicBrainzHttp> MusicBrainzClient<Http> {
|
|||||||
form_urlencoded::byte_serialize(query.join(" AND ").as_bytes()).collect();
|
form_urlencoded::byte_serialize(query.join(" AND ").as_bytes()).collect();
|
||||||
let url = format!("{MB_BASE_URL}/release-group?query={query}");
|
let url = format!("{MB_BASE_URL}/release-group?query={query}");
|
||||||
|
|
||||||
Ok(self.http.get(&url)?)
|
let response: DeserializeSearchReleaseGroupResponse = self.http.get(&url)?;
|
||||||
|
Ok(response.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,29 +154,71 @@ impl<'a> SearchReleaseGroupRequest<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Separate deserialize types from internal types like in JSON code.
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
|
||||||
pub struct SearchReleaseGroupResponse {
|
pub struct SearchReleaseGroupResponse {
|
||||||
pub release_groups: Vec<SearchReleaseGroupResponseUnit>,
|
pub release_groups: Vec<SearchReleaseGroupResponseUnit>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||||
|
struct DeserializeSearchReleaseGroupResponse {
|
||||||
|
release_groups: Vec<DeserializeSearchReleaseGroupResponseUnit>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DeserializeSearchReleaseGroupResponse> for SearchReleaseGroupResponse {
|
||||||
|
fn from(value: DeserializeSearchReleaseGroupResponse) -> Self {
|
||||||
|
SearchReleaseGroupResponse {
|
||||||
|
release_groups: value.release_groups.into_iter().map(Into::into).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SearchReleaseGroupResponseUnit {
|
pub struct SearchReleaseGroupResponseUnit {
|
||||||
pub score: u8,
|
pub score: u8,
|
||||||
pub id: Mbid,
|
pub id: Mbid,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub first_release_date: AlbumDate,
|
pub first_release_date: AlbumDate,
|
||||||
#[serde(with = "AlbumPrimaryTypeDef")]
|
|
||||||
pub primary_type: AlbumPrimaryType,
|
pub primary_type: AlbumPrimaryType,
|
||||||
pub secondary_types: Option<Vec<AlbumSecondaryType>>,
|
pub secondary_types: Option<Vec<AlbumSecondaryType>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MbidVisitor;
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||||
|
struct DeserializeSearchReleaseGroupResponseUnit {
|
||||||
|
score: u8,
|
||||||
|
id: SerdeMbid,
|
||||||
|
title: String,
|
||||||
|
first_release_date: SerdeAlbumDate,
|
||||||
|
primary_type: SerdeAlbumPrimaryType,
|
||||||
|
secondary_types: Option<Vec<SerdeAlbumSecondaryType>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for MbidVisitor {
|
impl From<DeserializeSearchReleaseGroupResponseUnit> for SearchReleaseGroupResponseUnit {
|
||||||
type Value = Mbid;
|
fn from(value: DeserializeSearchReleaseGroupResponseUnit) -> Self {
|
||||||
|
SearchReleaseGroupResponseUnit {
|
||||||
|
score: value.score,
|
||||||
|
id: value.id.into(),
|
||||||
|
title: value.title,
|
||||||
|
first_release_date: value.first_release_date.into(),
|
||||||
|
primary_type: value.primary_type.into(),
|
||||||
|
secondary_types: value
|
||||||
|
.secondary_types
|
||||||
|
.map(|v| v.into_iter().map(Into::into).collect()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerdeMbid(Mbid);
|
||||||
|
|
||||||
|
impl From<SerdeMbid> for Mbid {
|
||||||
|
fn from(value: SerdeMbid) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SerdeMbidVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for SerdeMbidVisitor {
|
||||||
|
type Value = SerdeMbid;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.write_str("a valid MusicBrainz identifier")
|
formatter.write_str("a valid MusicBrainz identifier")
|
||||||
@ -185,24 +228,34 @@ impl<'de> Visitor<'de> for MbidVisitor {
|
|||||||
where
|
where
|
||||||
E: serde::de::Error,
|
E: serde::de::Error,
|
||||||
{
|
{
|
||||||
Ok(v.try_into()
|
Ok(SerdeMbid(
|
||||||
.map_err(|e: MbidError| E::custom(e.to_string()))?)
|
v.try_into()
|
||||||
|
.map_err(|e: MbidError| E::custom(e.to_string()))?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Mbid {
|
impl<'de> Deserialize<'de> for SerdeMbid {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
deserializer.deserialize_str(MbidVisitor)
|
deserializer.deserialize_str(SerdeMbidVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AlbumDateVisitor;
|
pub struct SerdeAlbumDate(AlbumDate);
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for AlbumDateVisitor {
|
impl From<SerdeAlbumDate> for AlbumDate {
|
||||||
type Value = AlbumDate;
|
fn from(value: SerdeAlbumDate) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SerdeAlbumDateVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for SerdeAlbumDateVisitor {
|
||||||
|
type Value = SerdeAlbumDate;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.write_str("a valid YYYY(-MM-(-DD)) date")
|
formatter.write_str("a valid YYYY(-MM-(-DD)) date")
|
||||||
@ -232,16 +285,16 @@ impl<'de> Visitor<'de> for AlbumDateVisitor {
|
|||||||
.transpose()
|
.transpose()
|
||||||
.map_err(|e: ParseIntError| E::custom(e.to_string()))?;
|
.map_err(|e: ParseIntError| E::custom(e.to_string()))?;
|
||||||
|
|
||||||
Ok(AlbumDate::new(year, month, day))
|
Ok(SerdeAlbumDate(AlbumDate::new(year, month, day)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for AlbumDate {
|
impl<'de> Deserialize<'de> for SerdeAlbumDate {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
deserializer.deserialize_str(AlbumDateVisitor)
|
deserializer.deserialize_str(SerdeAlbumDateVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,47 +309,54 @@ pub enum AlbumPrimaryTypeDef {
|
|||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
// AlbumSecondaryType is implemented manually because deserializing to a remote type is not (yet)
|
#[derive(Debug, Deserialize)]
|
||||||
// supported for Option/Vec/Map by serde: https://github.com/serde-rs/serde/issues/723.
|
pub struct SerdeAlbumPrimaryType(#[serde(with = "AlbumPrimaryTypeDef")] AlbumPrimaryType);
|
||||||
struct AlbumSecondaryTypeVisitor;
|
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for AlbumSecondaryTypeVisitor {
|
impl From<SerdeAlbumPrimaryType> for AlbumPrimaryType {
|
||||||
type Value = AlbumSecondaryType;
|
fn from(value: SerdeAlbumPrimaryType) -> Self {
|
||||||
|
value.0
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
formatter.write_str("a valid MusicBrainz album secondary type")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: serde::de::Error,
|
|
||||||
{
|
|
||||||
let variant = match v {
|
|
||||||
"Compilation" => AlbumSecondaryType::Compilation,
|
|
||||||
"Soundtrack" => AlbumSecondaryType::Soundtrack,
|
|
||||||
"Spokenword" => AlbumSecondaryType::Spokenword,
|
|
||||||
"Interview" => AlbumSecondaryType::Interview,
|
|
||||||
"Audiobook" => AlbumSecondaryType::Audiobook,
|
|
||||||
"Audio drama" => AlbumSecondaryType::AudioDrama,
|
|
||||||
"Live" => AlbumSecondaryType::Live,
|
|
||||||
"Remix" => AlbumSecondaryType::Remix,
|
|
||||||
"DJ-mix" => AlbumSecondaryType::DjMix,
|
|
||||||
"Mixtape/Street" => AlbumSecondaryType::MixtapeStreet,
|
|
||||||
"Demo" => AlbumSecondaryType::Demo,
|
|
||||||
"Field recording" => AlbumSecondaryType::FieldRecording,
|
|
||||||
_ => return Err(E::custom(format!("unknown album secondary type: {v}"))),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(variant)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for AlbumSecondaryType {
|
impl From<AlbumPrimaryType> for SerdeAlbumPrimaryType {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn from(value: AlbumPrimaryType) -> Self {
|
||||||
where
|
SerdeAlbumPrimaryType(value)
|
||||||
D: Deserializer<'de>,
|
}
|
||||||
{
|
}
|
||||||
deserializer.deserialize_str(AlbumSecondaryTypeVisitor)
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(remote = "AlbumSecondaryType")]
|
||||||
|
pub enum AlbumSecondaryTypeDef {
|
||||||
|
Compilation,
|
||||||
|
Soundtrack,
|
||||||
|
Spokenword,
|
||||||
|
Interview,
|
||||||
|
Audiobook,
|
||||||
|
#[serde(rename = "Audio drama")]
|
||||||
|
AudioDrama,
|
||||||
|
Live,
|
||||||
|
Remix,
|
||||||
|
#[serde(rename = "DJ-mix")]
|
||||||
|
DjMix,
|
||||||
|
#[serde(rename = "Mixtape/Street")]
|
||||||
|
MixtapeStreet,
|
||||||
|
Demo,
|
||||||
|
#[serde(rename = "Field recording")]
|
||||||
|
FieldRecording,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct SerdeAlbumSecondaryType(#[serde(with = "AlbumSecondaryTypeDef")] AlbumSecondaryType);
|
||||||
|
|
||||||
|
impl From<SerdeAlbumSecondaryType> for AlbumSecondaryType {
|
||||||
|
fn from(value: SerdeAlbumSecondaryType) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AlbumSecondaryType> for SerdeAlbumSecondaryType {
|
||||||
|
fn from(value: AlbumSecondaryType) -> Self {
|
||||||
|
SerdeAlbumSecondaryType(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user