1use encoding8;
2use opts::{self, CFlag, Error::ConflictingOption};
3use results::{Error, Result};
4#[derive(Debug, Clone, Default)]
5pub struct Converter {
8 pub encode_to: EncodeTo,
10 pub case: Case,
12 pub swap_bytes: bool,
14}
15
16#[derive(Copy, Clone, Debug, PartialEq, Eq)]
17pub enum Case {
22 None,
23 Lower,
24 Upper,
25}
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
28#[allow(non_camel_case_types)]
29pub enum EncodeTo {
34 None,
35 ASCII,
37 EBCDIC,
39 IBM,
41 OLD_ASCII,
43 OLD_EBCDIC,
45 OLD_IBM,
47}
48pub trait ConvertSlice<T> {
51 fn convert_slice(&self, buf: &mut [T]);
53
54 fn convert_clone(&self, buf: &[T]) -> Vec<T>
57 where
58 T: Clone + Default,
59 {
60 let mut dest: Vec<T> = vec![T::default(); buf.len()];
61
62 dest.clone_from_slice(buf);
63 self.convert_slice(&mut dest);
64 dest
65 }
66 fn convert_copy(&self, buf: &[T]) -> Vec<T>
71 where
72 T: Copy + Default,
73 {
74 let mut dest: Vec<T> = vec![T::default(); buf.len()];
75
76 dest.copy_from_slice(buf);
77 self.convert_slice(&mut dest);
78 dest
79 }
80}
81
82impl Converter {
83 pub fn new(o: &opts::Opts) -> Result<Self> {
84 Ok(Converter {
85 encode_to: EncodeTo::new(&o.cflags)?,
86 case: Case::new(&o.cflags)?,
87 swap_bytes: o.cflag(CFlag::SWAB),
88 })
89 }
90}
91
92impl ConvertSlice<u8> for Converter {
93 fn convert_slice(&self, buf: &mut [u8]) {
94 match self.encode_to {
95 EncodeTo::ASCII | EncodeTo::OLD_ASCII => {
96 self.encode_to.convert_slice(buf);
98 self.case.convert_slice(buf);
99 },
100 _ => {
101 self.case.convert_slice(buf);
103 self.encode_to.convert_slice(buf);
104 },
105 };
106 if self.swap_bytes {
107 swap_pairs(buf)
108 }
109 }
110}
111impl<F, T> ConvertSlice<T> for F
112where
113 F: Fn(T) -> T,
114 T: Copy,
115{
116 fn convert_slice(&self, slice: &mut [T]) { slice.iter_mut().for_each(|t| *t = (self)(*t)) }
117}
118
119impl Default for EncodeTo {
120 fn default() -> Self { EncodeTo::None }
121}
122
123impl Case {
124 pub fn new(c: &CFlag) -> Result<Self> {
125 match (c.contains(CFlag::LCASE), c.contains(CFlag::UCASE)) {
126 (true, false) => Ok(Case::Lower),
127 (false, true) => Ok(Case::Upper),
128 (false, false) => Ok(Case::None),
129 (true, true) => Err(Error::from(ConflictingOption(
130 "options 'lcase' and 'ucase' are mutually exclusives",
131 ))),
132 }
133 }
134}
135
136impl ConvertSlice<u8> for Case {
137 fn convert_slice(&self, slice: &mut [u8]) {
138 match self {
139 Case::Lower => slice.iter_mut().for_each(u8::make_ascii_lowercase),
140 Case::Upper => slice.iter_mut().for_each(u8::make_ascii_uppercase),
141 Case::None => {},
142 }
143 }
144}
145
146pub fn swap_pairs<T>(slice: &mut [T]) { (0..(slice.len() / 2)).for_each(|i| slice.swap(2 * i, 2 * i + 1)) }
149
150impl EncodeTo {
151 fn new(c: &CFlag) -> Result<Self> {
152 match (
153 c.contains(CFlag::ASCII),
154 c.contains(CFlag::EBCDIC),
155 c.contains(CFlag::IBM),
156 c.contains(CFlag::OLDASCII),
157 c.contains(CFlag::OLDIBM),
158 c.contains(CFlag::OLDEBCDIC),
159 ) {
160 (true, false, false, false, false, false) => Ok(EncodeTo::ASCII),
161 (false, true, false, false, false, false) => Ok(EncodeTo::EBCDIC),
162 (false, false, true, false, false, false) => Ok(EncodeTo::IBM),
163 (false, false, false, true, false, false) => Ok(EncodeTo::OLD_ASCII),
164 (false, false, false, false, true, false) => Ok(EncodeTo::OLD_EBCDIC),
165 (false, false, false, false, false, true) => Ok(EncodeTo::OLD_IBM),
166 (false, false, false, false, false, false) => Ok(EncodeTo::None),
167 _ => Err(Error::from(ConflictingOption(concat!(
168 "must specify at most one of the following conversion flags: ",
169 "'ascii', 'ebcdic', 'ibm', 'old_ascii', 'old_ebcdic', 'old_imb'"
170 )))),
171 }
172 }
173}
174
175impl Default for Case {
176 fn default() -> Self { Case::None }
177}
178
179impl ConvertSlice<u8> for EncodeTo {
180 fn convert_slice(&self, s: &mut [u8]) {
181 match self {
182 EncodeTo::ASCII => s.iter_mut().for_each(encoding8::ebcdic::make_ascii),
183 EncodeTo::EBCDIC => s.iter_mut().for_each(encoding8::ascii::make_ebcdic),
184 EncodeTo::None => {},
185 encoding => unimplemented!("EncodeTo::{:?}.convert_slice", encoding),
186 }
187 }
188}