diff --git a/src/decode_impl.rs b/src/decode_impl.rs index 0963a0c..abb22b9 100644 --- a/src/decode_impl.rs +++ b/src/decode_impl.rs @@ -259,11 +259,40 @@ pub fn decode(input: &str, output: &mut Vec, bits: u64) -> Result<(), ZBase3 Ok(()) } +/// Decode a slice of characters to a [`Vec`] of octets (bytes). +/// +/// It decodes to the longest full octet string, and fails if any +/// left-over bits from the encoded form are non-zero. +/// +/// This method is not available in `no_std` mode. +#[cfg(feature = "std")] +pub fn decode_full_bytes(input: &str) -> Result, ZBase32Error> { + let bits:u64 = ((input.len() as u64 *5)/8)*8; + let mut output:Vec = Vec::new(); + match decode(input, &mut output, bits) { + Ok(_) => Ok(output), + Err(e) => Err(e), + } +} + #[cfg(test)] mod tests { + #[cfg(feature = "std")] use super::decode; + #[cfg(feature = "std")] + use super::decode_full_bytes; use crate::test_data::{TestCase, RANDOM_TEST_DATA, STANDARD_TEST_DATA}; + #[cfg(feature = "std")] + fn run_full_bytes_tests(test_cases: &[TestCase]) { + for test in test_cases { + if (test.bits % 8) == 0 { + assert_eq!(test.unencoded, decode_full_bytes(test.encoded).unwrap()); + } + } + } + + #[cfg(feature = "std")] fn run_tests(test_cases: &[TestCase]) { let mut buffer = Vec::new(); for test in test_cases { @@ -274,12 +303,26 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn test_decode_standard() { run_tests(STANDARD_TEST_DATA); } #[test] + #[cfg(feature = "std")] fn test_decode_random() { run_tests(RANDOM_TEST_DATA); } + + #[test] + #[cfg(feature = "std")] + fn test_decode_full_bytes_standard() { + run_full_bytes_tests(STANDARD_TEST_DATA); + } + + #[test] + #[cfg(feature = "std")] + fn test_decode_full_bytes_random() { + run_full_bytes_tests(RANDOM_TEST_DATA); + } } diff --git a/src/encode_impl.rs b/src/encode_impl.rs index 49aab2d..1139ade 100644 --- a/src/encode_impl.rs +++ b/src/encode_impl.rs @@ -248,11 +248,38 @@ pub fn encode(input: &[u8], output: &mut String, bits: u64) -> Result<(), ZBase3 Ok(()) } +/// Encode a whole number of octets (bytes) to a [`String`]. +/// +/// If you need a number of bits that is not a multiple of 8 (that is, +/// not a whole number of bytes), or you need to append to an existing +/// string, use [`encode`] instead. +/// +/// This method is not available in `no_std` mode. +#[cfg(feature = "std")] +pub fn encode_full_bytes(input: &[u8]) -> String { + let mut output = String::from(""); + encode(input, &mut output, input.len() as u64 * 8).unwrap(); + output +} + #[cfg(test)] mod tests { + #[cfg(feature = "std")] use super::encode; + #[cfg(feature = "std")] + use super::encode_full_bytes; use crate::test_data::{TestCase, RANDOM_TEST_DATA, STANDARD_TEST_DATA}; + #[cfg(feature = "std")] + fn run_full_bytes_tests(test_cases: &[TestCase]) { + for test in test_cases { + if (test.bits % 8) == 0 { + assert_eq!(String::from(test.encoded), encode_full_bytes(test.unencoded)); + } + } + } + + #[cfg(feature = "std")] fn run_tests(test_cases: &[TestCase]) { let mut buffer = String::new(); for test in test_cases { @@ -263,12 +290,26 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn test_encode_standard() { run_tests(STANDARD_TEST_DATA); } #[test] + #[cfg(feature = "std")] fn test_encode_random() { run_tests(RANDOM_TEST_DATA); } + + #[test] + #[cfg(feature = "std")] + fn test_encode_full_bytes_standard() { + run_full_bytes_tests(STANDARD_TEST_DATA); + } + + #[test] + #[cfg(feature = "std")] + fn test_encode_full_bytes_random() { + run_full_bytes_tests(RANDOM_TEST_DATA); + } } diff --git a/src/lib.rs b/src/lib.rs index cd5b499..d3d4923 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,17 +50,30 @@ //! //! ## High-level API //! -//! The high-level API consists of the functions [`encode`] and -//! its reverse, [`decode`]. +//! The high-level API consists of two encoding functions +//! [`encode_full_bytes`] and [`encode`]; and two decoding functions +//! [`decode_full_bytes`] and [`decode`]. +//! +//! [`encode_full_bytes`] and [`decode_full_bytes`] are simple to use +//! when you know that the unencoded bytestring is a whole number of +//! bytes. [`encode`] and [`decode`] can also handle numbers of +//! unencoded bits that are not divisible by 8, and can also append +//! their results to existing variables. //! //! Example: //! //! ``` -//! use libzbase32::{ZBase32Error, encode, decode}; +//! use libzbase32::{ZBase32Error, encode, encode_full_bytes, decode}; //! //! # fn main() { //! const DATA: &'static [u8] = &[0, 44, 55, 128]; //! +//! let full_bytes_encoded = encode_full_bytes(DATA); +//! assert_eq!(&full_bytes_encoded, "yysdxyy"); +//! +//! let full_bytes_decoded = decode_full_bytes(full_bytes_encoded); +//! assert_eq!(&full_bytes_decoded, DATA); +//! //! let mut encoded = String::new(); //! encode(DATA, &mut encoded, 25).expect("Encoding failed!"); //!