#![allow(rustdoc::private_intra_doc_links)]
#![deny(
// Documentation
// TODO: rustdoc::broken_intra_doc_links,
// TODO: rustdoc::missing_crate_level_docs,
// TODO: missing_docs,
// TODO: clippy::missing_docs_in_private_items,
//
// Other
deprecated_in_future,
exported_private_dependencies,
future_incompatible,
missing_copy_implementations,
missing_debug_implementations,
private_in_public,
rust_2018_compatibility,
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications,
// clippy attributes
clippy::missing_const_for_fn,
clippy::redundant_pub_crate,
clippy::use_self
)]
#![cfg_attr(docsrs, feature(doc_cfg), feature(doc_alias))]
use serde::{Deserialize, Serialize};
#[cfg(feature = "validate")]
use serde_valid::Validate;
use std::fmt;
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Resume {
pub basics: Option<Basics>,
pub work: Vec<Work>,
pub volunteer: Vec<Volunteer>,
pub education: Vec<Education>,
pub awards: Vec<Award>,
pub certificates: Vec<Certificate>,
pub publications: Vec<Publication>,
pub skills: Vec<Skill>,
pub languages: Vec<Language>,
pub interests: Vec<Interest>,
pub references: Vec<Reference>,
pub projects: Vec<Project>,
#[cfg(feature = "side-projects")]
#[serde(rename = "sideProjects")]
pub side_projects: Vec<Project>,
pub meta: Option<Meta>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Basics {
pub name: Option<String>,
pub label: Option<String>,
pub image: Option<String>,
pub email: Option<String>,
pub phone: Option<String>,
pub url: Option<String>,
pub summary: Option<String>,
pub location: Location,
pub profiles: Vec<Profile>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Location {
pub address: Option<String>,
#[serde(rename = "postalCode")]
pub postal_code: Option<String>,
pub city: Option<String>,
#[serde(rename = "countryCode")]
pub country_code: Option<String>,
pub region: Option<String>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Profile {
pub network: Option<String>,
pub username: Option<String>,
pub url: Option<String>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Work {
pub name: Option<String>,
pub location: Option<String>,
pub description: Option<String>,
pub position: Option<String>,
pub url: Option<String>,
#[serde(rename = "startDate")]
#[cfg_attr(
feature = "validate",
validate(
pattern = r"^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$"
)
)]
pub start_date: Option<String>,
#[serde(rename = "endDate")]
#[cfg_attr(
feature = "validate",
validate(
pattern = r"^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$"
)
)]
pub end_date: Option<String>,
pub highlights: Vec<Highlight>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
pub struct Highlight(pub String);
impl fmt::Display for Highlight {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Volunteer {
pub organization: Option<String>,
pub position: Option<String>,
pub url: Option<String>,
#[serde(rename = "startDate")]
#[cfg_attr(
feature = "validate",
validate(
pattern = r"^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$"
)
)]
pub start_date: Option<String>,
#[serde(rename = "endDate")]
#[cfg_attr(
feature = "validate",
validate(
pattern = r"^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$"
)
)]
pub end_date: Option<String>,
pub summary: Option<String>,
pub highlights: Vec<Highlight>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Education {
pub institution: Option<String>,
pub url: Option<String>,
pub area: Option<String>,
#[serde(rename = "studyType")]
pub study_type: Option<String>,
#[serde(rename = "startDate")]
#[cfg_attr(
feature = "validate",
validate(
pattern = r"^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$"
)
)]
pub start_date: Option<String>,
#[serde(rename = "endDate")]
#[cfg_attr(
feature = "validate",
validate(
pattern = r"^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$"
)
)]
pub end_date: Option<String>,
pub score: Option<String>,
#[serde(default)]
pub courses: Vec<Course>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
pub struct Course(pub String);
impl fmt::Display for Course {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Award {
pub title: Option<String>,
#[cfg_attr(
feature = "validate",
validate(
pattern = r"^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$"
)
)]
pub date: Option<String>,
pub awarder: Option<String>,
pub summary: Option<String>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Certificate {
pub name: Option<String>,
pub date: Option<String>,
pub url: Option<String>,
pub issuer: Option<String>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Publication {
pub name: Option<String>,
pub publisher: Option<String>,
#[serde(rename = "releaseDate")]
#[cfg_attr(
feature = "validate",
validate(
pattern = r"^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$"
)
)]
pub release_date: Option<String>,
pub url: Option<String>,
pub summary: Option<String>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Skill {
pub name: Option<String>,
pub level: Option<String>,
pub keywords: Vec<Keyword>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
pub struct Keyword(pub String);
impl fmt::Display for Keyword {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Language {
pub language: Option<String>,
pub fluency: Option<String>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Interest {
pub name: Option<String>,
pub keywords: Vec<Keyword>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Reference {
pub name: Option<String>,
pub reference: Option<String>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Project {
pub name: Option<String>,
pub description: Option<String>,
pub highlights: Vec<Highlight>,
pub keywords: Vec<Keyword>,
#[serde(rename = "startDate")]
#[cfg_attr(
feature = "validate",
validate(
pattern = r"^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$"
)
)]
pub start_date: Option<String>,
#[serde(rename = "endDate")]
#[cfg_attr(
feature = "validate",
validate(
pattern = r"^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$"
)
)]
pub end_date: Option<String>,
pub url: Option<String>,
pub roles: Vec<Role>,
pub entity: Option<String>,
pub r#type: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
pub struct Role(pub String);
impl fmt::Display for Role {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "validate", derive(Validate))]
#[serde(default)]
pub struct Meta {
pub canonical: Option<String>,
pub version: Option<String>,
#[serde(rename = "lastModified")]
pub last_modified: Option<String>,
}
#[cfg(feature = "validate")]
#[cfg(test)]
mod validate {
use super::*;
#[test]
fn sample() -> Result<(), Box<dyn std::error::Error>> {
const SAMPLE: &str = include_str!("../sample.resume.json");
let resume: Resume = serde_json::from_str(SAMPLE)?;
resume.validate()?;
Ok(())
}
#[test]
#[ignore = "Run explicitly"]
fn env() -> Result<(), Box<dyn std::error::Error>> {
let resume_file = std::env::var_os("RESUME_FILE").unwrap();
let resume = std::fs::read_to_string(resume_file)?;
let resume: Resume = serde_json::from_str(&resume)?;
resume.validate()?;
println!("{resume:#?}");
Ok(())
}
}