muter 0.7.0

utility for converting data between various formats and encodings
Documentation
use codec;
use codec::CodecSettings;
use codec::CodecTransform;
use codec::Error;
use std::collections::btree_map;
use std::collections::BTreeMap;
use std::io;

type Iter<'a> = btree_map::Iter<'a, &'static str, Box<CodecTransform>>;

#[derive(Default)]
pub struct CodecRegistry {
    map: BTreeMap<&'static str, Box<CodecTransform>>,
}

impl CodecRegistry {
    pub fn new() -> Self {
        let mut map: BTreeMap<&'static str, Box<CodecTransform>> = BTreeMap::new();

        map.insert(
            "ascii85",
            Box::new(codec::codecs::ascii85::Ascii85TransformFactory::new()),
        );
        map.insert(
            "base16",
            Box::new(codec::codecs::base16::TransformFactory::new()),
        );
        map.insert(
            "base32",
            Box::new(codec::codecs::base32::Base32TransformFactory::new()),
        );
        map.insert(
            "base32hex",
            Box::new(codec::codecs::base32::Base32HexTransformFactory::new()),
        );
        map.insert(
            "base64",
            Box::new(codec::codecs::base64::Base64TransformFactory::new()),
        );
        map.insert(
            "bubblebabble",
            Box::new(codec::codecs::bubblebabble::TransformFactory::new()),
        );
        map.insert(
            "checksum",
            Box::new(codec::codecs::checksum::TransformFactory::new()),
        );
        map.insert(
            "crlf",
            Box::new(codec::codecs::crlf::TransformFactory::new()),
        );
        map.insert(
            "deflate",
            Box::new(codec::codecs::compress::DeflateTransformFactory::new()),
        );
        map.insert(
            "form",
            Box::new(codec::codecs::uri::FormTransformFactory::new()),
        );
        map.insert(
            "gzip",
            Box::new(codec::codecs::compress::GzipTransformFactory::new()),
        );
        map.insert(
            "hash",
            Box::new(codec::codecs::hash::TransformFactory::new()),
        );
        map.insert("hex", Box::new(codec::codecs::hex::TransformFactory::new()));
        map.insert(
            "identity",
            Box::new(codec::codecs::identity::TransformFactory::new()),
        );
        map.insert("lf", Box::new(codec::codecs::lf::TransformFactory::new()));
        map.insert(
            "modhex",
            Box::new(codec::codecs::hex::ModHexTransformFactory::new()),
        );
        map.insert(
            "swab",
            Box::new(codec::codecs::swab::TransformFactory::new()),
        );
        map.insert(
            "quotedprintable",
            Box::new(codec::codecs::quotedprintable::TransformFactory::new()),
        );
        map.insert(
            "uri",
            Box::new(codec::codecs::uri::URITransformFactory::new()),
        );
        map.insert(
            "url64",
            Box::new(codec::codecs::base64::URL64TransformFactory::new()),
        );
        map.insert(
            "uuencode",
            Box::new(codec::codecs::uuencode::UuencodeTransformFactory::new()),
        );
        map.insert(
            "vis",
            Box::new(codec::codecs::vis::VisTransformFactory::new()),
        );
        map.insert(
            "wrap",
            Box::new(codec::codecs::wrap::TransformFactory::new()),
        );
        map.insert(
            "xml",
            Box::new(codec::codecs::xml::XMLTransformFactory::new()),
        );
        map.insert(
            "zlib",
            Box::new(codec::codecs::compress::ZlibTransformFactory::new()),
        );

        CodecRegistry { map }
    }

    pub fn insert(&mut self, k: &'static str, f: Box<CodecTransform>) {
        self.map.insert(k, f);
    }

    pub fn iter<'a>(&'a self) -> Iter<'a> {
        self.map.iter()
    }

    pub fn create<'a>(
        &self,
        name: &'a str,
        r: Box<io::BufRead>,
        s: CodecSettings,
    ) -> Result<Box<io::BufRead>, Error> {
        match self.map.get(name) {
            Some(t) => t.factory(r, s),
            None => Err(Error::UnknownCodec(String::from(name))),
        }
    }
}

#[cfg(test)]
mod tests {
    use codec::registry::CodecRegistry;
    use codec::CodecSettings;
    use codec::CodecTransform;
    use codec::Direction;
    use codec::Error;
    use std::collections::BTreeMap;
    use std::io;
    use std::io::Read;

    struct TestCodecFactory {}

    impl CodecTransform for TestCodecFactory {
        fn factory(
            &self,
            _r: Box<io::BufRead>,
            _s: CodecSettings,
        ) -> Result<Box<io::BufRead>, Error> {
            return Ok(Box::new(io::Cursor::new(vec![0x61, 0x62, 0x63])));
        }

        fn options(&self) -> BTreeMap<String, String> {
            BTreeMap::new()
        }

        fn can_reverse(&self) -> bool {
            true
        }

        fn name(&self) -> &'static str {
            "random"
        }
    }

    fn codec_settings() -> CodecSettings {
        CodecSettings {
            args: BTreeMap::new(),
            bufsize: 512,
            dir: Direction::Forward,
            strict: true,
        }
    }

    #[test]
    fn can_fetch_insertable() {
        let mut cr = CodecRegistry::new();
        let r = Box::new(io::Cursor::new(Vec::new()));

        match cr.create("random", r, codec_settings()) {
            Ok(_) => panic!("unexpected success"),
            Err(Error::UnknownCodec(s)) => assert_eq!(s, "random"),
            Err(e) => panic!("unexpected error: {:?}", e),
        }

        cr.insert("random", Box::new(TestCodecFactory {}));

        let r = Box::new(io::Cursor::new(Vec::new()));
        match cr.create("random", r, codec_settings()) {
            Ok(c) => {
                let c: Result<Vec<u8>, _> = c.bytes().collect();
                let v = c.unwrap();
                assert_eq!(v, vec![0x61, 0x62, 0x63]);
            }
            Err(_) => {
                panic!("failed to insert random");
            }
        }
    }

    #[test]
    fn iterates_in_sorted_order() {
        let cr = CodecRegistry::new();
        let keys: Vec<_> = cr.iter().map(|(key, _)| key).collect();
        let mut keys_sorted = keys.clone();
        keys_sorted.sort();

        assert_eq!(keys, keys_sorted);
    }
}