kasane_logic/spatial_id/single_id/constructor.rs
1use crate::SingleId;
2
3use crate::{
4 SpatialIdError, TemporalId,
5 error::Error,
6 spatial_id::constants::{F_MAX, F_MIN, MAX_ZOOM_LEVEL, XY_MAX},
7};
8
9impl SingleId {
10 /// 指定された値から [`SingleId`] を作成する。このコンストラクタは、与えられた `z`, `f`, `x`, `y` が 各ズームレベルにおける範囲内にあるかを検証し、範囲外の場合は [`Error`] を返す。
11 ///
12 /// # パラメータ
13 /// * `z` — ズームレベル(0–[MAX_ZOOM_LEVEL]の範囲が有効)
14 /// * `f` — Fインデックス(鉛直方向)
15 /// * `x` — Xインデックス(東西方向)
16 /// * `y` — Yインデックス(南北方向)
17 ///
18 /// # バリデーション
19 /// - `z` が [`MAX_ZOOM_LEVEL`] を超える場合、[`SpatialIdError::ZOutOfRange`] を返す。
20 /// - `f` がズームレベル `z` に対する `F_MIN[z]..=F_MAX[z]` の範囲外の場合、
21 /// [`SpatialIdError::FOutOfRange`] を返す。
22 /// - `x` または `y` が `0..=XY_MAX[z]` の範囲外の場合、
23 /// それぞれ [`SpatialIdError::XOutOfRange`]、[`SpatialIdError::YOutOfRange`] を返す。
24 ///
25 ///
26 /// IDの作成:
27 /// ```no_run
28 /// # use kasane_logic::SingleId;
29 /// let id = SingleId::new(5, 3, 2, 10).unwrap();
30 /// assert_eq!(id.to_string(), "5/3/2/10".to_string());
31 /// ```
32 ///
33 /// 次元の範囲外の検知:
34 /// ```no_run
35 /// # use kasane_logic::SingleId;
36 /// # use kasane_logic::SpatialIdError;
37 /// let id = SingleId::new(3, 3, 2, 10);
38 /// assert_eq!(id, Err(SpatialIdError::YOutOfRange{z:3,y:10}.into()));
39 /// ```
40 ///
41 /// ズームレベルの範囲外の検知:
42 /// ```
43 /// # use kasane_logic::SingleId;
44 /// # use kasane_logic::SpatialIdError;
45 /// let id = SingleId::new(68, 3, 2, 10);
46 /// assert_eq!(id, Err(SpatialIdError::ZOutOfRange { z:68 }.into()));
47 /// ```
48 pub fn new(z: u8, f: i32, x: u32, y: u32) -> Result<SingleId, Error> {
49 if z > MAX_ZOOM_LEVEL as u8 {
50 return Err(SpatialIdError::ZOutOfRange { z }.into());
51 }
52
53 let f_min = F_MIN[z as usize];
54 let f_max = F_MAX[z as usize];
55 let xy_max = XY_MAX[z as usize];
56
57 if f < f_min || f > f_max {
58 return Err(SpatialIdError::FOutOfRange { f, z }.into());
59 }
60 if x > xy_max {
61 return Err(SpatialIdError::XOutOfRange { x, z }.into());
62 }
63 if y > xy_max {
64 return Err(SpatialIdError::YOutOfRange { y, z }.into());
65 }
66
67 Ok(SingleId {
68 z,
69 f,
70 x,
71 y,
72 temporal_id: TemporalId::WHOLE,
73 })
74 }
75
76 /// 検証を行わずに [`SingleId`] を作成する。
77 ///
78 /// この関数は [`SingleId::new`] と異なり、与えられた `z`, `f`, `x`, `y` に対して一切の範囲チェックや整合性チェックを行わない。そのため、高速に ID を生成できるが、**不正なパラメータを与えた場合の動作は未定義である**。
79 ///
80 /// # 注意
81 /// 呼び出し側は、以下をすべて満たすことを保証しなければならない。
82 ///
83 /// * `z` が有効なズームレベル(0–[MAX_ZOOM_LEVEL])であること
84 /// * `f` が与えられた `z` に応じて `F_MIN[z]..=F_MAX[z]` の範囲内であること
85 /// * `x` および `y` が `0..=XY_MAX[z]` の範囲内であること
86 ///
87 /// これらが保証されない場合、パニック・不正メモリアクセス・未定義動作を引き起こす可能性がある。
88 ///
89 /// ```
90 /// # use kasane_logic::SingleId;
91 /// // パラメータが妥当であることを呼び出し側が保証する必要がある
92 /// let id = unsafe { SingleId::new_unchecked(5, 3, 2, 10) };
93 ///
94 /// assert_eq!(id.z(), 5u8);
95 /// assert_eq!(id.f(), 3i32);
96 /// assert_eq!(id.x(), 2u32);
97 /// assert_eq!(id.y(), 10u32);
98 /// ```
99 pub unsafe fn new_unchecked(z: u8, f: i32, x: u32, y: u32) -> SingleId {
100 SingleId {
101 z,
102 f,
103 x,
104 y,
105 temporal_id: TemporalId::WHOLE,
106 }
107 }
108
109 /// 指定された値から時間情報を指定した [`SingleId`] を作成する。このコンストラクタは、与えられた `z`, `f`, `x`, `y` が 各ズームレベルにおける範囲内にあるかを検証し、範囲外の場合は [`Error`] を返す。
110 ///
111 /// # パラメータ
112 /// * `z` — ズームレベル(0–[MAX_ZOOM_LEVEL]の範囲が有効)
113 /// * `f` — Fインデックス(鉛直方向)
114 /// * `x` — Xインデックス(東西方向)
115 /// * `y` — Yインデックス(南北方向)
116 /// * `temporal_id` — [TemporalId](時間ID)
117 ///
118 /// # バリデーション
119 /// - `z` が [`MAX_ZOOM_LEVEL`] を超える場合、[`SpatialIdError::ZOutOfRange`] を返す。
120 /// - `f` がズームレベル `z` に対する `F_MIN[z]..=F_MAX[z]` の範囲外の場合、
121 /// [`SpatialIdError::FOutOfRange`] を返す。
122 /// - `x` または `y` が `0..=XY_MAX[z]` の範囲外の場合、
123 /// それぞれ [`SpatialIdError::XOutOfRange`]、[`SpatialIdError::YOutOfRange`] を返す。
124 ///
125 ///
126 /// IDの作成:
127 /// ```no_run
128 /// # use kasane_logic::{SingleId,TemporalId};
129 /// //時間IDの作成
130 /// let temporal_id = TemporalId::new(60, [1,1]).unwrap();
131 ///
132 /// let id = SingleId::new_with_temporal(5, 3, 2, 10,temporal_id).unwrap();
133 /// assert_eq!(id.to_string(), "5/3/2/10_60/1:1".to_string());
134 /// ```
135 #[cfg(feature = "temporal_id")]
136 pub fn new_with_temporal(
137 z: u8,
138 f: i32,
139 x: u32,
140 y: u32,
141 temporal_id: TemporalId,
142 ) -> Result<SingleId, Error> {
143 if z > MAX_ZOOM_LEVEL as u8 {
144 return Err(SpatialIdError::ZOutOfRange { z }.into());
145 }
146
147 let f_min = F_MIN[z as usize];
148 let f_max = F_MAX[z as usize];
149 let xy_max = XY_MAX[z as usize];
150
151 if f < f_min || f > f_max {
152 return Err(SpatialIdError::FOutOfRange { f, z }.into());
153 }
154 if x > xy_max {
155 return Err(SpatialIdError::XOutOfRange { x, z }.into());
156 }
157 if y > xy_max {
158 return Err(SpatialIdError::YOutOfRange { y, z }.into());
159 }
160
161 Ok(SingleId {
162 z,
163 f,
164 x,
165 y,
166
167 temporal_id,
168 })
169 }
170
171 /// 検証を行わずに 時間情報を指定した[`SingleId`] を作成する。
172 ///
173 /// この関数は [`SingleId::new`] と異なり、与えられた `z`, `f`, `x`, `y` に対して一切の範囲チェックや整合性チェックを行わない。そのため、高速に ID を生成できるが、**不正なパラメータを与えた場合の動作は未定義である**。
174 ///
175 /// # 注意
176 /// 呼び出し側は、以下をすべて満たすことを保証しなければならない。
177 ///
178 /// * `z` が有効なズームレベル(0–[MAX_ZOOM_LEVEL])であること
179 /// * `f` が与えられた `z` に応じて `F_MIN[z]..=F_MAX[z]` の範囲内であること
180 /// * `x` および `y` が `0..=XY_MAX[z]` の範囲内であること
181 ///
182 /// これらが保証されない場合、パニック・不正メモリアクセス・未定義動作を引き起こす可能性がある。
183 ///
184 /// ```
185 /// # use kasane_logic::{SingleId,TemporalId};
186 /// //時間IDの作成
187 /// let temporal_id = TemporalId::new(60, [1,1]).unwrap();
188 ///
189 /// // パラメータが妥当であることを呼び出し側が保証する必要がある
190 /// let id = unsafe { SingleId::new_with_temporal_unchecked(5, 3, 2, 10,temporal_id) };
191 ///
192 /// assert_eq!(id.z(), 5u8);
193 /// assert_eq!(id.f(), 3i32);
194 /// assert_eq!(id.x(), 2u32);
195 /// assert_eq!(id.y(), 10u32);
196 /// ```
197 #[cfg(feature = "temporal_id")]
198 pub unsafe fn new_with_temporal_unchecked(
199 z: u8,
200 f: i32,
201 x: u32,
202 y: u32,
203 temporal_id: TemporalId,
204 ) -> SingleId {
205 SingleId {
206 z,
207 f,
208 x,
209 y,
210 temporal_id,
211 }
212 }
213}