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
use serde_derive::{Deserialize, Serialize};
use serde_json;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::path::Path;

use super::Error;

pub type Url = String;
pub type Uuid = String;
pub type Base64 = String;
pub type Hash = String;

#[derive(Debug, Serialize, Deserialize)]
pub struct RecipePhoto {
  pub data: Base64,
  pub filename: String,
  pub name: String,
  pub hash: Hash,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Recipe {
  pub created: String,
  pub difficulty: String,
  pub photo_large: Option<Base64>,
  pub uid: Uuid,
  pub photo: Option<String>,
  pub categories: Vec<String>,
  pub notes: String,
  pub prep_time: String,
  pub cook_time: String,
  pub source: String,
  pub source_url: String,
  pub photo_data: Option<Base64>,
  pub total_time: String,
  pub name: String,
  pub ingredients: String,
  pub photos: Vec<RecipePhoto>,
  pub rating: u8,
  pub description: String,
  pub photo_hash: Option<Hash>,
  pub image_url: Option<Url>,
  pub nutritional_info: String,
  pub directions: String,
  #[serde(skip_serializing)]
  pub hash: Hash,
  pub servings: String,
}

impl Recipe {
  pub fn from_reader<R: Read>(rdr: R) -> Result<Recipe, Error> {
    let gzip_decoder = libflate::gzip::Decoder::new(rdr)?;
    Ok(serde_json::from_reader(gzip_decoder)?)
  }

  pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Recipe, Error> {
    Ok(Self::from_reader(File::open(path)?)?)
  }

  pub fn to_writer<W: Write>(&self, writer: W) -> Result<(), Error> {
    let mut gzip_encoder = libflate::gzip::Encoder::new(writer)?;
    serde_json::to_writer(&mut gzip_encoder, self)?;
    gzip_encoder.finish().into_result()?;
    Ok(())
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  #[test]
  fn deserialization() {
    let data = include_bytes!("test/Brownies.paprikarecipe.json");
    let result: Result<Recipe, _> = serde_json::from_slice(data);
    assert!(result.is_ok(), true);

    let recipe = result.unwrap();
    assert_eq!(recipe.name, "Brownies");
  }

  #[test]
  fn from_file() {
    let data = include_bytes!("test/Brownies.paprikarecipe");
    let result = Recipe::from_reader(&data[..]);

    let recipe = result.unwrap();
    assert_eq!(recipe.name, "Brownies");
  }
}