1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! This library is a Rust implementation of the https://github.com/multiformats/multicodec project.
extern crate integer_encoding;

use std::io::Write;
use integer_encoding::VarInt;

mod codec_map;

/// Returns the data prefixed with the codec's code in a u8 buffer.
///
/// # Arguments
///
/// * `codec_code` - The codec code, eg. 'base1'
/// * `data` - the data to be prefixed
///
/// # Example
///
/// ```
/// extern crate rust_multicodec;
/// extern crate hex_slice;
///
/// use hex_slice::AsHex;
/// use std::process;
///
/// fn main(){
///     let data="Live long and prosper";
///
///     println!("{:X}",rust_multicodec::add_prefix("base1",data.as_bytes()).unwrap().as_hex());
///     // it will print [1 4C 69 76 65 20 6C 6F 6E 67 20 61 6E 64 20 70 72 6F 73 70 65 72]
/// }
/// ```
///
pub fn add_prefix(codec_code: &str, data: &[u8]) -> Result<Vec<u8>, &'static str> {
    match codec_map::get_decimal_by_code(codec_code) { // getting hex code of the codec
        Some(decimal) => {
            // encoding codec's (as decimal) into a varint
            let mut target:Vec<u8>=decimal.encode_var_vec();

            match target.write(data) {
                Err(_) => return Err("Could not write data into the result buffer"),
                _=> ()
            }

            Ok(target)
        }
        None => Err("No implementation for the given codec")
    }
}

/// Returns the codec's code the data was prefixed with.
///
/// # Arguments
///
/// * `data` - the data with prefix
///
/// # Example
///
/// ```
/// extern crate rust_multicodec;
/// extern crate hex_slice;
///
/// use hex_slice::AsHex;
/// use std::process;
///
/// fn main(){
///     let data="Live long and prosper";
///
///     let prefixed=rust_multicodec::add_prefix("base1",data.as_bytes()).unwrap();
///     println!("{}",rust_multicodec::get_codec(prefixed.as_slice()).unwrap().unwrap());
///     // it will print "base1"
/// }
/// ```
///
pub fn get_codec(data: &[u8]) -> Result<Option<&'static str>, &'static str> {
    let decoded:(u64,usize)=u64::decode_var_vec(&Vec::from(data));
    Ok(codec_map::get_code_by_decimal(decoded.0))
}

/// Removes the codec prefix and returns the raw data.
///
/// # Arguments
///
/// * `data` - the data with prefix
///
/// # Example
///
/// ```
/// extern crate rust_multicodec;
/// extern crate hex_slice;
///
/// use hex_slice::AsHex;
/// use std::process;
///
/// fn main(){
///     let data="Live long and prosper";
///
///     let prefixed=rust_multicodec::add_prefix("base1",data.as_bytes()).unwrap();
///     let raw_data=rust_multicodec::remove_prefix(prefixed.as_slice()).unwrap();
///     println!("Original data was {:?}", String::from_utf8(raw_data).unwrap())
///     // it will print return "Original data was Live long and prosper"
/// }
/// ```
///
pub fn remove_prefix(data:&[u8]) -> Result<Vec<u8>, &'static str>{
    let decoded:(u64,usize)=u64::decode_var_vec(&Vec::from(data));
    Ok(data[decoded.1..].to_vec())
}

#[cfg(test)]
mod tests {
    use super::*;

    const DATA:&str="Live long and prosper";

    #[test]
    fn works(){
        let result=add_prefix("utp",DATA.as_bytes());
        assert_eq!(result.is_ok(),true);

        let prefixed=result.unwrap();
        assert_eq!(get_codec(prefixed.as_slice()).unwrap().unwrap(),"utp");
        assert_eq!(remove_prefix(prefixed.as_slice()).unwrap(),DATA.as_bytes());
    }

    #[test]
    #[should_panic]
    fn fails_with_invalid_codec(){
        add_prefix("invalid_codec",DATA.as_bytes()).unwrap();
    }
}