druid/
data.rs

1// Copyright 2019 The Druid Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Traits for handling value types.
16
17use std::ptr;
18use std::rc::Rc;
19use std::sync::Arc;
20
21use crate::kurbo::{self, ParamCurve};
22use crate::piet;
23use crate::shell::Scale;
24
25pub use druid_derive::Data;
26use piet::ImageBuf;
27
28/// A trait used to represent value types.
29///
30/// These should be cheap to compare and cheap to clone.
31///
32/// See <https://sinusoid.es/lager/model.html#id2> for a well-written
33/// explanation of value types (albeit within a C++ context).
34///
35/// ## Derive macro
36///
37/// In general, you can use `derive` to generate a `Data` impl for your types.
38///
39/// ```
40/// # use std::sync::Arc;
41/// # use druid::Data;
42/// #[derive(Clone, Data)]
43/// enum Foo {
44///     Case1(i32, f32),
45///     Case2 { a: String, b: Arc<i32> }
46/// }
47/// ```
48///
49/// ### Derive macro attributes
50///
51/// There are a number of field attributes available for use with `derive(Data)`.
52///
53/// - **`#[data(ignore)]`**
54///
55/// Skip this field when computing `same`ness.
56///
57/// If the type you are implementing `Data` on contains some fields that are
58/// not relevant to the `Data` impl, you can ignore them with this attribute.
59///
60/// - **`#[data(same_fn = "path")]`**
61///
62/// Use a specific function to compute `same`ness.
63///
64/// By default, derived implementations of `Data` just call [`Data::same`]
65/// recursively on each field. With this attribute, you can specify a
66/// custom function that will be used instead.
67///
68/// This function must have a signature in the form, `fn<T>(&T, &T) -> bool`,
69/// where `T` is the type of the field.
70///
71/// ## Collection types
72///
73/// `Data` is not implemented for `std` collection types, because comparing them
74/// can be expensive. To use collection types with Druid, there are two easy options:
75/// either wrap the collection in an `Arc`, or build `druid` with the `im` feature,
76/// which adds `Data` implementations to the collections from the [`im` crate],
77/// a set of immutable data structures that fit nicely with Druid.
78///
79/// If the `im` feature is used, the `im` crate is reexported from the root
80/// of the `druid` crate.
81///
82/// ### Example:
83///
84/// ```
85/// # use std::path::PathBuf;
86/// # use std::time::Instant;
87/// # use druid::Data;
88/// #[derive(Clone, Data)]
89/// struct PathEntry {
90///     // There's no Data impl for PathBuf, but no problem
91///     #[data(eq)]
92///     path: PathBuf,
93///     priority: usize,
94///     // This field is not part of our data model.
95///     #[data(ignore)]
96///     last_read: Instant,
97/// }
98/// ```
99///
100/// ## C-style enums
101///
102/// In the case of a "c-style" enum (one that only contains unit variants,
103/// that is where no variant has fields), the implementation that is generated
104/// checks for equality. Therefore, such types must also implement `PartialEq`.
105///
106/// [`im` crate]: https://crates.io/crates/im
107pub trait Data: Clone + 'static {
108    //// ANCHOR: same_fn
109    /// Determine whether two values are the same.
110    ///
111    /// This is intended to always be a fast operation. If it returns
112    /// `true`, the two values *must* be equal, but two equal values
113    /// need not be considered the same here, as will often be the
114    /// case when two copies are separately allocated.
115    ///
116    /// Note that "equal" above has a slightly different meaning than
117    /// `PartialEq`, for example two floating point NaN values should
118    /// be considered equal when they have the same bit representation.
119    fn same(&self, other: &Self) -> bool;
120    //// ANCHOR_END: same_fn
121}
122
123/// An impl of `Data` suitable for simple types.
124///
125/// The `same` method is implemented with equality, so the type should
126/// implement `Eq` at least.
127macro_rules! impl_data_simple {
128    ($t:ty) => {
129        impl Data for $t {
130            fn same(&self, other: &Self) -> bool {
131                self == other
132            }
133        }
134    };
135}
136
137// Standard library impls
138
139impl_data_simple!(i8);
140impl_data_simple!(i16);
141impl_data_simple!(i32);
142impl_data_simple!(i64);
143impl_data_simple!(i128);
144impl_data_simple!(isize);
145impl_data_simple!(u8);
146impl_data_simple!(u16);
147impl_data_simple!(u32);
148impl_data_simple!(u64);
149impl_data_simple!(u128);
150impl_data_simple!(usize);
151impl_data_simple!(char);
152impl_data_simple!(bool);
153impl_data_simple!(std::num::NonZeroI8);
154impl_data_simple!(std::num::NonZeroI16);
155impl_data_simple!(std::num::NonZeroI32);
156impl_data_simple!(std::num::NonZeroI64);
157impl_data_simple!(std::num::NonZeroI128);
158impl_data_simple!(std::num::NonZeroIsize);
159impl_data_simple!(std::num::NonZeroU8);
160impl_data_simple!(std::num::NonZeroU16);
161impl_data_simple!(std::num::NonZeroU32);
162impl_data_simple!(std::num::NonZeroU64);
163impl_data_simple!(std::num::NonZeroU128);
164impl_data_simple!(std::num::NonZeroUsize);
165impl_data_simple!(std::time::SystemTime);
166impl_data_simple!(std::time::Instant);
167impl_data_simple!(std::time::Duration);
168impl_data_simple!(std::io::ErrorKind);
169impl_data_simple!(std::net::Ipv4Addr);
170impl_data_simple!(std::net::Ipv6Addr);
171impl_data_simple!(std::net::SocketAddrV4);
172impl_data_simple!(std::net::SocketAddrV6);
173impl_data_simple!(std::net::IpAddr);
174impl_data_simple!(std::net::SocketAddr);
175impl_data_simple!(std::ops::RangeFull);
176impl_data_simple!(druid::piet::InterpolationMode);
177#[cfg(feature = "chrono")]
178impl_data_simple!(chrono::Duration);
179#[cfg(feature = "chrono")]
180impl_data_simple!(chrono::naive::IsoWeek);
181#[cfg(feature = "chrono")]
182impl_data_simple!(chrono::naive::NaiveDate);
183#[cfg(feature = "chrono")]
184impl_data_simple!(chrono::naive::NaiveDateTime);
185#[cfg(feature = "chrono")]
186impl_data_simple!(chrono::naive::NaiveTime);
187
188//TODO: remove me!?
189impl_data_simple!(String);
190
191impl Data for &'static str {
192    fn same(&self, other: &Self) -> bool {
193        ptr::eq(*self, *other)
194    }
195}
196
197impl Data for f32 {
198    fn same(&self, other: &Self) -> bool {
199        self.to_bits() == other.to_bits()
200    }
201}
202
203impl Data for f64 {
204    fn same(&self, other: &Self) -> bool {
205        self.to_bits() == other.to_bits()
206    }
207}
208
209/// Checks pointer equality. The internal value is not checked.
210impl<T: ?Sized + 'static> Data for Arc<T> {
211    fn same(&self, other: &Self) -> bool {
212        Arc::ptr_eq(self, other)
213    }
214}
215
216impl<T: ?Sized + 'static> Data for std::sync::Weak<T> {
217    fn same(&self, other: &Self) -> bool {
218        std::sync::Weak::ptr_eq(self, other)
219    }
220}
221
222impl<T: ?Sized + 'static> Data for Rc<T> {
223    fn same(&self, other: &Self) -> bool {
224        Rc::ptr_eq(self, other)
225    }
226}
227
228impl<T: ?Sized + 'static> Data for std::rc::Weak<T> {
229    fn same(&self, other: &Self) -> bool {
230        std::rc::Weak::ptr_eq(self, other)
231    }
232}
233
234impl<T: Data> Data for Option<T> {
235    fn same(&self, other: &Self) -> bool {
236        match (self, other) {
237            (Some(a), Some(b)) => a.same(b),
238            (None, None) => true,
239            _ => false,
240        }
241    }
242}
243
244impl<T: Data, U: Data> Data for Result<T, U> {
245    fn same(&self, other: &Self) -> bool {
246        match (self, other) {
247            (Ok(a), Ok(b)) => a.same(b),
248            (Err(a), Err(b)) => a.same(b),
249            _ => false,
250        }
251    }
252}
253
254impl Data for () {
255    fn same(&self, _other: &Self) -> bool {
256        true
257    }
258}
259
260impl<T0: Data> Data for (T0,) {
261    fn same(&self, other: &Self) -> bool {
262        self.0.same(&other.0)
263    }
264}
265
266impl<T0: Data, T1: Data> Data for (T0, T1) {
267    fn same(&self, other: &Self) -> bool {
268        self.0.same(&other.0) && self.1.same(&other.1)
269    }
270}
271
272impl<T0: Data, T1: Data, T2: Data> Data for (T0, T1, T2) {
273    fn same(&self, other: &Self) -> bool {
274        self.0.same(&other.0) && self.1.same(&other.1) && self.2.same(&other.2)
275    }
276}
277
278impl<T0: Data, T1: Data, T2: Data, T3: Data> Data for (T0, T1, T2, T3) {
279    fn same(&self, other: &Self) -> bool {
280        self.0.same(&other.0)
281            && self.1.same(&other.1)
282            && self.2.same(&other.2)
283            && self.3.same(&other.3)
284    }
285}
286
287impl<T0: Data, T1: Data, T2: Data, T3: Data, T4: Data> Data for (T0, T1, T2, T3, T4) {
288    fn same(&self, other: &Self) -> bool {
289        self.0.same(&other.0)
290            && self.1.same(&other.1)
291            && self.2.same(&other.2)
292            && self.3.same(&other.3)
293            && self.4.same(&other.4)
294    }
295}
296
297impl<T0: Data, T1: Data, T2: Data, T3: Data, T4: Data, T5: Data> Data for (T0, T1, T2, T3, T4, T5) {
298    fn same(&self, other: &Self) -> bool {
299        self.0.same(&other.0)
300            && self.1.same(&other.1)
301            && self.2.same(&other.2)
302            && self.3.same(&other.3)
303            && self.4.same(&other.4)
304            && self.5.same(&other.5)
305    }
306}
307
308impl<T: 'static + ?Sized> Data for std::marker::PhantomData<T> {
309    fn same(&self, _other: &Self) -> bool {
310        // zero-sized types
311        true
312    }
313}
314
315impl<T: 'static> Data for std::mem::Discriminant<T> {
316    fn same(&self, other: &Self) -> bool {
317        *self == *other
318    }
319}
320
321impl<T: 'static + ?Sized + Data> Data for std::mem::ManuallyDrop<T> {
322    fn same(&self, other: &Self) -> bool {
323        (**self).same(&**other)
324    }
325}
326
327impl<T: Data> Data for std::num::Wrapping<T> {
328    fn same(&self, other: &Self) -> bool {
329        self.0.same(&other.0)
330    }
331}
332
333impl<T: Data> Data for std::ops::Range<T> {
334    fn same(&self, other: &Self) -> bool {
335        self.start.same(&other.start) && self.end.same(&other.end)
336    }
337}
338
339impl<T: Data> Data for std::ops::RangeFrom<T> {
340    fn same(&self, other: &Self) -> bool {
341        self.start.same(&other.start)
342    }
343}
344
345impl<T: Data> Data for std::ops::RangeInclusive<T> {
346    fn same(&self, other: &Self) -> bool {
347        self.start().same(other.start()) && self.end().same(other.end())
348    }
349}
350
351impl<T: Data> Data for std::ops::RangeTo<T> {
352    fn same(&self, other: &Self) -> bool {
353        self.end.same(&other.end)
354    }
355}
356
357impl<T: Data> Data for std::ops::RangeToInclusive<T> {
358    fn same(&self, other: &Self) -> bool {
359        self.end.same(&other.end)
360    }
361}
362
363impl<T: Data> Data for std::ops::Bound<T> {
364    fn same(&self, other: &Self) -> bool {
365        use std::ops::Bound::*;
366        match (self, other) {
367            (Included(t1), Included(t2)) if t1.same(t2) => true,
368            (Excluded(t1), Excluded(t2)) if t1.same(t2) => true,
369            (Unbounded, Unbounded) => true,
370            _ => false,
371        }
372    }
373}
374
375// druid & deps impls
376
377impl Data for Scale {
378    fn same(&self, other: &Self) -> bool {
379        self == other
380    }
381}
382
383impl Data for kurbo::Point {
384    fn same(&self, other: &Self) -> bool {
385        self.x.same(&other.x) && self.y.same(&other.y)
386    }
387}
388
389impl Data for kurbo::Vec2 {
390    fn same(&self, other: &Self) -> bool {
391        self.x.same(&other.x) && self.y.same(&other.y)
392    }
393}
394
395impl Data for kurbo::Size {
396    fn same(&self, other: &Self) -> bool {
397        self.width.same(&other.width) && self.height.same(&other.height)
398    }
399}
400
401impl Data for kurbo::Affine {
402    fn same(&self, other: &Self) -> bool {
403        let rhs = self.as_coeffs();
404        let lhs = other.as_coeffs();
405        rhs.iter().zip(lhs.iter()).all(|(r, l)| r.same(l))
406    }
407}
408
409impl Data for kurbo::Insets {
410    fn same(&self, other: &Self) -> bool {
411        self.x0.same(&other.x0)
412            && self.y0.same(&other.y0)
413            && self.x1.same(&other.x1)
414            && self.y1.same(&other.y1)
415    }
416}
417
418impl Data for kurbo::Rect {
419    fn same(&self, other: &Self) -> bool {
420        self.x0.same(&other.x0)
421            && self.y0.same(&other.y0)
422            && self.x1.same(&other.x1)
423            && self.y1.same(&other.y1)
424    }
425}
426
427impl Data for kurbo::RoundedRectRadii {
428    fn same(&self, other: &Self) -> bool {
429        self.top_left.same(&other.top_left)
430            && self.top_right.same(&other.top_right)
431            && self.bottom_left.same(&other.bottom_left)
432            && self.bottom_right.same(&other.bottom_right)
433    }
434}
435
436impl Data for kurbo::RoundedRect {
437    fn same(&self, other: &Self) -> bool {
438        self.rect().same(&other.rect()) && self.radii().same(&other.radii())
439    }
440}
441
442impl Data for kurbo::Arc {
443    fn same(&self, other: &Self) -> bool {
444        self.center.same(&other.center)
445            && self.radii.same(&other.radii)
446            && self.start_angle.same(&other.start_angle)
447            && self.sweep_angle.same(&other.sweep_angle)
448            && self.x_rotation.same(&other.x_rotation)
449    }
450}
451
452impl Data for kurbo::PathEl {
453    fn same(&self, other: &Self) -> bool {
454        use kurbo::PathEl::*;
455        match (self, other) {
456            (MoveTo(p1), MoveTo(p2)) => p1.same(p2),
457            (LineTo(p1), LineTo(p2)) => p1.same(p2),
458            (QuadTo(x1, y1), QuadTo(x2, y2)) => x1.same(x2) && y1.same(y2),
459            (CurveTo(x1, y1, z1), CurveTo(x2, y2, z2)) => x1.same(x2) && y1.same(y2) && z1.same(z2),
460            (ClosePath, ClosePath) => true,
461            _ => false,
462        }
463    }
464}
465
466impl Data for kurbo::PathSeg {
467    fn same(&self, other: &Self) -> bool {
468        use kurbo::PathSeg;
469        match (self, other) {
470            (PathSeg::Line(l1), PathSeg::Line(l2)) => l1.same(l2),
471            (PathSeg::Quad(q1), PathSeg::Quad(q2)) => q1.same(q2),
472            (PathSeg::Cubic(c1), PathSeg::Cubic(c2)) => c1.same(c2),
473            _ => false,
474        }
475    }
476}
477
478impl Data for kurbo::BezPath {
479    fn same(&self, other: &Self) -> bool {
480        let rhs = self.elements();
481        let lhs = other.elements();
482        if rhs.len() == lhs.len() {
483            rhs.iter().zip(lhs.iter()).all(|(x, y)| x.same(y))
484        } else {
485            false
486        }
487    }
488}
489
490impl Data for kurbo::Circle {
491    fn same(&self, other: &Self) -> bool {
492        self.center.same(&other.center) && self.radius.same(&other.radius)
493    }
494}
495
496impl Data for kurbo::CubicBez {
497    fn same(&self, other: &Self) -> bool {
498        self.p0.same(&other.p0)
499            && self.p1.same(&other.p1)
500            && self.p2.same(&other.p2)
501            && self.p3.same(&other.p3)
502    }
503}
504
505impl Data for kurbo::Line {
506    fn same(&self, other: &Self) -> bool {
507        self.p0.same(&other.p0) && self.p1.same(&other.p1)
508    }
509}
510
511impl Data for kurbo::ConstPoint {
512    fn same(&self, other: &Self) -> bool {
513        self.eval(0.).same(&other.eval(0.))
514    }
515}
516
517impl Data for kurbo::QuadBez {
518    fn same(&self, other: &Self) -> bool {
519        self.p0.same(&other.p0) && self.p1.same(&other.p1) && self.p2.same(&other.p2)
520    }
521}
522
523impl Data for piet::Color {
524    fn same(&self, other: &Self) -> bool {
525        self.as_rgba_u32().same(&other.as_rgba_u32())
526    }
527}
528
529impl Data for piet::FontFamily {
530    fn same(&self, other: &Self) -> bool {
531        self == other
532    }
533}
534
535impl Data for piet::FontWeight {
536    fn same(&self, other: &Self) -> bool {
537        self == other
538    }
539}
540
541impl Data for piet::FontStyle {
542    fn same(&self, other: &Self) -> bool {
543        self == other
544    }
545}
546
547impl Data for piet::TextAlignment {
548    fn same(&self, other: &Self) -> bool {
549        self == other
550    }
551}
552
553impl Data for ImageBuf {
554    fn same(&self, other: &Self) -> bool {
555        self.raw_pixels_shared().same(&other.raw_pixels_shared())
556    }
557}
558
559#[cfg(feature = "chrono")]
560impl<Tz: chrono::offset::TimeZone + 'static> Data for chrono::Date<Tz> {
561    fn same(&self, other: &Self) -> bool {
562        self == other
563    }
564}
565
566#[cfg(feature = "chrono")]
567impl<Tz: chrono::offset::TimeZone + 'static> Data for chrono::DateTime<Tz> {
568    fn same(&self, other: &Self) -> bool {
569        self == other
570    }
571}
572
573#[cfg(feature = "im")]
574impl<T: Data> Data for im::Vector<T> {
575    fn same(&self, other: &Self) -> bool {
576        // if a vec is small enough that it doesn't require an allocation
577        // it is 'inline'; in this case a pointer comparison is meaningless.
578        if self.is_inline() {
579            self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a.same(b))
580        } else {
581            self.ptr_eq(other)
582        }
583    }
584}
585
586#[cfg(feature = "im")]
587impl<K: Clone + 'static, V: Data> Data for im::HashMap<K, V> {
588    fn same(&self, other: &Self) -> bool {
589        self.ptr_eq(other)
590    }
591}
592
593#[cfg(feature = "im")]
594impl<T: Data> Data for im::HashSet<T> {
595    fn same(&self, other: &Self) -> bool {
596        self.ptr_eq(other)
597    }
598}
599
600#[cfg(feature = "im")]
601impl<K: Clone + 'static, V: Data> Data for im::OrdMap<K, V> {
602    fn same(&self, other: &Self) -> bool {
603        self.ptr_eq(other)
604    }
605}
606
607#[cfg(feature = "im")]
608impl<T: Data> Data for im::OrdSet<T> {
609    fn same(&self, other: &Self) -> bool {
610        self.ptr_eq(other)
611    }
612}
613
614impl<T: Data, const N: usize> Data for [T; N] {
615    fn same(&self, other: &Self) -> bool {
616        self.iter().zip(other.iter()).all(|(a, b)| a.same(b))
617    }
618}
619
620#[cfg(test)]
621mod test {
622    use super::Data;
623    use test_log::test;
624
625    #[test]
626    fn array_data() {
627        let input = [1u8, 0, 0, 1, 0];
628        assert!(input.same(&[1u8, 0, 0, 1, 0]));
629        assert!(!input.same(&[1u8, 1, 0, 1, 0]));
630    }
631
632    #[test]
633    #[cfg(feature = "im")]
634    fn im_data() {
635        for len in 8..256 {
636            let input = std::iter::repeat(0_u8).take(len).collect::<im::Vector<_>>();
637            let mut inp2 = input.clone();
638            assert!(input.same(&inp2));
639            inp2.set(len - 1, 98);
640            assert!(!input.same(&inp2));
641        }
642    }
643
644    #[test]
645    #[cfg(feature = "im")]
646    fn im_vec_different_length() {
647        let one = std::iter::repeat(0_u8).take(9).collect::<im::Vector<_>>();
648        let two = std::iter::repeat(0_u8).take(10).collect::<im::Vector<_>>();
649        assert!(!one.same(&two));
650    }
651
652    #[test]
653    fn static_strings() {
654        let first = "test";
655        let same = "test";
656        let second = "test2";
657        assert!(!Data::same(&first, &second));
658        assert!(Data::same(&first, &first));
659        // although these are different, the compiler will notice that the string "test" is common,
660        // intern it, and reuse it for all "text" `&'static str`s.
661        assert!(Data::same(&first, &same));
662    }
663}