From f640444986d2e0507931c2f103610d4816f8c8b9 Mon Sep 17 00:00:00 2001 From: Felix Krull Date: Mon, 2 Sep 2019 17:11:35 +0200 Subject: [PATCH] checksum: implement more traits and functions --- rust-bindings/rust/src/checksum.rs | 107 ++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 18 deletions(-) diff --git a/rust-bindings/rust/src/checksum.rs b/rust-bindings/rust/src/checksum.rs index 2dc25031..eee7e5c0 100644 --- a/rust-bindings/rust/src/checksum.rs +++ b/rust-bindings/rust/src/checksum.rs @@ -1,10 +1,10 @@ -use glib::translate::{from_glib_full, FromGlibPtrFull, ToGlibPtr}; +use glib::translate::{from_glib_full, FromGlibPtrFull, Stash, ToGlibPtr}; use glib::GString; -use glib_sys::{g_free, gpointer}; +use glib_sys::{g_free, g_malloc, g_malloc0, gpointer}; use std::fmt; +use std::ptr::copy_nonoverlapping; const BYTES_BUF_SIZE: usize = ostree_sys::OSTREE_SHA256_DIGEST_LEN as usize; -const HEX_BUF_SIZE: usize = (ostree_sys::OSTREE_SHA256_STRING_LEN + 1) as usize; const B64_BUF_SIZE: usize = 44; /// A binary SHA256 checksum. @@ -31,7 +31,7 @@ impl Checksum { /// Unfortunately, the underlying libostree function has no way to report parsing errors. If the /// string is not a valid SHA256 string, the program will abort! // TODO: implement by hand to avoid stupid assertions? - pub fn from_string(checksum: &str) -> Checksum { + pub fn from_hex(checksum: &str) -> Checksum { unsafe { from_glib_full(ostree_sys::ostree_checksum_to_bytes( checksum.to_glib_none().0, @@ -39,8 +39,25 @@ impl Checksum { } } - /// Return checksum as a hex digest string. - fn to_gstring(&self) -> GString { + /// Create a `Checksum` from a base64-encoded String. + /// + /// Data that is too long or too short will be silently accepted. For example, if you pass in + /// the empty string, the resulting checksum value will be all 0's. + /// // TODO: implement by hand for better error reporting? + pub fn from_base64(b64_checksum: &str) -> Checksum { + let b64_checksum: Stash<*mut libc::c_char, _> = b64_checksum.to_glib_none(); + unsafe { + let buf = g_malloc0(BYTES_BUF_SIZE) as *mut [u8; BYTES_BUF_SIZE]; + ostree_sys::ostree_checksum_b64_inplace_to_bytes( + b64_checksum.0 as *const [i8; 32], + buf as *mut u8, + ); + from_glib_full(buf) + } + } + + /// Convert checksum to hex-encoded string. + pub fn to_hex(&self) -> GString { unsafe { from_glib_full(ostree_sys::ostree_checksum_from_bytes(self.bytes)) } } @@ -69,6 +86,37 @@ impl Drop for Checksum { } } +impl Clone for Checksum { + fn clone(&self) -> Self { + unsafe { + let cloned = g_malloc(BYTES_BUF_SIZE) as *mut [u8; BYTES_BUF_SIZE]; + // copy one array of 32 elements + copy_nonoverlapping::<[u8; BYTES_BUF_SIZE]>(self.bytes, cloned, 1); + Checksum::new(cloned) + } + } +} + +impl PartialEq for Checksum { + fn eq(&self, other: &Self) -> bool { + unsafe { + let ret = ostree_sys::ostree_cmp_checksum_bytes( + self.bytes as *const u8, + other.bytes as *const u8, + ); + ret == 0 + } + } +} + +impl Eq for Checksum {} + +impl fmt::Display for Checksum { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_hex()) + } +} + impl FromGlibPtrFull<*mut [u8; BYTES_BUF_SIZE]> for Checksum { unsafe fn from_glib_full(ptr: *mut [u8; BYTES_BUF_SIZE]) -> Self { Checksum::new(ptr) @@ -87,12 +135,6 @@ impl FromGlibPtrFull<*mut u8> for Checksum { } } -impl fmt::Display for Checksum { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_gstring()) - } -} - #[cfg(test)] mod tests { use super::*; @@ -100,6 +142,7 @@ mod tests { const CHECKSUM_STRING: &str = "bf875306783efdc5bcab37ea10b6ca4e9b6aea8b94580d0ca94af120565c0e8a"; + const CHECKSUM_BASE64: &str = "v4dTBng+_cW8qzfqELbKTptq6ouUWA0MqUrxIFZcDoo"; #[test] fn should_create_checksum_from_bytes() { @@ -110,16 +153,44 @@ mod tests { #[test] fn should_parse_checksum_string_to_bytes() { - let csum = Checksum::from_string(CHECKSUM_STRING); + let csum = Checksum::from_hex(CHECKSUM_STRING); assert_eq!(csum.to_string(), CHECKSUM_STRING); } #[test] fn should_convert_checksum_to_base64() { - let csum = Checksum::from_string(CHECKSUM_STRING); - assert_eq!( - csum.to_base64(), - "v4dTBng+_cW8qzfqELbKTptq6ouUWA0MqUrxIFZcDoo" - ); + let csum = Checksum::from_hex(CHECKSUM_STRING); + assert_eq!(csum.to_base64(), CHECKSUM_BASE64); + } + + #[test] + fn should_convert_base64_string_to_checksum() { + let csum = Checksum::from_base64(CHECKSUM_BASE64); + assert_eq!(csum.to_base64(), CHECKSUM_BASE64); + assert_eq!(csum.to_string(), CHECKSUM_STRING); + } + + #[test] + fn should_be_zeros_for_empty_base64_string() { + let csum = Checksum::from_base64(""); + assert_eq!(csum.to_string(), "00".repeat(BYTES_BUF_SIZE)); + } + + #[test] + fn should_compare_checksums() { + let csum = Checksum::from_hex(CHECKSUM_STRING); + assert_eq!(csum, csum); + let csum2 = Checksum::from_hex(CHECKSUM_STRING); + assert_eq!(csum2, csum); + } + + #[test] + fn should_clone_value() { + let csum = Checksum::from_hex(CHECKSUM_STRING); + let csum2 = csum.clone(); + assert_eq!(csum2, csum); + let csum3 = csum2.clone(); + assert_eq!(csum3, csum); + assert_eq!(csum3, csum2); } }