1use crate::error::{RenderError, Result};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub struct TileCoordinate {
6 pub z: u8,
8 pub x: u32,
10 pub y: u32,
12}
13
14impl TileCoordinate {
15 pub fn new(z: u8, x: u32, y: u32) -> Result<Self> {
22 let max_coord = 2u32.pow(z as u32);
24 if x >= max_coord || y >= max_coord {
25 return Err(RenderError::InvalidCoordinate(format!(
26 "Tile coordinate ({}, {}) out of range for zoom level {} (max: {})",
27 x, y, z, max_coord - 1
28 )));
29 }
30
31 Ok(Self { z, x, y })
32 }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub struct BackgroundColor {
38 pub r: u8,
40 pub g: u8,
42 pub b: u8,
44 pub a: u8,
46}
47
48impl BackgroundColor {
49 pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
51 Self { r, g, b, a }
52 }
53
54 pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
56 Self::new(r, g, b, 255)
57 }
58
59 pub const fn transparent() -> Self {
61 Self::new(0, 0, 0, 0)
62 }
63
64 pub const fn white() -> Self {
66 Self::rgb(255, 255, 255)
67 }
68
69 pub const fn black() -> Self {
71 Self::rgb(0, 0, 0)
72 }
73}
74
75impl Default for BackgroundColor {
76 fn default() -> Self {
77 Self::transparent()
78 }
79}
80
81#[derive(Debug, Clone)]
83pub struct Settings {
84 pub background_color: BackgroundColor,
86 pub size: u32,
88}
89
90impl Settings {
91 pub fn new() -> Self {
93 Self::default()
94 }
95
96 pub fn builder() -> SettingsBuilder {
98 SettingsBuilder::default()
99 }
100}
101
102impl Default for Settings {
103 fn default() -> Self {
104 Self {
105 background_color: BackgroundColor::default(),
106 size: 256,
107 }
108 }
109}
110
111#[derive(Debug, Clone, Default)]
113pub struct SettingsBuilder {
114 background_color: Option<BackgroundColor>,
115 size: Option<u32>,
116}
117
118impl SettingsBuilder {
119 pub fn background_color(mut self, color: BackgroundColor) -> Self {
121 self.background_color = Some(color);
122 self
123 }
124
125 pub fn size(mut self, size: u32) -> Self {
127 self.size = Some(size);
128 self
129 }
130
131 pub fn build(self) -> Result<Settings> {
133 let size = self.size.unwrap_or(256);
134
135 if size == 0 {
137 return Err(RenderError::InvalidSettings(
138 "Tile size must be greater than 0".to_string(),
139 ));
140 }
141
142 if size > 4096 {
144 return Err(RenderError::InvalidSettings(
145 "Tile size must be 4096 or less".to_string(),
146 ));
147 }
148
149 Ok(Settings {
150 background_color: self.background_color.unwrap_or_default(),
151 size,
152 })
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 #[test]
161 fn test_tile_coordinate_new() {
162 assert!(TileCoordinate::new(0, 0, 0).is_ok());
164 assert!(TileCoordinate::new(5, 15, 20).is_ok());
165 assert!(TileCoordinate::new(10, 1023, 1023).is_ok());
166
167 assert!(TileCoordinate::new(0, 1, 0).is_err()); assert!(TileCoordinate::new(5, 32, 0).is_err()); assert!(TileCoordinate::new(5, 0, 32).is_err());
171 }
172
173 #[test]
174 fn test_background_color() {
175 let color = BackgroundColor::new(255, 128, 64, 200);
176 assert_eq!(color.r, 255);
177 assert_eq!(color.g, 128);
178 assert_eq!(color.b, 64);
179 assert_eq!(color.a, 200);
180
181 let rgb = BackgroundColor::rgb(100, 150, 200);
182 assert_eq!(rgb.a, 255);
183
184 let transparent = BackgroundColor::transparent();
185 assert_eq!(transparent.a, 0);
186 }
187
188 #[test]
189 fn test_settings_builder() {
190 let settings = Settings::builder()
191 .size(512)
192 .background_color(BackgroundColor::white())
193 .build()
194 .unwrap();
195
196 assert_eq!(settings.size, 512);
197 assert_eq!(settings.background_color, BackgroundColor::white());
198 }
199
200 #[test]
201 fn test_settings_builder_defaults() {
202 let settings = Settings::builder().build().unwrap();
203 assert_eq!(settings.size, 256);
204 assert_eq!(settings.background_color, BackgroundColor::transparent());
205 }
206
207 #[test]
208 fn test_settings_validation() {
209 assert!(Settings::builder().size(0).build().is_err());
211
212 assert!(Settings::builder().size(4097).build().is_err());
214
215 assert!(Settings::builder().size(1).build().is_ok());
217 assert!(Settings::builder().size(256).build().is_ok());
218 assert!(Settings::builder().size(4096).build().is_ok());
219 }
220}