unic_ucd_age/
age.rs

1// Copyright 2017 The UNIC Project Developers.
2//
3// See the COPYRIGHT file at the top-level directory of this distribution.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11use core::cmp;
12
13use unic_char_property::{CharProperty, CustomCharProperty, PartialCharProperty};
14pub use unic_ucd_version::UnicodeVersion;
15
16/// Represents values of the Unicode character property
17/// [*Age*](https://www.unicode.org/reports/tr44/#Age).
18///
19/// The Age property indicates the age of a character, which is defined based on the first Unicode
20/// version in which a particular Unicode character was *assigned* (as *character* or
21/// *noncharacter*).
22///
23/// Note: `Age` type has a reverse ordering compared to `UnicodeVersion`, because a character is
24/// *older* (has greater age) of another character if, and only if, it has a older (smaller)
25/// `UnicodeVersion` number.
26///
27/// Unicode versions with character *assignement* always have the Micro (Update) version value
28/// of zero (`0`). Therefore, all `UnicodeVersion` values return from `Age` will have their `macro`
29/// field as `0`.
30///
31/// The *earliest* (largest) value for this property is `UnicodeVersion { major: 1, minor: 1, micro:
32/// 0 }`, because of the massive changes for the merger of the Unicode Standard with ISO 10646.
33///
34/// The *latest* (smallest) value for this property is always equal to or greater than
35/// `UNICODE_VERSION`. (Only not equal when `UNICODE_VERSION` has non-zero *micro* value.)
36///
37/// * <https://www.unicode.org/reports/tr44/#Character_Age>
38#[derive(Clone, Copy, Eq, PartialEq, Ord, Debug, Hash)]
39pub struct Age(UnicodeVersion);
40
41impl CharProperty for Age {
42    fn prop_abbr_name() -> &'static str {
43        "age"
44    }
45
46    fn prop_long_name() -> &'static str {
47        "Age"
48    }
49
50    fn prop_human_name() -> &'static str {
51        "Age"
52    }
53}
54
55impl PartialCharProperty for Age {
56    fn of(ch: char) -> Option<Self> {
57        Self::of(ch)
58    }
59}
60
61impl CustomCharProperty<UnicodeVersion> for Age {
62    /// Get numeric value for character property value
63    fn actual(&self) -> UnicodeVersion {
64        Self::actual(self)
65    }
66}
67
68mod data {
69    use super::UnicodeVersion;
70    use unic_char_property::tables::CharDataTable;
71    pub const AGE_TABLE: CharDataTable<UnicodeVersion> = include!("../tables/age_values.rsv");
72}
73
74impl Age {
75    /// Find the character *Age* property value.
76    pub fn of(ch: char) -> Option<Age> {
77        data::AGE_TABLE.find(ch).map(Age)
78    }
79
80    /// Return the `UnicodeVersion` value of the age.
81    pub fn actual(&self) -> UnicodeVersion {
82        self.0
83    }
84}
85
86impl cmp::PartialOrd for Age {
87    fn partial_cmp(&self, other: &Age) -> Option<cmp::Ordering> {
88        match self.0.cmp(&other.0) {
89            cmp::Ordering::Greater => Some(cmp::Ordering::Less),
90            cmp::Ordering::Less => Some(cmp::Ordering::Greater),
91            cmp::Ordering::Equal => Some(cmp::Ordering::Equal),
92        }
93    }
94}
95
96/// Methods for character age property.
97pub trait CharAge {
98    /// Get `Age` of the character.
99    fn age(self) -> Option<Age>;
100}
101
102impl CharAge for char {
103    #[inline]
104    fn age(self) -> Option<Age> {
105        Age::of(self)
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::Age;
112    use unic_ucd_version::UnicodeVersion;
113
114    #[test]
115    fn test_values() {
116        // ASCII
117        assert_eq!(
118            Age::of('\u{0000}'),
119            Some(Age(UnicodeVersion {
120                major: 1,
121                minor: 1,
122                micro: 0,
123            }))
124        );
125        assert_eq!(
126            Age::of('\u{0021}'),
127            Some(Age(UnicodeVersion {
128                major: 1,
129                minor: 1,
130                micro: 0,
131            }))
132        );
133        assert_eq!(
134            Age::of('\u{0041}'),
135            Some(Age(UnicodeVersion {
136                major: 1,
137                minor: 1,
138                micro: 0,
139            }))
140        );
141        assert_eq!(
142            Age::of('\u{007f}'),
143            Some(Age(UnicodeVersion {
144                major: 1,
145                minor: 1,
146                micro: 0,
147            }))
148        );
149
150        assert_eq!(
151            Age::of('\u{0100}'),
152            Some(Age(UnicodeVersion {
153                major: 1,
154                minor: 1,
155                micro: 0,
156            }))
157        );
158        assert_eq!(
159            Age::of('\u{01f5}'),
160            Some(Age(UnicodeVersion {
161                major: 1,
162                minor: 1,
163                micro: 0,
164            }))
165        );
166        assert_eq!(
167            Age::of('\u{037e}'),
168            Some(Age(UnicodeVersion {
169                major: 1,
170                minor: 1,
171                micro: 0,
172            }))
173        );
174        assert_eq!(
175            Age::of('\u{200c}'),
176            Some(Age(UnicodeVersion {
177                major: 1,
178                minor: 1,
179                micro: 0,
180            }))
181        );
182
183        assert_eq!(
184            Age::of('\u{01f6}'),
185            Some(Age(UnicodeVersion {
186                major: 3,
187                minor: 0,
188                micro: 0,
189            }))
190        );
191        assert_eq!(
192            Age::of('\u{01f7}'),
193            Some(Age(UnicodeVersion {
194                major: 3,
195                minor: 0,
196                micro: 0,
197            }))
198        );
199        assert_eq!(
200            Age::of('\u{01f9}'),
201            Some(Age(UnicodeVersion {
202                major: 3,
203                minor: 0,
204                micro: 0,
205            }))
206        );
207
208        assert_eq!(
209            Age::of('\u{0860}'),
210            Some(Age(UnicodeVersion {
211                major: 10,
212                minor: 0,
213                micro: 0,
214            }))
215        );
216        assert_eq!(
217            Age::of('\u{0866}'),
218            Some(Age(UnicodeVersion {
219                major: 10,
220                minor: 0,
221                micro: 0,
222            }))
223        );
224        assert_eq!(
225            Age::of('\u{086a}'),
226            Some(Age(UnicodeVersion {
227                major: 10,
228                minor: 0,
229                micro: 0,
230            }))
231        );
232
233        assert_eq!(
234            Age::of('\u{fffe}'),
235            Some(Age(UnicodeVersion {
236                major: 1,
237                minor: 1,
238                micro: 0,
239            }))
240        );
241        assert_eq!(
242            Age::of('\u{ffff}'),
243            Some(Age(UnicodeVersion {
244                major: 1,
245                minor: 1,
246                micro: 0,
247            }))
248        );
249
250        assert_eq!(
251            Age::of('\u{10000}'),
252            Some(Age(UnicodeVersion {
253                major: 4,
254                minor: 0,
255                micro: 0,
256            }))
257        );
258        assert_eq!(
259            Age::of('\u{10001}'),
260            Some(Age(UnicodeVersion {
261                major: 4,
262                minor: 0,
263                micro: 0,
264            }))
265        );
266
267        assert_eq!(
268            Age::of('\u{e0100}'),
269            Some(Age(UnicodeVersion {
270                major: 4,
271                minor: 0,
272                micro: 0,
273            }))
274        );
275        assert_eq!(
276            Age::of('\u{e0101}'),
277            Some(Age(UnicodeVersion {
278                major: 4,
279                minor: 0,
280                micro: 0,
281            }))
282        );
283        assert_eq!(
284            Age::of('\u{e0170}'),
285            Some(Age(UnicodeVersion {
286                major: 4,
287                minor: 0,
288                micro: 0,
289            }))
290        );
291        assert_eq!(
292            Age::of('\u{e01ee}'),
293            Some(Age(UnicodeVersion {
294                major: 4,
295                minor: 0,
296                micro: 0,
297            }))
298        );
299        assert_eq!(
300            Age::of('\u{e01ef}'),
301            Some(Age(UnicodeVersion {
302                major: 4,
303                minor: 0,
304                micro: 0,
305            }))
306        );
307
308        assert_eq!(
309            Age::of('\u{10000}'),
310            Some(Age(UnicodeVersion {
311                major: 4,
312                minor: 0,
313                micro: 0,
314            }))
315        );
316
317        assert_eq!(
318            Age::of('\u{20000}'),
319            Some(Age(UnicodeVersion {
320                major: 3,
321                minor: 1,
322                micro: 0,
323            }))
324        );
325
326        assert_eq!(Age::of('\u{30000}'), None);
327        assert_eq!(Age::of('\u{40000}'), None);
328        assert_eq!(Age::of('\u{50000}'), None);
329        assert_eq!(Age::of('\u{60000}'), None);
330        assert_eq!(Age::of('\u{70000}'), None);
331        assert_eq!(Age::of('\u{80000}'), None);
332        assert_eq!(Age::of('\u{90000}'), None);
333        assert_eq!(Age::of('\u{a0000}'), None);
334        assert_eq!(Age::of('\u{b0000}'), None);
335        assert_eq!(Age::of('\u{c0000}'), None);
336        assert_eq!(Age::of('\u{d0000}'), None);
337        assert_eq!(Age::of('\u{e0000}'), None);
338        assert_eq!(Age::of('\u{efffd}'), None);
339
340        assert_eq!(
341            Age::of('\u{efffe}'),
342            Some(Age(UnicodeVersion {
343                major: 2,
344                minor: 0,
345                micro: 0,
346            }))
347        );
348        assert_eq!(
349            Age::of('\u{effff}'),
350            Some(Age(UnicodeVersion {
351                major: 2,
352                minor: 0,
353                micro: 0,
354            }))
355        );
356
357        // Priavte-Use Area
358        assert_eq!(
359            Age::of('\u{f0000}'),
360            Some(Age(UnicodeVersion {
361                major: 2,
362                minor: 0,
363                micro: 0,
364            }))
365        );
366        assert_eq!(
367            Age::of('\u{f0001}'),
368            Some(Age(UnicodeVersion {
369                major: 2,
370                minor: 0,
371                micro: 0,
372            }))
373        );
374        assert_eq!(
375            Age::of('\u{ffffe}'),
376            Some(Age(UnicodeVersion {
377                major: 2,
378                minor: 0,
379                micro: 0,
380            }))
381        );
382        assert_eq!(
383            Age::of('\u{fffff}'),
384            Some(Age(UnicodeVersion {
385                major: 2,
386                minor: 0,
387                micro: 0,
388            }))
389        );
390        assert_eq!(
391            Age::of('\u{100000}'),
392            Some(Age(UnicodeVersion {
393                major: 2,
394                minor: 0,
395                micro: 0,
396            }))
397        );
398        assert_eq!(
399            Age::of('\u{100001}'),
400            Some(Age(UnicodeVersion {
401                major: 2,
402                minor: 0,
403                micro: 0,
404            }))
405        );
406        assert_eq!(
407            Age::of('\u{10fffe}'),
408            Some(Age(UnicodeVersion {
409                major: 2,
410                minor: 0,
411                micro: 0,
412            }))
413        );
414        assert_eq!(
415            Age::of('\u{10ffff}'),
416            Some(Age(UnicodeVersion {
417                major: 2,
418                minor: 0,
419                micro: 0,
420            }))
421        );
422    }
423
424    #[test]
425    fn test_cmp() {
426        assert!(Age::of('A') == Age::of('a'));
427        assert!(Age::of('A') > Age::of('Ɐ'));
428        assert!(Age::of('A') > Age::of('\u{10000}'));
429        assert!(Age::of('A') > Age::of('\u{D0000}'));
430
431        assert!(
432            Some(Age(UnicodeVersion {
433                major: 1,
434                minor: 1,
435                micro: 0,
436            })) == Some(Age(UnicodeVersion {
437                major: 1,
438                minor: 1,
439                micro: 0,
440            }))
441        );
442        assert!(
443            Some(Age(UnicodeVersion {
444                major: 1,
445                minor: 1,
446                micro: 0,
447            })) > Some(Age(UnicodeVersion {
448                major: 2,
449                minor: 0,
450                micro: 0,
451            }))
452        );
453        assert!(
454            Some(Age(UnicodeVersion {
455                major: 1,
456                minor: 1,
457                micro: 0,
458            })) > Some(Age(UnicodeVersion {
459                major: 3,
460                minor: 0,
461                micro: 0,
462            }))
463        );
464        assert!(
465            Some(Age(UnicodeVersion {
466                major: 1,
467                minor: 1,
468                micro: 0,
469            })) > Some(Age(UnicodeVersion {
470                major: 10,
471                minor: 0,
472                micro: 0,
473            }))
474        );
475        assert!(
476            Some(Age(UnicodeVersion {
477                major: 1,
478                minor: 1,
479                micro: 0,
480            })) > None
481        );
482
483        assert!(
484            Some(Age(UnicodeVersion {
485                major: 2,
486                minor: 0,
487                micro: 0,
488            })) < Some(Age(UnicodeVersion {
489                major: 1,
490                minor: 1,
491                micro: 0,
492            }))
493        );
494        assert!(
495            Some(Age(UnicodeVersion {
496                major: 2,
497                minor: 0,
498                micro: 0,
499            })) == Some(Age(UnicodeVersion {
500                major: 2,
501                minor: 0,
502                micro: 0,
503            }))
504        );
505        assert!(
506            Some(Age(UnicodeVersion {
507                major: 2,
508                minor: 0,
509                micro: 0,
510            })) > Some(Age(UnicodeVersion {
511                major: 3,
512                minor: 0,
513                micro: 0,
514            }))
515        );
516        assert!(
517            Some(Age(UnicodeVersion {
518                major: 2,
519                minor: 0,
520                micro: 0,
521            })) > Some(Age(UnicodeVersion {
522                major: 10,
523                minor: 0,
524                micro: 0,
525            }))
526        );
527        assert!(
528            Some(Age(UnicodeVersion {
529                major: 2,
530                minor: 0,
531                micro: 0,
532            })) > None
533        );
534
535        assert!(
536            Some(Age(UnicodeVersion {
537                major: 3,
538                minor: 0,
539                micro: 0,
540            })) < Some(Age(UnicodeVersion {
541                major: 1,
542                minor: 1,
543                micro: 0,
544            }))
545        );
546        assert!(
547            Some(Age(UnicodeVersion {
548                major: 3,
549                minor: 0,
550                micro: 0,
551            })) < Some(Age(UnicodeVersion {
552                major: 2,
553                minor: 0,
554                micro: 0,
555            }))
556        );
557        assert!(
558            Some(Age(UnicodeVersion {
559                major: 3,
560                minor: 0,
561                micro: 0,
562            })) == Some(Age(UnicodeVersion {
563                major: 3,
564                minor: 0,
565                micro: 0,
566            }))
567        );
568        assert!(
569            Some(Age(UnicodeVersion {
570                major: 3,
571                minor: 0,
572                micro: 0,
573            })) > Some(Age(UnicodeVersion {
574                major: 10,
575                minor: 0,
576                micro: 0,
577            }))
578        );
579        assert!(
580            Some(Age(UnicodeVersion {
581                major: 3,
582                minor: 0,
583                micro: 0,
584            })) > None
585        );
586
587        assert!(
588            Some(Age(UnicodeVersion {
589                major: 10,
590                minor: 0,
591                micro: 0,
592            })) < Some(Age(UnicodeVersion {
593                major: 1,
594                minor: 1,
595                micro: 0,
596            }))
597        );
598        assert!(
599            Some(Age(UnicodeVersion {
600                major: 10,
601                minor: 0,
602                micro: 0,
603            })) < Some(Age(UnicodeVersion {
604                major: 2,
605                minor: 0,
606                micro: 0,
607            }))
608        );
609        assert!(
610            Some(Age(UnicodeVersion {
611                major: 10,
612                minor: 0,
613                micro: 0,
614            })) < Some(Age(UnicodeVersion {
615                major: 3,
616                minor: 0,
617                micro: 0,
618            }))
619        );
620        assert!(
621            Some(Age(UnicodeVersion {
622                major: 10,
623                minor: 0,
624                micro: 0,
625            })) == Some(Age(UnicodeVersion {
626                major: 10,
627                minor: 0,
628                micro: 0,
629            }))
630        );
631        assert!(
632            Some(Age(UnicodeVersion {
633                major: 10,
634                minor: 0,
635                micro: 0,
636            })) > None
637        );
638
639        assert!(
640            None < Some(Age(UnicodeVersion {
641                major: 1,
642                minor: 1,
643                micro: 0,
644            }))
645        );
646        assert!(
647            None < Some(Age(UnicodeVersion {
648                major: 2,
649                minor: 0,
650                micro: 0,
651            }))
652        );
653        assert!(
654            None < Some(Age(UnicodeVersion {
655                major: 3,
656                minor: 0,
657                micro: 0,
658            }))
659        );
660        assert!(
661            None < Some(Age(UnicodeVersion {
662                major: 10,
663                minor: 0,
664                micro: 0,
665            }))
666        );
667    }
668
669    #[test]
670    fn test_char_trait() {
671        use super::CharAge;
672
673        assert_eq!(
674            '\u{0000}'.age().unwrap().actual(),
675            UnicodeVersion {
676                major: 1,
677                minor: 1,
678                micro: 0,
679            }
680        );
681        assert_eq!(
682            '\u{0041}'.age().unwrap().actual(),
683            UnicodeVersion {
684                major: 1,
685                minor: 1,
686                micro: 0,
687            }
688        );
689        assert_eq!(
690            '\u{10ffff}'.age().unwrap().actual(),
691            UnicodeVersion {
692                major: 2,
693                minor: 0,
694                micro: 0,
695            }
696        );
697    }
698}