1use crate::alloc::borrow::ToOwned;
2use alloc::format;
3use alloc::string::{String, ToString};
4
5#[derive(Copy, Clone)]
6pub enum NotationKind {
7 Iso,
9 Uns,
11 Alphanumeric,
13}
14
15#[derive(PartialEq, Clone, Copy, Debug)]
16pub enum QuadrantKind {
17 TopLeft,
18 TopRight,
19 BottomLeft,
20 BottomRight,
21}
22
23pub enum ToothType {
24 Incisor,
25 Canine,
26 Premolar,
27 Molar,
28}
29
30#[derive(PartialEq)]
34pub struct Tooth {
35 quadrant: QuadrantKind,
36 number: u8,
37 permanent: bool,
38}
39
40impl Tooth {
41 pub fn new(number: u8, quadrant: QuadrantKind, permanent: bool) -> Result<Tooth, String> {
42 if let Err(err) = Tooth::check_tooth_number(number, permanent) {
43 return Err(err);
44 }
45
46 Ok(Tooth {
47 number,
48 quadrant,
49 permanent,
50 })
51 }
52
53 fn check_tooth_number(number: u8, permanent: bool) -> Result<(), String> {
54 if permanent && (number < 1 || number > 8) {
55 Err(format!(
56 "Permanent tooth {} should be in range [1; 8]",
57 number
58 ))
59 } else if !permanent && (number < 1 || number > 5) {
60 Err(format!(
61 "Primary tooth {} should be in range [1; 5]",
62 number
63 ))
64 } else {
65 Ok(())
66 }
67 }
68
69 pub fn quadrant_max(permanent: bool) -> u8 {
71 if permanent {
72 8
73 } else {
74 5
75 }
76 }
77
78 pub fn from_iso(value: &str) -> Result<Self, String> {
79 if value.len() != 2 {
80 return Err(format!("{} is not a valid ISO dental notation", value));
81 }
82 let mut char_iter = value.chars();
83 let (quadrant, permanent) = match char_iter.next().unwrap() {
84 '1' => (QuadrantKind::TopLeft, true),
85 '2' => (QuadrantKind::TopRight, true),
86 '3' => (QuadrantKind::BottomRight, true),
87 '4' => (QuadrantKind::BottomLeft, true),
88 '5' => (QuadrantKind::TopLeft, false),
89 '6' => (QuadrantKind::TopRight, false),
90 '7' => (QuadrantKind::BottomRight, false),
91 '8' => (QuadrantKind::BottomLeft, false),
92 x => return Err(format!("Quadrant value {} not included in range [1; 8]", x)),
93 };
94
95 let tooth_string = char_iter.next().unwrap();
96 let tooth_number_option = tooth_string.to_digit(10);
97
98 if tooth_number_option.is_none() {
99 return Err(format!("{} is not a number", tooth_string));
100 }
101 let number = tooth_number_option.unwrap() as u8;
102 if let Err(err) = Tooth::check_tooth_number(number, permanent) {
103 return Err(err);
104 }
105 Ok(Tooth {
106 quadrant,
107 permanent,
108 number,
109 })
110 }
111
112 pub fn to_iso(&self) -> String {
113 let quadrant_number: u8 = match (&self.quadrant, self.permanent) {
114 (QuadrantKind::TopLeft, true) => 1,
115 (QuadrantKind::TopRight, true) => 2,
116 (QuadrantKind::BottomLeft, true) => 4,
117 (QuadrantKind::BottomRight, true) => 3,
118 (QuadrantKind::TopLeft, false) => 5,
119 (QuadrantKind::TopRight, false) => 6,
120 (QuadrantKind::BottomLeft, false) => 8,
121 (QuadrantKind::BottomRight, false) => 7,
122 };
123 quadrant_number.to_string() + &self.number.to_string()
124 }
125
126 pub fn from_uns(value: &str) -> Result<Self, String> {
127 let number_value_option = value.parse::<u8>();
128 let mut permanent = false;
129 let uns = if number_value_option.is_ok() {
130 permanent = true;
131 number_value_option.unwrap()
132 } else {
133 (value.chars().next().expect("No value available") as i32 - 64) as u8
134 };
135
136 if permanent && (uns < 1 || uns > 32) {
137 return Err(format!(
138 "UNS permanent tooth has to be in range [1; 32] (currently {})",
139 uns
140 ));
141 } else if !permanent && (uns < 1 || uns > 20) {
142 return Err(format!("UNS primary tooth has to be in range [A; T]"));
143 }
144 let max = Tooth::quadrant_max(permanent);
145 let quadrant = match ((uns - 1) / max) + 1 {
146 1 => QuadrantKind::TopLeft,
147 2 => QuadrantKind::TopRight,
148 3 => QuadrantKind::BottomRight,
149 4 => QuadrantKind::BottomLeft,
150 _ => return Err(format!("UNS tooth value not in range")),
151 };
152 let number = if quadrant == QuadrantKind::TopRight || quadrant == QuadrantKind::BottomLeft {
153 ((uns - 1) % max) + 1
154 } else {
155 max - ((uns - 1) % max)
156 };
157 if let Err(err) = Tooth::check_tooth_number(number, permanent) {
158 return Err(err);
159 }
160 Ok(Tooth {
161 quadrant,
162 number,
163 permanent,
164 })
165 }
166
167 pub fn to_uns(&self) -> String {
168 let max = Tooth::quadrant_max(self.permanent);
169 let value: u8 = match (&self.quadrant, self.number) {
170 (QuadrantKind::TopLeft, x) => max - x + 1,
171 (QuadrantKind::TopRight, x) => x + max,
172 (QuadrantKind::BottomRight, x) => (max - x + 1) + max * 2,
173 (QuadrantKind::BottomLeft, x) => x + max * 3,
174 };
175
176 if self.permanent {
177 format!("{:2}", value)
178 } else {
179 ((value + 64) as char).to_string()
180 }
181 }
182
183 pub fn from_alphanumeric(value: &str) -> Result<Self, String> {
184 if value.len() != 3 {
185 return Err(format!(
186 "{} is not a valid alphanumeric dental notation",
187 value
188 ));
189 }
190 let quadrant = match &value[0..2] {
191 "UL" => QuadrantKind::TopLeft,
192 "UR" => QuadrantKind::TopRight,
193 "LR" => QuadrantKind::BottomRight,
194 "LL" => QuadrantKind::BottomLeft,
195 x => {
196 return Err(format!(
197 "Quadrant value {} not a valid value (accepted: ['UL', 'UR', 'LR', 'LL'])",
198 x
199 ))
200 }
201 };
202
203 let tooth_string = &value[2..3];
204
205 let (number, permanent) = match tooth_string {
206 "1" => (1, true),
207 "2" => (2, true),
208 "3" => (3, true),
209 "4" => (4, true),
210 "5" => (5, true),
211 "6" => (6, true),
212 "7" => (7, true),
213 "8" => (8, true),
214 "A" => (1, false),
215 "B" => (2, false),
216 "C" => (3, false),
217 "D" => (4, false),
218 "E" => (5, false),
219 x => {
220 return Err(format!(
221 "Number value {} not a valid value (accepted: [1; 8] and ['A'; 'E'])",
222 x
223 ))
224 }
225 };
226 if let Err(err) = Tooth::check_tooth_number(number, permanent) {
227 return Err(err);
228 }
229 Ok(Tooth {
230 quadrant,
231 permanent,
232 number,
233 })
234 }
235
236 pub fn to_alphanumeric(&self) -> String {
237 let quadrant = match &self.quadrant {
238 QuadrantKind::TopLeft => "UL",
239 QuadrantKind::TopRight => "UR",
240 QuadrantKind::BottomRight => "LR",
241 QuadrantKind::BottomLeft => "LL",
242 };
243
244 let number = if self.permanent {
245 self.number.to_string()
246 } else {
247 ((self.number + 64) as char).to_string()
248 };
249 quadrant.to_owned() + &number
250 }
251
252 pub fn from(value: &str, from: &NotationKind) -> Result<Self, String> {
253 match from {
254 NotationKind::Iso => Tooth::from_iso(value),
255 NotationKind::Uns => Tooth::from_uns(value),
256 NotationKind::Alphanumeric => Tooth::from_alphanumeric(value),
257 }
258 }
259 pub fn to(&self, to: &NotationKind) -> String {
260 match to {
261 NotationKind::Iso => self.to_iso(),
262 NotationKind::Uns => self.to_uns(),
263 NotationKind::Alphanumeric => self.to_alphanumeric(),
264 }
265 }
266
267 #[deprecated(since = "1.0.0", note = "Use 'to' and 'from' directly")]
268 pub fn convert(from: &NotationKind, to: &NotationKind, value: &str) -> Result<String, String> {
269 let tooth_result = Tooth::from(value, from);
270
271 match tooth_result {
272 Ok(tooth) => Ok(tooth.to(to)),
273 Err(err) => Err(err),
274 }
275 }
276
277 pub fn get_type(&self) -> ToothType {
278 match (&self.number, &self.permanent) {
279 (1..=2, _) => ToothType::Incisor,
280 (3, _) => ToothType::Canine,
281 (4..=5, true) => ToothType::Premolar,
282 _ => ToothType::Molar,
283 }
284 }
285}
286
287#[cfg(test)]
288mod test {
289 use super::*;
290
291 macro_rules! to {
292 ($name:ident, $func:ident, $quadrant:expr,$number:expr, $permanent:expr, $value:expr) => {
293 #[test]
294 fn $name() {
295 let tooth = Tooth {
296 quadrant: $quadrant,
297 number: $number,
298 permanent: $permanent,
299 };
300 assert_eq!(tooth.$func(), $value);
301 }
302 };
303 }
304
305 macro_rules! from {
306 ($name:ident, $func:ident, $value:expr, $quadrant:expr,$number:expr, $permanent:expr) => {
307 #[test]
308 fn $name() {
309 let tooth = Tooth::$func($value).unwrap();
310
311 assert_eq!(tooth.quadrant, $quadrant);
312 assert_eq!(tooth.number, $number);
313 assert_eq!(tooth.permanent, $permanent);
314 }
315 };
316 }
317
318 macro_rules! from_fail {
319 ($name:ident, $func:ident, $value:expr) => {
320 #[test]
321 fn $name() {
322 assert!(Tooth::$func($value).is_err());
323 }
324 };
325 }
326
327 to!(to_iso_11, to_iso, QuadrantKind::TopLeft, 1, true, "11");
328 to!(to_iso_18, to_iso, QuadrantKind::TopLeft, 8, true, "18");
329 to!(to_iso_21, to_iso, QuadrantKind::TopRight, 1, true, "21");
330 to!(to_iso_28, to_iso, QuadrantKind::TopRight, 8, true, "28");
331 to!(to_iso_31, to_iso, QuadrantKind::BottomRight, 1, true, "31");
332 to!(to_iso_38, to_iso, QuadrantKind::BottomRight, 8, true, "38");
333 to!(to_iso_41, to_iso, QuadrantKind::BottomLeft, 1, true, "41");
334 to!(to_iso_48, to_iso, QuadrantKind::BottomLeft, 8, true, "48");
335 to!(to_iso_51, to_iso, QuadrantKind::TopLeft, 1, false, "51");
336 to!(to_iso_55, to_iso, QuadrantKind::TopLeft, 5, false, "55");
337 to!(to_iso_61, to_iso, QuadrantKind::TopRight, 1, false, "61");
338 to!(to_iso_65, to_iso, QuadrantKind::TopRight, 5, false, "65");
339 to!(to_iso_71, to_iso, QuadrantKind::BottomRight, 1, false, "71");
340 to!(to_iso_75, to_iso, QuadrantKind::BottomRight, 5, false, "75");
341 to!(to_iso_81, to_iso, QuadrantKind::BottomLeft, 1, false, "81");
342 to!(to_iso_85, to_iso, QuadrantKind::BottomLeft, 5, false, "85");
343
344 from!(from_iso_11, from_iso, "11", QuadrantKind::TopLeft, 1, true);
345 from!(from_iso_18, from_iso, "18", QuadrantKind::TopLeft, 8, true);
346 from!(from_iso_21, from_iso, "21", QuadrantKind::TopRight, 1, true);
347 from!(from_iso_28, from_iso, "28", QuadrantKind::TopRight, 8, true);
348 from!(
349 from_iso_31,
350 from_iso,
351 "31",
352 QuadrantKind::BottomRight,
353 1,
354 true
355 );
356 from!(
357 from_iso_38,
358 from_iso,
359 "38",
360 QuadrantKind::BottomRight,
361 8,
362 true
363 );
364 from!(
365 from_iso_41,
366 from_iso,
367 "41",
368 QuadrantKind::BottomLeft,
369 1,
370 true
371 );
372 from!(
373 from_iso_48,
374 from_iso,
375 "48",
376 QuadrantKind::BottomLeft,
377 8,
378 true
379 );
380 from!(from_iso_51, from_iso, "51", QuadrantKind::TopLeft, 1, false);
381 from!(from_iso_55, from_iso, "55", QuadrantKind::TopLeft, 5, false);
382 from!(
383 from_iso_61,
384 from_iso,
385 "61",
386 QuadrantKind::TopRight,
387 1,
388 false
389 );
390 from!(
391 from_iso_65,
392 from_iso,
393 "65",
394 QuadrantKind::TopRight,
395 5,
396 false
397 );
398 from!(
399 from_iso_71,
400 from_iso,
401 "71",
402 QuadrantKind::BottomRight,
403 1,
404 false
405 );
406 from!(
407 from_iso_75,
408 from_iso,
409 "75",
410 QuadrantKind::BottomRight,
411 5,
412 false
413 );
414 from!(
415 from_iso_81,
416 from_iso,
417 "81",
418 QuadrantKind::BottomLeft,
419 1,
420 false
421 );
422 from!(
423 from_iso_85,
424 from_iso,
425 "85",
426 QuadrantKind::BottomLeft,
427 5,
428 false
429 );
430
431 from_fail!(from_iso_fail_10, from_iso, "10");
432 from_fail!(from_iso_fail_19, from_iso, "19");
433 from_fail!(from_iso_fail_20, from_iso, "20");
434 from_fail!(from_iso_fail_29, from_iso, "29");
435 from_fail!(from_iso_fail_30, from_iso, "30");
436 from_fail!(from_iso_fail_39, from_iso, "39");
437 from_fail!(from_iso_fail_40, from_iso, "40");
438 from_fail!(from_iso_fail_49, from_iso, "49");
439 from_fail!(from_iso_fail_50, from_iso, "50");
440 from_fail!(from_iso_fail_56, from_iso, "56");
441 from_fail!(from_iso_fail_60, from_iso, "60");
442 from_fail!(from_iso_fail_66, from_iso, "66");
443 from_fail!(from_iso_fail_70, from_iso, "70");
444 from_fail!(from_iso_fail_76, from_iso, "76");
445 from_fail!(from_iso_fail_80, from_iso, "80");
446 from_fail!(from_iso_fail_86, from_iso, "86");
447
448 to!(to_uns_1, to_uns, QuadrantKind::TopLeft, 1, true, "8");
449 to!(to_uns_8, to_uns, QuadrantKind::TopLeft, 8, true, "1");
450 to!(to_uns_9, to_uns, QuadrantKind::TopRight, 1, true, "9");
451 to!(to_uns_16, to_uns, QuadrantKind::TopRight, 8, true, "16");
452 to!(to_uns_17, to_uns, QuadrantKind::BottomRight, 1, true, "24");
453 to!(to_uns_24, to_uns, QuadrantKind::BottomRight, 8, true, "17");
454 to!(to_uns_25, to_uns, QuadrantKind::BottomLeft, 1, true, "25");
455 to!(to_uns_32, to_uns, QuadrantKind::BottomLeft, 8, true, "32");
456 to!(to_uns_a, to_uns, QuadrantKind::TopLeft, 1, false, "E");
457 to!(to_uns_e, to_uns, QuadrantKind::TopLeft, 5, false, "A");
458 to!(to_uns_f, to_uns, QuadrantKind::TopRight, 1, false, "F");
459 to!(to_uns_j, to_uns, QuadrantKind::TopRight, 5, false, "J");
460 to!(to_uns_k, to_uns, QuadrantKind::BottomRight, 1, false, "O");
461 to!(to_uns_o, to_uns, QuadrantKind::BottomRight, 5, false, "K");
462 to!(to_uns_p, to_uns, QuadrantKind::BottomLeft, 1, false, "P");
463 to!(to_uns_t, to_uns, QuadrantKind::BottomLeft, 5, false, "T");
464
465 from!(from_uns_8, from_uns, "8", QuadrantKind::TopLeft, 1, true);
466 from!(from_uns_1, from_uns, "1", QuadrantKind::TopLeft, 8, true);
467 from!(from_uns_9, from_uns, "9", QuadrantKind::TopRight, 1, true);
468 from!(from_uns_16, from_uns, "16", QuadrantKind::TopRight, 8, true);
469 from!(
470 from_uns_24,
471 from_uns,
472 "24",
473 QuadrantKind::BottomRight,
474 1,
475 true
476 );
477 from!(
478 from_uns_17,
479 from_uns,
480 "17",
481 QuadrantKind::BottomRight,
482 8,
483 true
484 );
485 from!(
486 from_uns_25,
487 from_uns,
488 "25",
489 QuadrantKind::BottomLeft,
490 1,
491 true
492 );
493 from!(
494 from_uns_32,
495 from_uns,
496 "32",
497 QuadrantKind::BottomLeft,
498 8,
499 true
500 );
501 from!(from_uns_e, from_uns, "E", QuadrantKind::TopLeft, 1, false);
502 from!(from_uns_a, from_uns, "A", QuadrantKind::TopLeft, 5, false);
503 from!(from_uns_f, from_uns, "F", QuadrantKind::TopRight, 1, false);
504 from!(from_uns_j, from_uns, "J", QuadrantKind::TopRight, 5, false);
505 from!(
506 from_uns_o,
507 from_uns,
508 "O",
509 QuadrantKind::BottomRight,
510 1,
511 false
512 );
513 from!(
514 from_uns_k,
515 from_uns,
516 "K",
517 QuadrantKind::BottomRight,
518 5,
519 false
520 );
521 from!(
522 from_uns_p,
523 from_uns,
524 "P",
525 QuadrantKind::BottomLeft,
526 1,
527 false
528 );
529 from!(
530 from_uns_t,
531 from_uns,
532 "T",
533 QuadrantKind::BottomLeft,
534 5,
535 false
536 );
537
538 from_fail!(from_uns_fail_0, from_uns, "0");
539 from_fail!(from_uns_fail_33, from_uns, "33");
540 from_fail!(from_uns_fail_at, from_uns, "@");
541 from_fail!(from_uns_fail_u, from_uns, "U");
542
543 to!(
544 to_alphanumeric_ul1,
545 to_alphanumeric,
546 QuadrantKind::TopLeft,
547 1,
548 true,
549 "UL1"
550 );
551 to!(
552 to_alphanumeric_ul8,
553 to_alphanumeric,
554 QuadrantKind::TopLeft,
555 8,
556 true,
557 "UL8"
558 );
559 to!(
560 to_alphanumeric_ur1,
561 to_alphanumeric,
562 QuadrantKind::TopRight,
563 1,
564 true,
565 "UR1"
566 );
567 to!(
568 to_alphanumeric_ur8,
569 to_alphanumeric,
570 QuadrantKind::TopRight,
571 8,
572 true,
573 "UR8"
574 );
575 to!(
576 to_alphanumeric_lr1,
577 to_alphanumeric,
578 QuadrantKind::BottomRight,
579 1,
580 true,
581 "LR1"
582 );
583 to!(
584 to_alphanumeric_lr8,
585 to_alphanumeric,
586 QuadrantKind::BottomRight,
587 8,
588 true,
589 "LR8"
590 );
591 to!(
592 to_alphanumeric_ll1,
593 to_alphanumeric,
594 QuadrantKind::BottomLeft,
595 1,
596 true,
597 "LL1"
598 );
599 to!(
600 to_alphanumeric_ll8,
601 to_alphanumeric,
602 QuadrantKind::BottomLeft,
603 8,
604 true,
605 "LL8"
606 );
607 to!(
608 to_alphanumeric_ula,
609 to_alphanumeric,
610 QuadrantKind::TopLeft,
611 1,
612 false,
613 "ULA"
614 );
615 to!(
616 to_alphanumeric_ule,
617 to_alphanumeric,
618 QuadrantKind::TopLeft,
619 5,
620 false,
621 "ULE"
622 );
623 to!(
624 to_alphanumeric_ura,
625 to_alphanumeric,
626 QuadrantKind::TopRight,
627 1,
628 false,
629 "URA"
630 );
631 to!(
632 to_alphanumeric_ure,
633 to_alphanumeric,
634 QuadrantKind::TopRight,
635 5,
636 false,
637 "URE"
638 );
639 to!(
640 to_alphanumeric_lra,
641 to_alphanumeric,
642 QuadrantKind::BottomRight,
643 1,
644 false,
645 "LRA"
646 );
647 to!(
648 to_alphanumeric_lre,
649 to_alphanumeric,
650 QuadrantKind::BottomRight,
651 5,
652 false,
653 "LRE"
654 );
655 to!(
656 to_alphanumeric_lla,
657 to_alphanumeric,
658 QuadrantKind::BottomLeft,
659 1,
660 false,
661 "LLA"
662 );
663 to!(
664 to_alphanumeric_lle,
665 to_alphanumeric,
666 QuadrantKind::BottomLeft,
667 5,
668 false,
669 "LLE"
670 );
671 from!(
672 from_alphanumeric_ul1,
673 from_alphanumeric,
674 "UL1",
675 QuadrantKind::TopLeft,
676 1,
677 true
678 );
679 from!(
680 from_alphanumeric_ul8,
681 from_alphanumeric,
682 "UL8",
683 QuadrantKind::TopLeft,
684 8,
685 true
686 );
687 from!(
688 from_alphanumeric_ur1,
689 from_alphanumeric,
690 "UR1",
691 QuadrantKind::TopRight,
692 1,
693 true
694 );
695 from!(
696 from_alphanumeric_ur8,
697 from_alphanumeric,
698 "UR8",
699 QuadrantKind::TopRight,
700 8,
701 true
702 );
703 from!(
704 from_alphanumeric_lr1,
705 from_alphanumeric,
706 "LR1",
707 QuadrantKind::BottomRight,
708 1,
709 true
710 );
711 from!(
712 from_alphanumeric_lr8,
713 from_alphanumeric,
714 "LR8",
715 QuadrantKind::BottomRight,
716 8,
717 true
718 );
719 from!(
720 from_alphanumeric_ll1,
721 from_alphanumeric,
722 "LL1",
723 QuadrantKind::BottomLeft,
724 1,
725 true
726 );
727 from!(
728 from_alphanumeric_ll8,
729 from_alphanumeric,
730 "LL8",
731 QuadrantKind::BottomLeft,
732 8,
733 true
734 );
735 from!(
736 from_alphanumeric_ula,
737 from_alphanumeric,
738 "ULA",
739 QuadrantKind::TopLeft,
740 1,
741 false
742 );
743 from!(
744 from_alphanumeric_ule,
745 from_alphanumeric,
746 "ULE",
747 QuadrantKind::TopLeft,
748 5,
749 false
750 );
751 from!(
752 from_alphanumeric_ura,
753 from_alphanumeric,
754 "URA",
755 QuadrantKind::TopRight,
756 1,
757 false
758 );
759 from!(
760 from_alphanumeric_ure,
761 from_alphanumeric,
762 "URE",
763 QuadrantKind::TopRight,
764 5,
765 false
766 );
767 from!(
768 from_alphanumeric_lra,
769 from_alphanumeric,
770 "LRA",
771 QuadrantKind::BottomRight,
772 1,
773 false
774 );
775 from!(
776 from_alphanumeric_lre,
777 from_alphanumeric,
778 "LRE",
779 QuadrantKind::BottomRight,
780 5,
781 false
782 );
783 from!(
784 from_alphanumeric_lla,
785 from_alphanumeric,
786 "LLA",
787 QuadrantKind::BottomLeft,
788 1,
789 false
790 );
791 from!(
792 from_alphanumeric_lle,
793 from_alphanumeric,
794 "LLE",
795 QuadrantKind::BottomLeft,
796 5,
797 false
798 );
799 from_fail!(from_alphanumeric_fail_ul0, from_alphanumeric, "UL0");
800 from_fail!(from_alphanumeric_fail_ul9, from_alphanumeric, "UL9");
801 from_fail!(from_alphanumeric_fail_ur0, from_alphanumeric, "UR0");
802 from_fail!(from_alphanumeric_fail_ur9, from_alphanumeric, "UR9");
803 from_fail!(from_alphanumeric_fail_lr0, from_alphanumeric, "LR0");
804 from_fail!(from_alphanumeric_fail_lr9, from_alphanumeric, "LR9");
805 from_fail!(from_alphanumeric_fail_ll0, from_alphanumeric, "LL0");
806 from_fail!(from_alphanumeric_fail_ll9, from_alphanumeric, "LL9");
807 from_fail!(from_alphanumeric_fail_ulat, from_alphanumeric, "UL@");
808 from_fail!(from_alphanumeric_fail_ulf, from_alphanumeric, "ULF");
809 from_fail!(from_alphanumeric_fail_urat, from_alphanumeric, "UR@");
810 from_fail!(from_alphanumeric_fail_urf, from_alphanumeric, "URF");
811 from_fail!(from_alphanumeric_fail_lrat, from_alphanumeric, "LR@");
812 from_fail!(from_alphanumeric_fail_lrf, from_alphanumeric, "LRF");
813 from_fail!(from_alphanumeric_fail_llat, from_alphanumeric, "LL@");
814 from_fail!(from_alphanumeric_fail_llf, from_alphanumeric, "LLF");
815}