diff options
| author | Mason Reed <mason@vector35.com> | 2025-05-07 23:22:48 -0400 |
|---|---|---|
| committer | Mason Reed <35282038+emesare@users.noreply.github.com> | 2025-05-12 17:45:24 -0400 |
| commit | 3992860ca7d636661d7b2671d5fe7cf028987be1 (patch) | |
| tree | c5613a3ce749a6866f40a734571752b248258e7b /rust/src | |
| parent | d5c4ea4018432750999e5ef11f83736bc8612a03 (diff) | |
[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
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/metadata.rs | 173 |
1 files changed, 88 insertions, 85 deletions
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<bool, ()> { + pub fn get_boolean(&self) -> Option<bool> { 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<u64, ()> { + pub fn get_unsigned_integer(&self) -> Option<u64> { 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<i64, ()> { + pub fn get_signed_integer(&self) -> Option<i64> { match self.get_type() { MetadataType::SignedIntegerDataType => { - Ok(unsafe { BNMetadataGetSignedInteger(self.handle) }) + Some(unsafe { BNMetadataGetSignedInteger(self.handle) }) } - _ => Err(()), + _ => None, } } - pub fn get_double(&self) -> Result<f64, ()> { + pub fn get_double(&self) -> Option<f64> { 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<BnString, ()> { + pub fn get_string(&self) -> Option<BnString> { 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<Vec<bool>, ()> { + pub fn get_boolean_list(&self) -> Option<Vec<bool>> { 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<Vec<u64>, ()> { + pub fn get_unsigned_integer_list(&self) -> Option<Vec<u64>> { 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<Vec<i64>, ()> { + pub fn get_signed_integer_list(&self) -> Option<Vec<i64>> { 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<Vec<f64>, ()> { + pub fn get_double_list(&self) -> Option<Vec<f64>> { 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<Vec<BnString>, ()> { + pub fn get_string_list(&self) -> Option<Vec<BnString>> { 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::<Vec<_>>(); unsafe { BNFreeMetadataStringList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_json_string(&self) -> Result<BnString, ()> { + pub fn get_json_string(&self) -> Option<BnString> { 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<Vec<u8>, ()> { + pub fn get_raw(&self) -> Option<Vec<u8>> { 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<Array<Metadata>, ()> { + pub fn get_array(&self) -> Option<Array<Metadata>> { 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<HashMap<String, Ref<Metadata>>, ()> { + pub fn get_value_store(&self) -> Option<HashMap<String, Ref<Metadata>>> { 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::<Metadata>::new(Self { - handle: BNNewMetadataReference(values[i]), - }) - }; + let key = raw_to_string(keys[i]).unwrap(); + let value = unsafe { Ref::<Metadata>::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<Metadata>> for Ref<Metadata> { } } -impl<S: IntoCStr> From<HashMap<S, Ref<Metadata>>> for Ref<Metadata> { - fn from(value: HashMap<S, Ref<Metadata>>) -> Self { - let data: Vec<(S::Result, Ref<Metadata>)> = - value.into_iter().map(|(k, v)| (k.to_cstr(), v)).collect(); +impl<S: IntoCStr, T: Into<Ref<Metadata>>> From<HashMap<S, T>> for Ref<Metadata> { + fn from(value: HashMap<S, T>) -> Self { + let data: Vec<(S::Result, Ref<Metadata>)> = 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<Self, Self::Error> { - 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<Self, Self::Error> { - 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<Self, Self::Error> { - 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<Self, Self::Error> { - 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<Self, Self::Error> { - 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<Self, Self::Error> { - 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<bool> { type Error = (); fn try_from(value: &Metadata) -> Result<Self, Self::Error> { - value.get_boolean_list() + value.get_boolean_list().ok_or(()) } } @@ -605,7 +605,7 @@ impl TryFrom<&Metadata> for Vec<u64> { type Error = (); fn try_from(value: &Metadata) -> Result<Self, Self::Error> { - value.get_unsigned_integer_list() + value.get_unsigned_integer_list().ok_or(()) } } @@ -613,7 +613,7 @@ impl TryFrom<&Metadata> for Vec<i64> { type Error = (); fn try_from(value: &Metadata) -> Result<Self, Self::Error> { - value.get_signed_integer_list() + value.get_signed_integer_list().ok_or(()) } } @@ -621,7 +621,7 @@ impl TryFrom<&Metadata> for Vec<f64> { type Error = (); fn try_from(value: &Metadata) -> Result<Self, Self::Error> { - value.get_double_list() + value.get_double_list().ok_or(()) } } @@ -629,7 +629,7 @@ impl TryFrom<&Metadata> for Vec<BnString> { type Error = (); fn try_from(value: &Metadata) -> Result<Self, Self::Error> { - value.get_string_list() + value.get_string_list().ok_or(()) } } @@ -637,11 +637,14 @@ impl TryFrom<&Metadata> for Vec<String> { type Error = (); fn try_from(value: &Metadata) -> Result<Self, Self::Error> { - 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<u8> { type Error = (); fn try_from(value: &Metadata) -> Result<Self, Self::Error> { - value.get_raw() + value.get_raw().ok_or(()) } } @@ -657,7 +660,7 @@ impl TryFrom<&Metadata> for Array<Metadata> { type Error = (); fn try_from(value: &Metadata) -> Result<Self, Self::Error> { - value.get_array() + value.get_array().ok_or(()) } } @@ -665,20 +668,20 @@ impl TryFrom<&Metadata> for HashMap<String, Ref<Metadata>> { type Error = (); fn try_from(value: &Metadata) -> Result<Self, Self::Error> { - value.get_value_store() + value.get_value_store().ok_or(()) } } impl IntoJson for &Metadata { type Output = BnString; fn get_json_string(self) -> Result<BnString, ()> { - Metadata::get_json_string(self) + Metadata::get_json_string(self).ok_or(()) } } impl IntoJson for Ref<Metadata> { type Output = BnString; fn get_json_string(self) -> Result<BnString, ()> { - Metadata::get_json_string(&self) + Metadata::get_json_string(&self).ok_or(()) } } |
