From 3992860ca7d636661d7b2671d5fe7cf028987be1 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 7 May 2025 23:22:48 -0400 Subject: [Rust] Metadata API improvements - Don't use Result for some or none values - Fix freeing of key value store objects - Improve ergonomics a little bit - Add unit tests --- rust/src/metadata.rs | 173 ++++++++++++++++++++++++++------------------------- 1 file changed, 88 insertions(+), 85 deletions(-) (limited to 'rust/src') diff --git a/rust/src/metadata.rs b/rust/src/metadata.rs index 6cf1cbce..e541577d 100644 --- a/rust/src/metadata.rs +++ b/rust/src/metadata.rs @@ -1,5 +1,5 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnString, IntoCStr, IntoJson}; +use crate::string::{raw_to_string, BnString, IntoCStr, IntoJson}; use binaryninjacore_sys::*; use std::collections::HashMap; use std::os::raw::c_char; @@ -30,129 +30,129 @@ impl Metadata { unsafe { BNMetadataGetType(self.handle) } } - pub fn get_boolean(&self) -> Result { + pub fn get_boolean(&self) -> Option { match self.get_type() { - MetadataType::BooleanDataType => Ok(unsafe { BNMetadataGetBoolean(self.handle) }), - _ => Err(()), + MetadataType::BooleanDataType => Some(unsafe { BNMetadataGetBoolean(self.handle) }), + _ => None, } } - pub fn get_unsigned_integer(&self) -> Result { + pub fn get_unsigned_integer(&self) -> Option { match self.get_type() { MetadataType::UnsignedIntegerDataType => { - Ok(unsafe { BNMetadataGetUnsignedInteger(self.handle) }) + Some(unsafe { BNMetadataGetUnsignedInteger(self.handle) }) } - _ => Err(()), + _ => None, } } - pub fn get_signed_integer(&self) -> Result { + pub fn get_signed_integer(&self) -> Option { match self.get_type() { MetadataType::SignedIntegerDataType => { - Ok(unsafe { BNMetadataGetSignedInteger(self.handle) }) + Some(unsafe { BNMetadataGetSignedInteger(self.handle) }) } - _ => Err(()), + _ => None, } } - pub fn get_double(&self) -> Result { + pub fn get_double(&self) -> Option { match self.get_type() { - MetadataType::DoubleDataType => Ok(unsafe { BNMetadataGetDouble(self.handle) }), - _ => Err(()), + MetadataType::DoubleDataType => Some(unsafe { BNMetadataGetDouble(self.handle) }), + _ => None, } } - pub fn get_string(&self) -> Result { + pub fn get_string(&self) -> Option { match self.get_type() { MetadataType::StringDataType => { let ptr: *mut c_char = unsafe { BNMetadataGetString(self.handle) }; if ptr.is_null() { - return Err(()); + return None; } - Ok(unsafe { BnString::from_raw(ptr) }) + Some(unsafe { BnString::from_raw(ptr) }) } - _ => Err(()), + _ => None, } } - pub fn get_boolean_list(&self) -> Result, ()> { + pub fn get_boolean_list(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut bool = unsafe { BNMetadataGetBooleanList(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = Vec::from(list); unsafe { BNFreeMetadataBooleanList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_unsigned_integer_list(&self) -> Result, ()> { + pub fn get_unsigned_integer_list(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut u64 = unsafe { BNMetadataGetUnsignedIntegerList(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = Vec::from(list); unsafe { BNFreeMetadataUnsignedIntegerList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_signed_integer_list(&self) -> Result, ()> { + pub fn get_signed_integer_list(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut i64 = unsafe { BNMetadataGetSignedIntegerList(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = Vec::from(list); unsafe { BNFreeMetadataSignedIntegerList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_double_list(&self) -> Result, ()> { + pub fn get_double_list(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut f64 = unsafe { BNMetadataGetDoubleList(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = Vec::from(list); unsafe { BNFreeMetadataDoubleList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_string_list(&self) -> Result, ()> { + pub fn get_string_list(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut *mut c_char = unsafe { BNMetadataGetStringList(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = list @@ -160,66 +160,66 @@ impl Metadata { .map(|ptr| unsafe { BnString::from_raw(*ptr) }) .collect::>(); unsafe { BNFreeMetadataStringList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_json_string(&self) -> Result { + pub fn get_json_string(&self) -> Option { match self.get_type() { MetadataType::StringDataType => { let ptr: *mut c_char = unsafe { BNMetadataGetJsonString(self.handle) }; if ptr.is_null() { - return Err(()); + return None; } - Ok(unsafe { BnString::from_raw(ptr) }) + Some(unsafe { BnString::from_raw(ptr) }) } - _ => Err(()), + _ => None, } } - pub fn get_raw(&self) -> Result, ()> { + pub fn get_raw(&self) -> Option> { match self.get_type() { MetadataType::RawDataType => { let mut size: usize = 0; let ptr: *mut u8 = unsafe { BNMetadataGetRaw(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = Vec::from(list); unsafe { BNFreeMetadataRaw(ptr) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_array(&self) -> Result, ()> { + pub fn get_array(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut *mut BNMetadata = unsafe { BNMetadataGetArray(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } - Ok(unsafe { Array::new(ptr, size, ()) }) + Some(unsafe { Array::new(ptr, size, ()) }) } - _ => Err(()), + _ => None, } } - pub fn get_value_store(&self) -> Result>, ()> { + pub fn get_value_store(&self) -> Option>> { match self.get_type() { MetadataType::KeyValueDataType => { let ptr: *mut BNMetadataValueStore = unsafe { BNMetadataGetValueStore(self.handle) }; if ptr.is_null() { - return Err(()); + return None; } let size = unsafe { (*ptr).size }; @@ -230,21 +230,16 @@ impl Metadata { let mut map = HashMap::new(); for i in 0..size { - let key = unsafe { BnString::into_string(keys[i]) }; - - let value = unsafe { - Ref::::new(Self { - handle: BNNewMetadataReference(values[i]), - }) - }; + let key = raw_to_string(keys[i]).unwrap(); + let value = unsafe { Ref::::new(Self { handle: values[i] }) }; map.insert(key, value); } unsafe { BNFreeMetadataValueStore(ptr) }; - Ok(map) + Some(map) } - _ => Err(()), + _ => None, } } @@ -424,10 +419,12 @@ impl From<&Array> for Ref { } } -impl From>> for Ref { - fn from(value: HashMap>) -> Self { - let data: Vec<(S::Result, Ref)> = - value.into_iter().map(|(k, v)| (k.to_cstr(), v)).collect(); +impl>> From> for Ref { + fn from(value: HashMap) -> Self { + let data: Vec<(S::Result, Ref)> = value + .into_iter() + .map(|(k, v)| (k.to_cstr(), v.into())) + .collect(); let mut keys: Vec<*const c_char> = data.iter().map(|(k, _)| k.as_ptr()).collect(); let mut values: Vec<*mut BNMetadata> = data.iter().map(|(_, v)| v.handle).collect(); @@ -549,7 +546,7 @@ impl TryFrom<&Metadata> for bool { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_boolean() + value.get_boolean().ok_or(()) } } @@ -557,7 +554,7 @@ impl TryFrom<&Metadata> for u64 { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_unsigned_integer() + value.get_unsigned_integer().ok_or(()) } } @@ -565,7 +562,7 @@ impl TryFrom<&Metadata> for i64 { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_signed_integer() + value.get_signed_integer().ok_or(()) } } @@ -573,7 +570,7 @@ impl TryFrom<&Metadata> for f64 { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_double() + value.get_double().ok_or(()) } } @@ -581,7 +578,7 @@ impl TryFrom<&Metadata> for BnString { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_string() + value.get_string().ok_or(()) } } @@ -589,7 +586,10 @@ impl TryFrom<&Metadata> for String { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_string().map(|s| s.to_string_lossy().to_string()) + value + .get_string() + .map(|s| s.to_string_lossy().to_string()) + .ok_or(()) } } @@ -597,7 +597,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_boolean_list() + value.get_boolean_list().ok_or(()) } } @@ -605,7 +605,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_unsigned_integer_list() + value.get_unsigned_integer_list().ok_or(()) } } @@ -613,7 +613,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_signed_integer_list() + value.get_signed_integer_list().ok_or(()) } } @@ -621,7 +621,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_double_list() + value.get_double_list().ok_or(()) } } @@ -629,7 +629,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_string_list() + value.get_string_list().ok_or(()) } } @@ -637,11 +637,14 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_string_list().map(|v| { - v.into_iter() - .map(|s| s.to_string_lossy().to_string()) - .collect() - }) + value + .get_string_list() + .map(|v| { + v.into_iter() + .map(|s| s.to_string_lossy().to_string()) + .collect() + }) + .ok_or(()) } } @@ -649,7 +652,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_raw() + value.get_raw().ok_or(()) } } @@ -657,7 +660,7 @@ impl TryFrom<&Metadata> for Array { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_array() + value.get_array().ok_or(()) } } @@ -665,20 +668,20 @@ impl TryFrom<&Metadata> for HashMap> { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_value_store() + value.get_value_store().ok_or(()) } } impl IntoJson for &Metadata { type Output = BnString; fn get_json_string(self) -> Result { - Metadata::get_json_string(self) + Metadata::get_json_string(self).ok_or(()) } } impl IntoJson for Ref { type Output = BnString; fn get_json_string(self) -> Result { - Metadata::get_json_string(&self) + Metadata::get_json_string(&self).ok_or(()) } } -- cgit v1.3.1