codepage_437/
decode.rs

1use self::super::Cp437Dialect;
2use std::iter::FromIterator;
3use std::borrow::Cow;
4use std::str;
5
6
7/// Move data encoded in cp437 to a Unicode container of the specified type.
8///
9/// # Examples
10///
11/// ```
12/// # use codepage_437::{CP437_CONTROL, FromCp437};
13/// let cp437 = vec![0x4C, 0x6F, 0x63, 0x61, 0x6C, 0x20, 0x6E, 0x65, 0x77, 0x73, 0x20, 0x72, 0x65,
14///                  0x70, 0x6F, 0x72, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68,
15///                  0x65, 0x20, 0x9E, 0xAB, 0x20, 0x6D, 0x69, 0x6C, 0x6C, 0x69, 0x6F, 0x6E, 0x20,
16///                  0x41, 0x69, 0x72, 0x20, 0x4D, 0x65, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x69, 0x91,
17///                  0x20, 0x61, 0x69, 0x72, 0x63, 0x72, 0x61, 0x66, 0x74, 0x20, 0x68, 0x61, 0x73,
18///                  0x20, 0x63, 0x72, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73,
19///                  0x20, 0x6D, 0x6F, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x72, 0x6F, 0x75,
20///                  0x6E, 0x64, 0x20, 0x39, 0x3A, 0x30, 0x30, 0x61, 0x6D, 0x2E];
21/// let unicode = "Local news reports that the ₧½ million Air Melanesiæ aircraft has crashed this morning around 9:00am.";
22///
23/// assert_eq!(String::from_cp437(cp437, &CP437_CONTROL), unicode);  // cp437 is moved out of
24/// ```
25pub trait FromCp437<T: Sized> {
26    /// Do the conversion.
27    fn from_cp437(cp437: T, dialect: &Cp437Dialect) -> Self;
28}
29
30macro_rules! from_cp437_slice_impl {
31    ($($l:expr)*) => ($(
32        impl FromCp437<[u8; $l]> for String {
33            fn from_cp437(cp437: [u8; $l], dialect: &Cp437Dialect) -> Self {
34                from_cp437_slice_impl(&cp437, dialect)
35            }
36        }
37    )*)
38}
39
40impl FromCp437<Vec<u8>> for String {
41    fn from_cp437(cp437: Vec<u8>, dialect: &Cp437Dialect) -> Self {
42        if cp437.iter().all(|&b| dialect.overlap_cp437(b)) {
43            String::from_utf8(cp437).unwrap()
44        } else {
45            String::from_iter(cp437.into_iter().map(|b| dialect.decode(b)))
46        }
47    }
48}
49
50impl FromCp437<[u8; 0]> for String {
51    fn from_cp437(_: [u8; 0], _: &Cp437Dialect) -> Self {
52        String::new()
53    }
54}
55
56from_cp437_slice_impl!(    1  2  3  4  5  6  7  8  9
57                       10 11 12 13 14 15 16 17 18 19
58                       20 21 22 23 24 25 26 27 28 29
59                       30 31 32);
60
61fn from_cp437_slice_impl(cp437: &[u8], dialect: &Cp437Dialect) -> String {
62    if cp437.iter().all(|&b| dialect.overlap_cp437(b)) {
63        String::from_utf8(cp437.to_vec()).unwrap()
64    } else {
65        String::from_iter(cp437.iter().map(|&b| dialect.decode(b)))
66    }
67}
68
69
70/// Try to borrow data encoded in cp437 as a Unicode container of the specified type.
71///
72/// If that cannot be done, clone it.
73///
74/// # Examples
75///
76/// ```
77/// # use codepage_437::{CP437_CONTROL, BorrowFromCp437};
78/// # use std::borrow::Cow;
79/// let cp437 = [0x4C, 0x6F, 0x63, 0x61, 0x6C, 0x20, 0x6E, 0x65, 0x77, 0x73, 0x20, 0x72, 0x65,
80///              0x70, 0x6F, 0x72, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68,
81///              0x65, 0x20, 0x9E, 0xAB, 0x20, 0x6D, 0x69, 0x6C, 0x6C, 0x69, 0x6F, 0x6E, 0x20,
82///              0x41, 0x69, 0x72, 0x20, 0x4D, 0x65, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x69, 0x91,
83///              0x20, 0x61, 0x69, 0x72, 0x63, 0x72, 0x61, 0x66, 0x74, 0x20, 0x68, 0x61, 0x73,
84///              0x20, 0x63, 0x72, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73,
85///              0x20, 0x6D, 0x6F, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x72, 0x6F, 0x75,
86///              0x6E, 0x64, 0x20, 0x39, 0x3A, 0x30, 0x30, 0x61, 0x6D, 0x2E];
87/// let unicode = "Local news reports that the ₧½ million Air Melanesiæ aircraft has crashed this morning around 9:00am.";
88///
89/// assert_eq!(Cow::borrow_from_cp437(&cp437[..], &CP437_CONTROL),
90///            String::borrow_from_cp437(&cp437[..], &CP437_CONTROL));
91/// assert_eq!(Cow::borrow_from_cp437(&cp437[..], &CP437_CONTROL), unicode);
92/// ```
93pub trait BorrowFromCp437<'c, T: ?Sized> {
94    /// Do the conversion.
95    fn borrow_from_cp437(cp437: &'c T, dialect: &Cp437Dialect) -> Self;
96}
97
98impl<'c, T: AsRef<[u8]> + ?Sized> BorrowFromCp437<'c, T> for Cow<'c, str> {
99    fn borrow_from_cp437(cp437: &'c T, dialect: &Cp437Dialect) -> Self {
100        borrow_from_cp437_cow_slice_impl(cp437.as_ref(), dialect)
101    }
102}
103
104impl<'c, T: AsRef<[u8]> + ?Sized> BorrowFromCp437<'c, T> for String {
105    fn borrow_from_cp437(cp437: &'c T, dialect: &Cp437Dialect) -> Self {
106        borrow_from_cp437_string_slice_impl(cp437.as_ref(), dialect)
107    }
108}
109
110fn borrow_from_cp437_cow_slice_impl<'c>(cp437: &'c [u8], dialect: &Cp437Dialect) -> Cow<'c, str> {
111    if cp437.iter().all(|&b| dialect.overlap_cp437(b)) {
112        Cow::Borrowed(str::from_utf8(&cp437[..]).unwrap())
113    } else {
114        Cow::Owned(String::from_iter(cp437.iter().map(|&b| dialect.decode(b))))
115    }
116}
117
118fn borrow_from_cp437_string_slice_impl(cp437: &[u8], dialect: &Cp437Dialect) -> String {
119    if cp437.iter().all(|&b| dialect.overlap_cp437(b)) {
120        String::from_utf8(cp437.to_vec()).unwrap()
121    } else {
122        String::from_iter(cp437.iter().map(|&b| dialect.decode(b)))
123    }
124}