1use std::path::PathBuf;
6
7use serde::Serialize;
8
9use crate::{format, Size};
10
11#[derive(Debug, Serialize, Clone, Copy)]
13pub struct Rect {
14 pub x: u32,
16 pub y: u32,
18 pub width: u32,
20 pub height: u32,
22}
23
24#[derive(Debug, Serialize, Clone)]
26pub struct Entry {
27 pub name: String,
29 pub path: String,
31 pub rect: Rect,
33}
34
35#[derive(Debug, Serialize)]
37pub struct Dictionary {
38 width: u32,
40 height: u32,
42 items: Vec<Entry>,
44}
45
46impl Dictionary {
47 pub fn new(size: Size) -> Self {
49 Self {
50 width: size.width,
51 height: size.height,
52 items: vec![],
53 }
54 }
55
56 #[allow(clippy::ptr_arg)]
60 pub fn record(&mut self, path: &PathBuf, rect: &crate::Rect) -> Entry {
61 let name = path
62 .file_stem()
63 .or_else(|| path.file_name())
64 .unwrap_or(path.as_os_str())
65 .to_string_lossy()
66 .to_string();
67
68 let entry = Entry {
69 name: self.pick_name(&name),
70 path: path.to_string_lossy().to_string(),
71 rect: self::Rect {
72 x: rect.origin.x,
73 y: rect.origin.y,
74 width: rect.size.width,
75 height: rect.size.height,
76 },
77 };
78
79 self.items.push(entry.clone());
80 entry
81 }
82
83 fn pick_name(&self, name: &str) -> String {
84 let exists = |name: &str| self.items.iter().any(|v| v.name == name);
85
86 if !exists(name) {
87 return String::from(name);
88 }
89
90 for i in 0.. {
91 let new_name = format!("{}-{}", name, i);
92
93 if !exists(&new_name) {
94 return new_name;
95 }
96 }
97
98 String::from(name)
99 }
100
101 pub fn save(&self, name: &str, dict: format::DictionaryFormat) -> anyhow::Result<()> {
103 let content = match dict {
104 format::DictionaryFormat::Toml => toml::to_vec(self)?,
105 format::DictionaryFormat::Json => serde_json::to_vec_pretty(self)?,
106 format::DictionaryFormat::Yaml => serde_yaml::to_string(self)?.into_bytes(),
107 format::DictionaryFormat::Ron => ron::to_string(self)?.into_bytes(),
108 };
109 std::fs::write(format!("{}.{}", name, dict.ext()), content)?;
110 Ok(())
111 }
112}