gdritter repos palladio / b6ca455
Move Document info into new module Getty Ritter 6 years ago
3 changed file(s) with 109 addition(s) and 103 deletion(s). Collapse all Expand all
1 use failure::Error;
2 use image;
3 use serde_json;
4 use std::io::{Read, Write, Seek};
5 use zip::{ZipArchive, ZipWriter};
6
7 /// This value represents both the current document in-memory as well
8 /// as the entirety of the values that we will want to both save and
9 /// restore
10 pub struct Document {
11 pub tilesheet: image::DynamicImage,
12 pub metadata: Metadata,
13 pub rules: (),
14 }
15
16 /// This should be renamed;
17 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
18 pub struct Metadata {
19 pub tile_width: u16,
20 pub tile_height: u16,
21 pub config_loop_forever: bool,
22 }
23
24 impl Document {
25 pub fn open_from_file<R: Read + Seek>(r: &mut R) -> Result<Document, Error> {
26 let mut archive = ZipArchive::new(r)?;
27 let tilesheet = {
28 let mut buf = Vec::new();
29 archive.by_name("tilesheet.png")?.read_to_end(&mut buf)?;
30 image::load_from_memory(&buf)?
31 };
32 let metadata = {
33 let file = archive.by_name("metadata.json")?;
34 serde_json::from_reader(file)?
35 };
36 let rules = {
37 let file = archive.by_name("rules.json")?;
38 serde_json::from_reader(file)?
39 };
40 Ok(Document{ tilesheet, metadata, rules })
41 }
42
43 pub fn save_to_file<W: Write + Seek>(&self, w: &mut W) -> Result<(), Error> {
44 use zip::write::FileOptions;
45
46 let mut zip = ZipWriter::new(w);
47 zip.start_file("tilesheet.png", FileOptions::default())?;
48 self.tilesheet.write_to(&mut zip, image::ImageOutputFormat::PNG)?;
49
50 zip.start_file("metadata.json", FileOptions::default())?;
51 serde_json::to_writer(&mut zip, &self.metadata)?;
52
53 zip.start_file("rules.json", FileOptions::default())?;
54 serde_json::to_writer(&mut zip, &self.rules)?;
55
56 zip.start_file("info.txt", FileOptions::default())?;
57 writeln!(
58 &mut zip,
59 "Created by {} v{}",
60 ::constants::PROGRAM_NAME,
61 ::constants::PROGRAM_VERSION,
62 )?;
63
64 zip.finish()?;
65 Ok(())
66 }
67
68 pub fn dummy() -> Document {
69 Document {
70 tilesheet: image::DynamicImage::new_rgb8(32, 32),
71 metadata: Metadata {
72 tile_width: 16,
73 tile_height: 16,
74 config_loop_forever: false,
75 },
76 rules: (),
77 }
78 }
79 }
80
81 #[cfg(test)]
82 mod tests {
83 use super::Document;
84 use std::io::{BufReader, Cursor};
85
86 #[test]
87 fn round_trip() {
88 let mut buf = Cursor::new(Vec::new());
89 let doc1 = Document::dummy();
90 doc1.save_to_file(&mut buf).unwrap();
91 let buf = buf.into_inner();
92 let doc2 = Document::open_from_file(&mut BufReader::new(Cursor::new(buf))).unwrap();
93 assert!(doc1.metadata == doc2.metadata);
94 }
95 }
1 pub mod document;
2 pub use self::document::*;
3
4 pub struct State {
5 pub document: Document,
6 pub save_state: SaveState,
7 }
8
9 #[derive(Debug)]
10 pub enum SaveState {
11 Unsaved,
12 Modified,
13 Saved,
14 }
+0
-103
src/model.rs less more
1 use failure::Error;
2 use image;
3 use serde_json;
4 use std::io::{Read, Write, Seek};
5 use zip::{ZipArchive, ZipWriter};
6
7 pub struct State {
8 pub document: Document,
9 pub save_state: SaveState,
10 }
11
12 #[derive(Debug)]
13 pub enum SaveState {
14 Unsaved,
15 Modified,
16 Saved,
17 }
18
19 pub struct Document {
20 pub tilesheet: image::DynamicImage,
21 pub metadata: Metadata,
22 pub rules: (),
23 }
24
25 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
26 pub struct Metadata {
27 pub tile_width: u16,
28 pub tile_height: u16,
29 pub config_loop_forever: bool,
30 }
31
32 impl Document {
33 pub fn open_from_file<R: Read + Seek>(r: &mut R) -> Result<Document, Error> {
34 let mut archive = ZipArchive::new(r)?;
35 let tilesheet = {
36 let mut buf = Vec::new();
37 archive.by_name("tilesheet.png")?.read_to_end(&mut buf)?;
38 image::load_from_memory(&buf)?
39 };
40 let metadata = {
41 let file = archive.by_name("metadata.json")?;
42 serde_json::from_reader(file)?
43 };
44 let rules = {
45 let file = archive.by_name("rules.json")?;
46 serde_json::from_reader(file)?
47 };
48 Ok(Document{ tilesheet, metadata, rules })
49 }
50
51 pub fn save_to_file<W: Write + Seek>(&self, w: &mut W) -> Result<(), Error> {
52 use zip::write::FileOptions;
53
54 let mut zip = ZipWriter::new(w);
55 zip.start_file("tilesheet.png", FileOptions::default())?;
56 self.tilesheet.write_to(&mut zip, image::ImageOutputFormat::PNG)?;
57
58 zip.start_file("metadata.json", FileOptions::default())?;
59 serde_json::to_writer(&mut zip, &self.metadata)?;
60
61 zip.start_file("rules.json", FileOptions::default())?;
62 serde_json::to_writer(&mut zip, &self.rules)?;
63
64 zip.start_file("info.txt", FileOptions::default())?;
65 writeln!(
66 &mut zip,
67 "Created by {} v{}",
68 ::constants::PROGRAM_NAME,
69 ::constants::PROGRAM_VERSION,
70 )?;
71
72 zip.finish()?;
73 Ok(())
74 }
75
76 pub fn dummy() -> Document {
77 Document {
78 tilesheet: image::DynamicImage::new_rgb8(32, 32),
79 metadata: Metadata {
80 tile_width: 16,
81 tile_height: 16,
82 config_loop_forever: false,
83 },
84 rules: (),
85 }
86 }
87 }
88
89 #[cfg(test)]
90 mod tests {
91 use super::Document;
92 use std::io::{BufReader, Cursor};
93
94 #[test]
95 fn round_trip() {
96 let mut buf = Cursor::new(Vec::new());
97 let doc1 = Document::dummy();
98 doc1.save_to_file(&mut buf).unwrap();
99 let buf = buf.into_inner();
100 let doc2 = Document::open_from_file(&mut BufReader::new(Cursor::new(buf))).unwrap();
101 assert!(doc1.metadata == doc2.metadata);
102 }
103 }