simplify with .into_iter()
This commit is contained in:
@@ -5,7 +5,7 @@ use chrono::{DateTime, FixedOffset};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Id(pub String);
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -287,7 +287,7 @@ pub enum Response {
|
||||
Entity,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum DataType {
|
||||
Manga,
|
||||
Chapter,
|
||||
@@ -397,7 +397,7 @@ struct ChapterContent {
|
||||
struct ChapterAttributesContent {
|
||||
volume: Option<String>,
|
||||
chapter: Option<String>,
|
||||
title: String,
|
||||
title: Option<String>,
|
||||
translated_language: String,
|
||||
external_url: Option<String>,
|
||||
publish_at: String,
|
||||
@@ -420,7 +420,7 @@ pub struct Chapter {
|
||||
pub struct ChapterAttributes {
|
||||
pub volume: Option<f32>,
|
||||
pub chapter: Option<f32>,
|
||||
pub title: String,
|
||||
pub title: Option<String>,
|
||||
pub translated_language: Language,
|
||||
pub external_url: Option<String>,
|
||||
pub published_at: DateTime<FixedOffset>,
|
||||
@@ -540,8 +540,8 @@ struct ContentRelationship {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChapterRelationship {
|
||||
id: Id,
|
||||
data_type: DataType,
|
||||
pub id: Id,
|
||||
pub data_type: DataType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -941,19 +941,11 @@ impl TryFrom<SearchResponse> for SearchResult {
|
||||
.try_into()
|
||||
.map_err(|_| ResponseConversionError::Result(search_response.result))?;
|
||||
|
||||
let mut data: Result<Vec<Manga>, ResponseConversionError> =
|
||||
Ok(Vec::with_capacity(search_response.data.len()));
|
||||
for m in search_response.data {
|
||||
if let Ok(ref mut d) = data {
|
||||
match m.try_into() {
|
||||
Ok(v) => d.push(v),
|
||||
Err(e) => {
|
||||
data = Err(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let data: Result<Vec<Manga>, Self::Error> = search_response
|
||||
.data
|
||||
.into_iter()
|
||||
.map(|m| m.try_into())
|
||||
.collect();
|
||||
Ok(SearchResult {
|
||||
response,
|
||||
result,
|
||||
@@ -1235,7 +1227,7 @@ impl TryFrom<ContentAttributes> for MangaAttributes {
|
||||
links: attributes.links,
|
||||
original_language: (attributes.original_language.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| AttributeConversionError::Language(attributes.original_language))?,
|
||||
.map_err(|_| Self::Error::Language(attributes.original_language))?,
|
||||
last_volume: match attributes.last_volume {
|
||||
Some(s) => match s.parse() {
|
||||
Ok(v) => Some(v),
|
||||
@@ -1243,7 +1235,7 @@ impl TryFrom<ContentAttributes> for MangaAttributes {
|
||||
if s.is_empty() {
|
||||
None
|
||||
} else {
|
||||
return Err(AttributeConversionError::LastVolume(s));
|
||||
return Err(Self::Error::LastVolume(s));
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1256,7 +1248,7 @@ impl TryFrom<ContentAttributes> for MangaAttributes {
|
||||
if n.is_empty() {
|
||||
None
|
||||
} else {
|
||||
return Err(AttributeConversionError::LastVolume(n));
|
||||
return Err(Self::Error::LastVolume(n));
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1266,56 +1258,43 @@ impl TryFrom<ContentAttributes> for MangaAttributes {
|
||||
Some(s) => Some(
|
||||
(s.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| AttributeConversionError::PublicationDemographic(s))?,
|
||||
.map_err(|_| Self::Error::PublicationDemographic(s))?,
|
||||
),
|
||||
None => None,
|
||||
},
|
||||
status: (attributes.status.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| AttributeConversionError::Status(attributes.status))?,
|
||||
.map_err(|_| Self::Error::Status(attributes.status))?,
|
||||
year: attributes.year,
|
||||
content_rating: attributes
|
||||
.content_rating
|
||||
.as_str()
|
||||
.try_into()
|
||||
.map_err(|_| AttributeConversionError::ContentRating(attributes.content_rating))?,
|
||||
tags: {
|
||||
let mut tags = Vec::with_capacity(attributes.tags.len());
|
||||
for m in attributes.tags {
|
||||
tags.push(({
|
||||
|| {
|
||||
Ok::<Tag, AttributeConversionError>(Tag {
|
||||
.map_err(|_| Self::Error::ContentRating(attributes.content_rating))?,
|
||||
tags: attributes
|
||||
.tags
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
Ok(Tag {
|
||||
data_type: (m.type_name.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| AttributeConversionError::DataType(m.type_name))?,
|
||||
.map_err(|_| Self::Error::DataType(m.type_name))?,
|
||||
id: Id(m.id),
|
||||
relationships: {
|
||||
let mut relationships =
|
||||
Vec::with_capacity(m.relationships.len());
|
||||
for m in m.relationships {
|
||||
relationships.push(({
|
||||
|| {
|
||||
Ok::<Relationship, AttributeConversionError>(
|
||||
Relationship {
|
||||
id: Id(m.id),
|
||||
data_type: (m.type_name.as_str())
|
||||
relationships: m
|
||||
.relationships
|
||||
.into_iter()
|
||||
.map(|r| {
|
||||
Ok::<Relationship, Self::Error>(Relationship {
|
||||
id: Id(r.id),
|
||||
data_type: (r.type_name.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| {
|
||||
AttributeConversionError::DataType(
|
||||
m.type_name,
|
||||
)
|
||||
})?,
|
||||
.map_err(|_| Self::Error::DataType(r.type_name))?,
|
||||
// TODO: Do this
|
||||
attributes: None,
|
||||
related: m.related,
|
||||
},
|
||||
)
|
||||
}
|
||||
})(
|
||||
)?);
|
||||
}
|
||||
relationships
|
||||
},
|
||||
related: r.related,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<Relationship>, Self::Error>>()?,
|
||||
attributes: TagAttributes {
|
||||
name: m.attributes.name,
|
||||
group: m.attributes.group,
|
||||
@@ -1326,39 +1305,31 @@ impl TryFrom<ContentAttributes> for MangaAttributes {
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
})()?);
|
||||
}
|
||||
tags
|
||||
},
|
||||
})
|
||||
.collect::<Result<Vec<Tag>, Self::Error>>()?,
|
||||
state: (attributes.state.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| AttributeConversionError::State(attributes.state))?,
|
||||
.map_err(|_| Self::Error::State(attributes.state))?,
|
||||
chapter_numbers_reset_on_new_volume: attributes.chapter_numbers_reset_on_new_volume,
|
||||
created_at: DateTime::parse_from_rfc3339(&attributes.created_at).map_err(|_| {
|
||||
AttributeConversionError::CreatedAtDateTime(attributes.created_at.clone())
|
||||
})?,
|
||||
created_at: DateTime::parse_from_rfc3339(&attributes.created_at)
|
||||
.map_err(|_| Self::Error::CreatedAtDateTime(attributes.created_at.clone()))?,
|
||||
updated_at: DateTime::parse_from_rfc3339(&attributes.updated_at)
|
||||
.map_err(|_| AttributeConversionError::UpdatedAtDateTime(attributes.created_at))?,
|
||||
.map_err(|_| Self::Error::UpdatedAtDateTime(attributes.created_at))?,
|
||||
version: attributes.version,
|
||||
available_translated_languages: {
|
||||
let mut av = Vec::with_capacity(attributes.available_translated_languages.len());
|
||||
for m in attributes.available_translated_languages {
|
||||
av.push(({
|
||||
|| {
|
||||
Ok::<Option<Language>, AttributeConversionError>(match m {
|
||||
available_translated_languages: attributes
|
||||
.available_translated_languages
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
Ok(match m {
|
||||
Some(s) => Some(
|
||||
(s.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| AttributeConversionError::Language(s))?,
|
||||
.map_err(|_| Self::Error::Language(s))?,
|
||||
),
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
})()?);
|
||||
}
|
||||
av
|
||||
},
|
||||
})
|
||||
.collect::<Result<Vec<Option<Language>>, Self::Error>>()?,
|
||||
latest_uploaded_chapter: attributes
|
||||
.latest_uploaded_chapter
|
||||
.as_ref()
|
||||
@@ -1368,6 +1339,7 @@ impl TryFrom<ContentAttributes> for MangaAttributes {
|
||||
}
|
||||
|
||||
pub fn deserialize_id_query(json: &str) -> Result<IdQueryResult, IdQueryResultError> {
|
||||
std::fs::write("id_query.json", json).unwrap();
|
||||
let id_query_response: IdQueryResponse = serde_json::from_str(json)
|
||||
.map_err(|e| IdQueryResultError::Serde(JsonError::Message(e.to_string())))?;
|
||||
id_query_response
|
||||
@@ -1383,16 +1355,13 @@ impl TryFrom<IdQueryResponse> for IdQueryResult {
|
||||
.result
|
||||
.as_str()
|
||||
.try_into()
|
||||
.map_err(|_| IdQueryResponseError::Result)?,
|
||||
.map_err(|_| Self::Error::Result)?,
|
||||
response: response
|
||||
.response
|
||||
.as_str()
|
||||
.try_into()
|
||||
.map_err(|_| IdQueryResponseError::Response)?,
|
||||
data: response
|
||||
.data
|
||||
.try_into()
|
||||
.map_err(IdQueryResponseError::Data)?,
|
||||
.map_err(|_| Self::Error::Response)?,
|
||||
data: response.data.try_into().map_err(Self::Error::Data)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1422,14 +1391,18 @@ impl TryFrom<ChapterFeedResponse> for ChapterFeed {
|
||||
type Error = ChapterFeedConversionError;
|
||||
|
||||
fn try_from(feed: ChapterFeedResponse) -> Result<Self, Self::Error> {
|
||||
// Now this is a bit of an abomination. It uses closures such that you can use the ? syntax
|
||||
// sugar to return an error. Also uses for loops instead of iterators since they do not take
|
||||
// ownership. I think I should have just kept the iterators.
|
||||
let mut data: Vec<Chapter> = Vec::with_capacity(feed.data.len());
|
||||
for m in feed.data {
|
||||
let chapter: Chapter = ({
|
||||
|| {
|
||||
Ok::<Chapter, ChapterConversionError>(Chapter {
|
||||
Ok(ChapterFeed {
|
||||
result: (feed.result.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| Self::Error::Result(feed.result))?,
|
||||
response: (feed.response.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| Self::Error::Result(feed.response))?,
|
||||
data: feed
|
||||
.data
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
Ok(Chapter {
|
||||
data_type: (m.type_name.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| ChapterConversionError::DataType(m.type_name))?,
|
||||
@@ -1438,45 +1411,22 @@ impl TryFrom<ChapterFeedResponse> for ChapterFeed {
|
||||
.attributes
|
||||
.try_into()
|
||||
.map_err(ChapterConversionError::Attributes)?,
|
||||
relationships: {
|
||||
let mut relationships = Vec::with_capacity(m.relationships.len());
|
||||
for r in m.relationships {
|
||||
relationships.push(
|
||||
({
|
||||
|| {
|
||||
Ok({
|
||||
ChapterRelationship {
|
||||
data_type: (r.type_name.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| {
|
||||
ChapterRelationshipError::TypeData(
|
||||
r.type_name,
|
||||
)
|
||||
relationships: m
|
||||
.relationships
|
||||
.into_iter()
|
||||
.map(|r| {
|
||||
Ok(ChapterRelationship {
|
||||
data_type: (r.type_name.as_str()).try_into().map_err(|_| {
|
||||
ChapterRelationshipError::TypeData(r.type_name)
|
||||
})?,
|
||||
id: Id(r.id),
|
||||
}
|
||||
})
|
||||
}
|
||||
})()
|
||||
})
|
||||
.collect::<Result<Vec<ChapterRelationship>, ChapterRelationshipError>>()
|
||||
.map_err(ChapterConversionError::Relationship)?,
|
||||
);
|
||||
}
|
||||
relationships
|
||||
},
|
||||
})
|
||||
}
|
||||
})()
|
||||
.map_err(ChapterFeedConversionError::Chapter)?;
|
||||
data.push(chapter);
|
||||
}
|
||||
Ok(ChapterFeed {
|
||||
result: (feed.result.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| ChapterFeedConversionError::Result(feed.result))?,
|
||||
response: (feed.response.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| ChapterFeedConversionError::Result(feed.response))?,
|
||||
data,
|
||||
})
|
||||
.collect::<Result<Vec<Chapter>, Self::Error>>()?,
|
||||
limit: feed.limit,
|
||||
offset: feed.offset,
|
||||
total: feed.total,
|
||||
@@ -1491,33 +1441,29 @@ impl TryFrom<ChapterAttributesContent> for ChapterAttributes {
|
||||
volume: match &attributes.volume {
|
||||
Some(v) => match v.parse() {
|
||||
Ok(n) => Some(n),
|
||||
Err(_) => return Err(ChapterAttributeConversionError::Volume(v.to_owned())),
|
||||
Err(_) => return Err(Self::Error::Volume(v.to_owned())),
|
||||
},
|
||||
None => None,
|
||||
},
|
||||
chapter: match &attributes.chapter {
|
||||
Some(v) => match v.parse() {
|
||||
Ok(v) => Some(v),
|
||||
Err(_) => return Err(ChapterAttributeConversionError::Chapter(v.to_owned())),
|
||||
Err(_) => return Err(Self::Error::Chapter(v.to_owned())),
|
||||
},
|
||||
None => None,
|
||||
},
|
||||
created_at: DateTime::parse_from_rfc3339(&attributes.created_at)
|
||||
.map_err(|_| ChapterAttributeConversionError::CreatedAt(attributes.created_at))?,
|
||||
.map_err(|_| Self::Error::CreatedAt(attributes.created_at))?,
|
||||
published_at: DateTime::parse_from_rfc3339(&attributes.publish_at)
|
||||
.map_err(|_| ChapterAttributeConversionError::CreatedAt(attributes.publish_at))?,
|
||||
.map_err(|_| Self::Error::CreatedAt(attributes.publish_at))?,
|
||||
updated_at: DateTime::parse_from_rfc3339(&attributes.updated_at)
|
||||
.map_err(|_| ChapterAttributeConversionError::CreatedAt(attributes.updated_at))?,
|
||||
.map_err(|_| Self::Error::CreatedAt(attributes.updated_at))?,
|
||||
external_url: attributes.external_url,
|
||||
title: attributes.title,
|
||||
pages: attributes.pages,
|
||||
translated_language: (attributes.translated_language.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| {
|
||||
ChapterAttributeConversionError::TranslatedLanguage(
|
||||
attributes.translated_language,
|
||||
)
|
||||
})?,
|
||||
.map_err(|_| Self::Error::TranslatedLanguage(attributes.translated_language))?,
|
||||
version: attributes.version,
|
||||
})
|
||||
}
|
||||
@@ -1529,7 +1475,7 @@ impl TryFrom<ChapterImagesContent> for ChapterImages {
|
||||
Ok(ChapterImages {
|
||||
result: (data.result.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| ChapterImageError::Result(data.result))?,
|
||||
.map_err(|_| Self::Error::Result(data.result))?,
|
||||
base_url: data.base_url,
|
||||
chapter: ChapterImageData {
|
||||
hash: data.chapter.hash,
|
||||
@@ -1562,23 +1508,20 @@ impl TryFrom<ContentData> for Manga {
|
||||
Ok(Manga {
|
||||
id: Id(m.id),
|
||||
data_type: (m.type_name.as_str()).try_into().map_err(|_| {
|
||||
ResponseConversionError::Attribute(AttributeConversionError::DataType(m.type_name))
|
||||
Self::Error::Attribute(AttributeConversionError::DataType(m.type_name))
|
||||
})?,
|
||||
attributes: m
|
||||
.attributes
|
||||
.try_into()
|
||||
.map_err(ResponseConversionError::Attribute)?,
|
||||
relationships: {
|
||||
let mut relationships = Vec::with_capacity(m.relationships.len());
|
||||
for m in m.relationships {
|
||||
relationships.push(
|
||||
({
|
||||
|| {
|
||||
Ok::<Relationship, AttributeConversionError>(Relationship {
|
||||
attributes: m.attributes.try_into().map_err(Self::Error::Attribute)?,
|
||||
relationships: m
|
||||
.relationships
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
Ok(Relationship {
|
||||
id: Id(m.id),
|
||||
data_type: m.type_name.as_str().try_into().map_err(|_| {
|
||||
AttributeConversionError::DataType(m.type_name)
|
||||
})?,
|
||||
data_type: m
|
||||
.type_name
|
||||
.as_str()
|
||||
.try_into()
|
||||
.map_err(|_| AttributeConversionError::DataType(m.type_name))?,
|
||||
attributes: {
|
||||
if let Some(attributes) = m.attributes {
|
||||
Some(CoverAttributes {
|
||||
@@ -1601,13 +1544,13 @@ impl TryFrom<ContentData> for Manga {
|
||||
// TODO: Something should probably be done here
|
||||
description: attributes.description,
|
||||
file_name: Id(attributes.file_name.clone()),
|
||||
locale: (attributes.locale.as_str())
|
||||
.try_into()
|
||||
.map_err(|_| {
|
||||
locale: (attributes.locale.as_str()).try_into().map_err(
|
||||
|_| {
|
||||
AttributeConversionError::Locale(
|
||||
attributes.locale.clone(),
|
||||
)
|
||||
})?,
|
||||
},
|
||||
)?,
|
||||
version: attributes.version,
|
||||
volume: match &attributes.volume {
|
||||
Some(v) => v.parse().ok(),
|
||||
@@ -1620,13 +1563,8 @@ impl TryFrom<ContentData> for Manga {
|
||||
},
|
||||
related: m.related.clone(),
|
||||
})
|
||||
}
|
||||
})()
|
||||
.map_err(ResponseConversionError::Attribute)?,
|
||||
);
|
||||
}
|
||||
relationships
|
||||
},
|
||||
})
|
||||
.collect::<Result<Vec<Relationship>, AttributeConversionError>>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1638,24 +1576,32 @@ mod tests {
|
||||
#[test]
|
||||
fn id_query() {
|
||||
let manga = std::fs::read_to_string("test_data/id_query_hunter_x_hunter.json").unwrap();
|
||||
assert_eq!(deserialize_id_query(&manga).unwrap().result , ResponseResult::Ok);
|
||||
assert_eq!(
|
||||
deserialize_id_query(&manga).unwrap().result,
|
||||
ResponseResult::Ok
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn search() {
|
||||
let search_result = std::fs::read_to_string("test_data/search_result.json").unwrap();
|
||||
assert_eq!(deserialize_search(&search_result).unwrap().result , ResponseResult::Ok);
|
||||
assert_eq!(
|
||||
deserialize_search(&search_result).unwrap().result,
|
||||
ResponseResult::Ok
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chapter_feed() {
|
||||
let chapter_feed = std::fs::read_to_string("test_data/chapter_feed_hunter_x_hunter.json").unwrap();
|
||||
let chapter_feed =
|
||||
std::fs::read_to_string("test_data/chapter_feed_hunter_x_hunter.json").unwrap();
|
||||
deserialize_chapter_feed(&chapter_feed).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chapter_images() {
|
||||
let chapter_images = std::fs::read_to_string("test_data/chapter_images_hunter_x_hunter.json").unwrap();
|
||||
let chapter_images =
|
||||
std::fs::read_to_string("test_data/chapter_images_hunter_x_hunter.json").unwrap();
|
||||
deserialize_chapter_images(&chapter_images).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user