1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
use crate::datatypes::RandomData; use failure::Fail; use std::iter::Iterator; use std::string::ToString; use serde_derive::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Reference { path: String, property: String, } #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "type", content = "value")] pub enum DataType { RandomData(RandomData), List(Box<DataType>), Model(String), Reference { path: String, property: String }, } use std::collections::{hash_map::Iter, HashMap}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Model { #[serde(flatten)] properties: HashMap<String, DataType>, } impl Model { pub fn type_iter(&self) -> Iter<String, DataType> { self.properties.iter() } } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Specification { serialize: HashMap<String, Vec<String>>, models: HashMap<String, Model>, } impl Specification { pub fn has_model<S: ToString>(&self, name: S) -> bool { self.models.contains_key(&name.to_string()) } pub fn get_definition<S: ToString>(&self, name: S) -> &Model { &self.models.get(&name.to_string()).unwrap() } pub fn get_serialize_ref<S: ToString>(&self, name: S) -> Option<&Vec<String>> { self.serialize.get(&name.to_string()) } } pub mod io { use super::Specification; use crate::generator::from_spec; use failure::Fail; use std::convert::AsRef; use std::fs::read_to_string; use std::io::Result; use std::path::{Path, PathBuf}; use serde_derive::{Deserialize, Serialize}; use serde_json::{error::Category, from_str}; pub type SpecResult<Success> = std::result::Result<Success, SpecError>; #[derive(Debug, Fail)] pub enum SpecError { #[fail(display = "Could not find the spec file: {}", 0)] MissingFile(String), #[fail(display = "Failed for unhandled reason: {}", inner)] IOError { inner: std::io::Error }, #[fail(display = "The provided spec path could not be correctly converted")] BadPath, #[fail(display = "The specification is not valid JSON")] BadFormat, #[fail(display = "The specification contained one or more invalid definitions")] BadData, } fn pathable_to_string<P: AsRef<Path>>(path: &P) -> SpecResult<String> { return match path.as_ref().to_str() { Some(string) => Ok(String::from(string)), None => Err(SpecError::BadPath), }; } pub fn read_spec<P: AsRef<Path>>(path: P) -> SpecResult<Specification> { let content = match read_to_string(&path) { Ok(content) => content, Err(e) => match e.kind() { std::io::ErrorKind::NotFound => { return Err(SpecError::MissingFile(pathable_to_string(&path)?)) } _ => return Err(SpecError::IOError { inner: e }), }, }; match from_str(&content) { Ok(spec) => Ok(spec), Err(e) => match e.classify() { Category::Eof | Category::Syntax => Err(SpecError::BadFormat), Category::Data => Err(SpecError::BadData), Category::Io => Err(SpecError::IOError { inner: e.into() }), }, } } }