1use std::{fmt, marker::PhantomData, ops};
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Serialize, Deserialize)]
8#[serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))]
9pub struct SideOffsets2D<T, U> {
10 pub top: T,
12 pub right: T,
14 pub bottom: T,
16 pub left: T,
18 #[doc(hidden)]
19 #[serde(skip)] pub _unit: PhantomData<U>,
21}
22impl<T, U> From<euclid::SideOffsets2D<T, U>> for SideOffsets2D<T, U> {
23 fn from(value: euclid::SideOffsets2D<T, U>) -> Self {
24 Self {
25 top: value.top,
26 right: value.right,
27 bottom: value.bottom,
28 left: value.left,
29 _unit: PhantomData,
30 }
31 }
32}
33impl<T, U> From<SideOffsets2D<T, U>> for euclid::SideOffsets2D<T, U> {
34 fn from(value: SideOffsets2D<T, U>) -> Self {
35 Self {
36 top: value.top,
37 right: value.right,
38 bottom: value.bottom,
39 left: value.left,
40 _unit: PhantomData,
41 }
42 }
43}
44impl<T: Copy, U> Copy for SideOffsets2D<T, U> {}
45impl<T: Clone, U> Clone for SideOffsets2D<T, U> {
46 fn clone(&self) -> Self {
47 SideOffsets2D {
48 top: self.top.clone(),
49 right: self.right.clone(),
50 bottom: self.bottom.clone(),
51 left: self.left.clone(),
52 _unit: PhantomData,
53 }
54 }
55}
56impl<T, U> Eq for SideOffsets2D<T, U> where T: Eq {}
57impl<T, U> PartialEq for SideOffsets2D<T, U>
58where
59 T: PartialEq,
60{
61 fn eq(&self, other: &Self) -> bool {
62 self.top == other.top && self.right == other.right && self.bottom == other.bottom && self.left == other.left
63 }
64}
65impl<T, U> std::hash::Hash for SideOffsets2D<T, U>
66where
67 T: std::hash::Hash,
68{
69 fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
70 self.top.hash(h);
71 self.right.hash(h);
72 self.bottom.hash(h);
73 self.left.hash(h);
74 }
75}
76impl<T: fmt::Debug, U> fmt::Debug for SideOffsets2D<T, U> {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 write!(f, "({:?},{:?},{:?},{:?})", self.top, self.right, self.bottom, self.left)
79 }
80}
81impl<T: Default, U> Default for SideOffsets2D<T, U> {
82 fn default() -> Self {
83 SideOffsets2D {
84 top: Default::default(),
85 right: Default::default(),
86 bottom: Default::default(),
87 left: Default::default(),
88 _unit: PhantomData,
89 }
90 }
91}
92impl<T, U> SideOffsets2D<T, U> {
93 pub const fn new(top: T, right: T, bottom: T, left: T) -> Self {
98 SideOffsets2D {
99 top,
100 right,
101 bottom,
102 left,
103 _unit: PhantomData,
104 }
105 }
106
107 pub fn from_vectors_outer(min: euclid::Vector2D<T, U>, max: euclid::Vector2D<T, U>) -> Self
113 where
114 T: ops::Neg<Output = T>,
115 {
116 SideOffsets2D {
117 left: -min.x,
118 top: -min.y,
119 right: max.x,
120 bottom: max.y,
121 _unit: PhantomData,
122 }
123 }
124
125 pub fn from_vectors_inner(min: euclid::Vector2D<T, U>, max: euclid::Vector2D<T, U>) -> Self
131 where
132 T: ops::Neg<Output = T>,
133 {
134 SideOffsets2D {
135 left: min.x,
136 top: min.y,
137 right: -max.x,
138 bottom: -max.y,
139 _unit: PhantomData,
140 }
141 }
142
143 pub fn zero() -> Self
145 where
146 T: euclid::num::Zero,
147 {
148 use euclid::num::Zero;
149 SideOffsets2D::new(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero())
150 }
151
152 pub fn is_zero(&self) -> bool
154 where
155 T: euclid::num::Zero + PartialEq,
156 {
157 let zero = T::zero();
158 self.top == zero && self.right == zero && self.bottom == zero && self.left == zero
159 }
160
161 pub fn new_all_same(all: T) -> Self
163 where
164 T: Copy,
165 {
166 SideOffsets2D::new(all, all, all, all)
167 }
168
169 pub fn horizontal(&self) -> T
171 where
172 T: Copy + ops::Add<T, Output = T>,
173 {
174 self.left + self.right
175 }
176
177 pub fn vertical(&self) -> T
179 where
180 T: Copy + ops::Add<T, Output = T>,
181 {
182 self.top + self.bottom
183 }
184}
185impl<T, U> ops::Add for SideOffsets2D<T, U>
186where
187 T: ops::Add<T, Output = T>,
188{
189 type Output = Self;
190 fn add(self, other: Self) -> Self {
191 SideOffsets2D::new(
192 self.top + other.top,
193 self.right + other.right,
194 self.bottom + other.bottom,
195 self.left + other.left,
196 )
197 }
198}
199impl<T, U> ops::AddAssign<Self> for SideOffsets2D<T, U>
200where
201 T: ops::AddAssign<T>,
202{
203 fn add_assign(&mut self, other: Self) {
204 self.top += other.top;
205 self.right += other.right;
206 self.bottom += other.bottom;
207 self.left += other.left;
208 }
209}
210impl<T, U> ops::Sub for SideOffsets2D<T, U>
211where
212 T: ops::Sub<T, Output = T>,
213{
214 type Output = Self;
215 fn sub(self, other: Self) -> Self {
216 SideOffsets2D::new(
217 self.top - other.top,
218 self.right - other.right,
219 self.bottom - other.bottom,
220 self.left - other.left,
221 )
222 }
223}
224impl<T, U> ops::SubAssign<Self> for SideOffsets2D<T, U>
225where
226 T: ops::SubAssign<T>,
227{
228 fn sub_assign(&mut self, other: Self) {
229 self.top -= other.top;
230 self.right -= other.right;
231 self.bottom -= other.bottom;
232 self.left -= other.left;
233 }
234}
235
236impl<T, U> ops::Neg for SideOffsets2D<T, U>
237where
238 T: ops::Neg<Output = T>,
239{
240 type Output = Self;
241 fn neg(self) -> Self {
242 SideOffsets2D {
243 top: -self.top,
244 right: -self.right,
245 bottom: -self.bottom,
246 left: -self.left,
247 _unit: PhantomData,
248 }
249 }
250}
251impl<T: Copy + ops::Mul, U> ops::Mul<T> for SideOffsets2D<T, U> {
252 type Output = SideOffsets2D<T::Output, U>;
253
254 #[inline]
255 fn mul(self, scale: T) -> Self::Output {
256 SideOffsets2D::new(self.top * scale, self.right * scale, self.bottom * scale, self.left * scale)
257 }
258}
259impl<T: Copy + ops::MulAssign, U> ops::MulAssign<T> for SideOffsets2D<T, U> {
260 #[inline]
261 fn mul_assign(&mut self, other: T) {
262 self.top *= other;
263 self.right *= other;
264 self.bottom *= other;
265 self.left *= other;
266 }
267}
268impl<T: Copy + ops::Mul, U1, U2> ops::Mul<euclid::Scale<T, U1, U2>> for SideOffsets2D<T, U1> {
269 type Output = SideOffsets2D<T::Output, U2>;
270
271 #[inline]
272 fn mul(self, scale: euclid::Scale<T, U1, U2>) -> Self::Output {
273 SideOffsets2D::new(self.top * scale.0, self.right * scale.0, self.bottom * scale.0, self.left * scale.0)
274 }
275}
276impl<T: Copy + ops::MulAssign, U> ops::MulAssign<euclid::Scale<T, U, U>> for SideOffsets2D<T, U> {
277 #[inline]
278 fn mul_assign(&mut self, other: euclid::Scale<T, U, U>) {
279 *self *= other.0;
280 }
281}
282impl<T: Copy + ops::Div, U> ops::Div<T> for SideOffsets2D<T, U> {
283 type Output = SideOffsets2D<T::Output, U>;
284
285 #[inline]
286 fn div(self, scale: T) -> Self::Output {
287 SideOffsets2D::new(self.top / scale, self.right / scale, self.bottom / scale, self.left / scale)
288 }
289}
290impl<T: Copy + ops::DivAssign, U> ops::DivAssign<T> for SideOffsets2D<T, U> {
291 #[inline]
292 fn div_assign(&mut self, other: T) {
293 self.top /= other;
294 self.right /= other;
295 self.bottom /= other;
296 self.left /= other;
297 }
298}
299impl<T: Copy + ops::Div, U1, U2> ops::Div<euclid::Scale<T, U1, U2>> for SideOffsets2D<T, U2> {
300 type Output = SideOffsets2D<T::Output, U1>;
301
302 #[inline]
303 fn div(self, scale: euclid::Scale<T, U1, U2>) -> Self::Output {
304 SideOffsets2D::new(self.top / scale.0, self.right / scale.0, self.bottom / scale.0, self.left / scale.0)
305 }
306}
307impl<T: Copy + ops::DivAssign, U> ops::DivAssign<euclid::Scale<T, U, U>> for SideOffsets2D<T, U> {
308 fn div_assign(&mut self, other: euclid::Scale<T, U, U>) {
309 *self /= other.0;
310 }
311}