use crate::general::{Date, DbTag, PersonId};
use crate::parsing::{read_vec_node, read_node, read_string, UnexpectedTags};
use crate::parsing::{XmlNode, XmlVecNode};
use quick_xml::events::{BytesStart, Event};
use quick_xml::Reader;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "lowercase")]
pub enum ArticleId {
PubMed(PubMedId),
Medline(MedlineUID),
DOI(DOI),
PmcId(PmcID),
PmPid(PmPid),
Other(DbTag),
}
pub type PubMedId = u64;
pub type MedlineUID = u64;
pub type DOI = String;
pub type PII = String;
pub type PmcID = u64;
pub type PmcPid = String;
pub type PmPid = String;
pub type ArticleIdSet = Vec<ArticleId>;
#[derive(Clone, Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum PubStatus {
Received = 1,
Accepted,
EPublish,
PPublish,
Revised,
PMC,
PMCR,
PubMed,
PubMedR,
AheadOfPrint,
PreMedline,
Medline,
Other = 255,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct PubStatusDate {
pub pubstatus: PubStatus,
pub date: Date,
}
pub type PubStatusDateSet = Vec<PubStatusDate>;
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "lowercase")]
pub enum CitArtFrom {
Journal(CitJour),
Book(CitBook),
Proc(CitProc),
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct CitArt {
pub title: Option<Title>,
pub authors: Option<AuthList>,
pub from: CitArtFrom,
pub ids: Option<ArticleIdSet>,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct CitJour {
pub title: Title,
pub imp: Imprint,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct CitBook {
pub title: Title,
pub coll: Option<Title>,
pub authors: AuthList,
pub imp: Imprint,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct CitProc {
pub book: CitBook,
pub meet: Meeting,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct CitPat {
pub title: String,
pub authors: AuthList,
pub country: String,
pub doc_type: String,
pub number: Option<String>,
pub date_issue: Option<Date>,
pub class: Option<Vec<String>>,
pub app_number: Option<String>,
pub app_date: Option<Date>,
pub applicants: Option<AuthList>,
pub assignees: Option<AuthList>,
pub priority: Option<Vec<PatentPriority>>,
#[serde(rename = "abstract")]
pub r#abstract: Option<String>,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct PatentPriority {
pub country: String,
pub number: String,
pub date: Date,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "lowercase")]
pub enum IdPatChoice {
Number(String),
AppNumber(String),
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct IdPat {
pub country: String,
pub id: IdPatChoice,
pub doc_type: Option<String>,
}
#[derive(Clone, Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum CitLetType {
Manuscript = 1,
Letter,
Thesis,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct CitLet {
pub cit: CitBook,
pub man_id: Option<String>,
#[serde(rename = "type")]
pub r#type: CitLetType,
}
#[derive(Clone, Serialize_repr, Deserialize_repr, PartialEq, Debug, Default)]
#[repr(u8)]
pub enum CitSubMedium {
#[default]
Paper = 1,
Tape,
Floppy,
Email,
Other = 255,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct CitSub {
pub authors: AuthList,
pub imp: Option<Imprint>,
pub medium: CitSubMedium,
pub date: Option<Date>,
pub descr: Option<String>,
}
impl CitSub {
pub fn new(authors: AuthList) -> Self {
Self {
authors,
imp: None,
medium: Default::default(),
date: None,
descr: None,
}
}
}
impl XmlNode for CitSub {
fn start_bytes() -> BytesStart<'static> {
BytesStart::new("Cit-sub")
}
fn from_reader(reader: &mut Reader<&[u8]>) -> Option<Self>
where
Self: Sized,
{
let authors_element = BytesStart::new("Cit-sub_authors");
let date_element = BytesStart::new("Cit-sub_date");
let mut cit = CitSub::new(AuthList {
names: AuthListNames::Std(vec![]),
affil: None,
});
let forbidden = UnexpectedTags(&[]);
loop {
match reader.read_event().unwrap() {
Event::Start(e) => {
let name = e.name();
if name == authors_element.name() {
cit.authors = read_node(reader).unwrap();
} else if name == date_element.name() {
cit.date = read_node(reader);
} else if name != Self::start_bytes().name() {
forbidden.check(&name);
}
}
Event::End(e) => {
if Self::is_end(&e) {
break;
}
}
_ => (),
}
}
cit.into()
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug, Default)]
#[serde(rename_all = "kebab-case")]
pub struct CitGen {
pub cit: Option<String>,
pub authors: Option<AuthList>,
pub muid: Option<u64>,
pub journal: Option<Title>,
pub volume: Option<String>,
pub issue: Option<String>,
pub pages: Option<String>,
pub date: Option<Date>,
pub serial_number: Option<u64>,
pub title: Option<String>,
pub pmid: Option<PubMedId>,
}
impl XmlNode for CitGen {
fn start_bytes() -> BytesStart<'static> {
BytesStart::new("Cit-gen")
}
fn from_reader(reader: &mut Reader<&[u8]>) -> Option<Self>
where
Self: Sized,
{
let mut gen = CitGen::default();
let cit_element = BytesStart::new("Cit-gen_cit");
let authors_element = BytesStart::new("Cit-gen_authors");
let title_element = BytesStart::new("Cit-gen_title");
let forbidden = UnexpectedTags(&[]);
loop {
match reader.read_event().unwrap() {
Event::Start(e) => {
let name = e.name();
if name == cit_element.name() {
gen.cit = read_string(reader);
} else if name == title_element.name() {
gen.title = read_string(reader);
} else if name == authors_element.name() {
gen.authors = read_node(reader);
} else if name != Self::start_bytes().name() {
forbidden.check(&name)
}
}
Event::End(e) => {
if Self::is_end(&e) {
return gen.into();
}
}
_ => (),
}
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "lowercase")]
pub enum AuthListNames {
Std(Vec<Author>),
Ml(Vec<String>),
Str(Vec<String>),
}
impl Default for AuthListNames {
fn default() -> Self {
Self::Str(vec![])
}
}
impl XmlNode for AuthListNames {
fn start_bytes() -> BytesStart<'static> {
BytesStart::new("Auth-list_names")
}
fn from_reader(reader: &mut Reader<&[u8]>) -> Option<Self>
where
Self: Sized,
{
let std_element = BytesStart::new("Auth-list_names_std");
let forbidden = UnexpectedTags(&[]);
loop {
match reader.read_event().unwrap() {
Event::Start(e) => {
let name = e.name();
if name == std_element.name() {
return Self::Std(read_vec_node(reader, std_element.to_end())).into();
} else if name == Self::start_bytes().name() {
forbidden.check(&name);
}
}
Event::End(e) => {
if Self::is_end(&e) {
return None;
}
}
_ => (),
}
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug, Default)]
pub struct AuthList {
pub names: AuthListNames,
pub affil: Option<Affil>,
}
impl XmlNode for AuthList {
fn start_bytes() -> BytesStart<'static> {
BytesStart::new("Auth-list")
}
fn from_reader(reader: &mut Reader<&[u8]>) -> Option<Self>
where
Self: Sized,
{
let mut list = AuthList::default();
let names_element = BytesStart::new("Auth-list_names");
let affil_element = BytesStart::new("Auth-list_affil");
let forbidden = UnexpectedTags(&[]);
loop {
match reader.read_event().unwrap() {
Event::Start(e) => {
let name = e.name();
if name == names_element.name() {
list.names = read_node(reader).unwrap();
} else if name == affil_element.name() {
list.affil = read_node(reader);
} else if name != Self::start_bytes().name() {
forbidden.check(&name);
}
}
Event::End(e) => {
if Self::is_end(&e) {
return list.into();
}
}
_ => (),
}
}
}
}
#[derive(Clone, Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum AuthorLevel {
Primary = 1,
Secondary,
}
#[derive(Clone, Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum AuthorRole {
Compiler = 1,
Editor,
PatentAssignee,
Translator,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Author {
pub name: PersonId,
pub level: Option<AuthorLevel>,
pub role: Option<AuthorRole>,
pub affil: Option<Affil>,
pub is_corr: Option<bool>,
}
impl Author {
pub fn new(name: PersonId) -> Self {
Self {
name,
level: None,
role: None,
affil: None,
is_corr: None,
}
}
}
impl XmlNode for Author {
fn start_bytes() -> BytesStart<'static> {
BytesStart::new("Author")
}
fn from_reader(reader: &mut Reader<&[u8]>) -> Option<Self>
where
Self: Sized,
{
let mut author = Author::new(PersonId::default());
let name_element = BytesStart::new("Author_name");
let forbidden = UnexpectedTags(&[]);
loop {
match reader.read_event().unwrap() {
Event::Start(e) => {
let name = e.name();
if name == name_element.name() {
author.name = read_node(reader).unwrap();
} else {
forbidden.check(&name);
}
}
Event::End(e) => {
if Self::is_end(&e) {
return author.into();
}
}
_ => (),
}
}
}
}
impl XmlVecNode for Author {}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug, Default)]
#[serde(rename_all = "kebab-case")]
pub struct AffilStd {
pub affil: Option<String>,
pub div: Option<String>,
pub city: Option<String>,
pub sub: Option<String>,
pub country: Option<String>,
pub street: Option<String>,
pub email: Option<String>,
pub fax: Option<String>,
pub phone: Option<String>,
pub postal_code: Option<String>,
}
impl XmlNode for AffilStd {
fn start_bytes() -> BytesStart<'static> {
BytesStart::new("Affil_std")
}
fn from_reader(reader: &mut Reader<&[u8]>) -> Option<Self>
where
Self: Sized,
{
let mut affil = AffilStd::default();
let affil_element = BytesStart::new("Affil_std_affil");
let div_element = BytesStart::new("Affil_std_div");
let city_element = BytesStart::new("Affil_std_city");
let sub_element = BytesStart::new("Affil_std_sub");
let country_element = BytesStart::new("Affil_std_country");
let street_element = BytesStart::new("Affil_std_street");
let postal_code_element = BytesStart::new("Affil_std_postal-code");
let forbidden = UnexpectedTags(&[]);
loop {
match reader.read_event().unwrap() {
Event::Start(e) => {
let name = e.name();
if name == affil_element.name() {
affil.affil = read_string(reader);
} else if name == div_element.name() {
affil.div = read_string(reader);
} else if name == city_element.name() {
affil.city = read_string(reader);
} else if name == sub_element.name() {
affil.sub = read_string(reader);
} else if name == country_element.name() {
affil.country = read_string(reader);
} else if name == street_element.name() {
affil.street = read_string(reader);
} else if name == postal_code_element.name() {
affil.postal_code = read_string(reader);
} else if name != Self::start_bytes().name() {
forbidden.check(&name);
}
}
Event::End(e) => {
if Self::is_end(&e) {
return affil.into();
}
}
_ => (),
}
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "lowercase")]
pub enum Affil {
Str(String),
Std(AffilStd),
}
impl XmlNode for Affil {
fn start_bytes() -> BytesStart<'static> {
BytesStart::new("Affil")
}
fn from_reader(reader: &mut Reader<&[u8]>) -> Option<Self>
where
Self: Sized,
{
let str_element = BytesStart::new("Affil_str");
let std_element = BytesStart::new("Affil_std");
loop {
match reader.read_event().unwrap() {
Event::Start(e) => {
let name = e.name();
if name == std_element.name() {
return Self::Std(read_node(reader).unwrap()).into();
}
if name == str_element.name() {
return Self::Str(read_string(reader).unwrap()).into();
}
}
Event::End(e) => {
if Self::is_end(&e) {
return None;
}
}
_ => (),
}
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "lowercase")]
pub enum TitleItem {
Name(String),
TSub(String),
Trans(String),
Jta(String),
#[serde(rename = "iso-jta")]
IsoJta(String),
MlJta(String),
Coden(String),
ISSN(String),
Abr(String),
ISBN(String),
}
pub type Title = Vec<TitleItem>;
#[derive(Clone, Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum ImprintPrePub {
Submitted = 1,
InPress,
Other = 255,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Imprint {
pub date: Date,
pub volume: Option<String>,
pub issue: Option<String>,
pub pages: Option<String>,
pub section: Option<String>,
#[serde(rename = "pub")]
pub r#pub: Option<Affil>,
pub cprt: Option<Date>,
pub part_sup: Option<String>,
pub language: Option<String>,
pub prepub: Option<ImprintPrePub>,
pub part_supi: Option<String>,
pub retract: Option<CitRetract>,
pub pubstatus: Option<PubStatus>,
pub history: Option<PubStatusDateSet>,
}
#[derive(Clone, Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum CitRetractType {
Retracted = 1,
Notice,
InError,
Erratum,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct CitRetract {
#[serde(rename = "type")]
pub r#type: CitRetractType,
pub exp: Option<String>,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct Meeting {
pub number: String,
pub date: Date,
pub place: Option<Affil>,
}