rot13/
rot13.rs

1// This is a part of encoding-next.
2// Copyright (c) 2015, Simonas Kazlauskas
3// See README.md and LICENSE.txt for details.
4
5/**
6 * Rotation by 13 places encoding.
7 *
8 * This example demonstrates how to use encoding-types package to implement your own encodings.
9 */
10extern crate encoding_types;
11
12use encoding_types::*;
13use std::str::from_utf8;
14
15#[derive(Clone, Copy)]
16pub struct ROT13Encoding;
17
18impl Encoding for ROT13Encoding {
19    fn name(&self) -> &'static str {
20        "rot13"
21    }
22    fn whatwg_name(&self) -> Option<&'static str> {
23        None
24    }
25    fn raw_encoder(&self) -> Box<dyn RawEncoder> {
26        ROT13Encoder::new()
27    }
28    fn raw_decoder(&self) -> Box<dyn RawDecoder> {
29        ROT13Decoder::new()
30    }
31}
32
33#[derive(Clone, Copy)]
34pub struct ROT13Encoder;
35
36impl ROT13Encoder {
37    #[allow(clippy::new_ret_no_self)]
38    pub fn new() -> Box<dyn RawEncoder> {
39        Box::new(ROT13Encoder)
40    }
41}
42
43impl RawEncoder for ROT13Encoder {
44    fn from_self(&self) -> Box<dyn RawEncoder> {
45        ROT13Encoder::new()
46    }
47    fn is_ascii_compatible(&self) -> bool {
48        true
49    }
50
51    fn raw_feed(
52        &mut self,
53        input: &str,
54        output: &mut dyn ByteWriter,
55    ) -> (usize, Option<CodecError>) {
56        output.writer_hint(input.len());
57        for byte in input.bytes() {
58            output.write_byte(rotate_byte(byte))
59        }
60        (input.len(), None)
61    }
62
63    fn raw_finish(&mut self, _output: &mut dyn ByteWriter) -> Option<CodecError> {
64        None
65    }
66}
67
68#[derive(Clone, Copy)]
69pub struct ROT13Decoder;
70
71impl ROT13Decoder {
72    #[allow(clippy::new_ret_no_self)]
73    pub fn new() -> Box<dyn RawDecoder> {
74        Box::new(ROT13Decoder)
75    }
76}
77
78impl RawDecoder for ROT13Decoder {
79    fn from_self(&self) -> Box<dyn RawDecoder> {
80        ROT13Decoder::new()
81    }
82    fn is_ascii_compatible(&self) -> bool {
83        true
84    }
85
86    fn raw_feed(
87        &mut self,
88        input: &[u8],
89        output: &mut dyn StringWriter,
90    ) -> (usize, Option<CodecError>) {
91        output.writer_hint(input.len());
92        let string = match from_utf8(input) {
93            Ok(s) => s,
94            Err(_e) => {
95                return (
96                    0,
97                    Some(CodecError {
98                        upto: 0, // Utf8Error::valid_up_to is unstable at the time of writing,
99                        // therefore we can’t quite do partial parsing yet
100                        cause: "input is not valid utf-8".into(),
101                    }),
102                );
103            }
104        };
105        for ch in string.chars() {
106            match ch {
107                'a'..='z' | 'A'..='Z' => output.write_char(rotate_byte(ch as u8) as char),
108                _ => output.write_char(ch),
109            }
110        }
111        (input.len(), None)
112    }
113
114    fn raw_finish(&mut self, _output: &mut dyn StringWriter) -> Option<CodecError> {
115        None
116    }
117}
118
119fn rotate_byte(byte: u8) -> u8 {
120    match byte {
121        b'a'..=b'm' | b'A'..=b'M' => byte + 13,
122        b'n'..=b'z' | b'N'..=b'Z' => byte - 13,
123        _ => byte,
124    }
125}
126
127fn main() {
128    use std::io;
129    use std::io::Read;
130
131    let mut ret = Vec::new();
132    io::stdin()
133        .read_to_end(&mut ret)
134        .expect("cannot read from the input");
135    match ROT13Encoding.decode(&ret, DecoderTrap::Strict) {
136        Ok(s) => println!("{}", s),
137        Err(e) => panic!("decoder error: {}", e),
138    };
139}