summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rust/src/lib.rs1
-rw-r--r--rust/src/qualified_name.rs221
-rw-r--r--rust/src/types.rs223
3 files changed, 227 insertions, 218 deletions
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 2d9cab27..ba654f09 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -68,6 +68,7 @@ pub mod metadata;
pub mod platform;
pub mod progress;
pub mod project;
+pub mod qualified_name;
pub mod rc;
pub mod references;
pub mod relocation;
diff --git a/rust/src/qualified_name.rs b/rust/src/qualified_name.rs
new file mode 100644
index 00000000..c1d943f8
--- /dev/null
+++ b/rust/src/qualified_name.rs
@@ -0,0 +1,221 @@
+use crate::rc::{CoreArrayProvider, CoreArrayProviderInner};
+use crate::string::{raw_to_string, strings_to_string_list, BnString};
+use binaryninjacore_sys::*;
+use std::borrow::Cow;
+use std::fmt::{Display, Formatter};
+use std::ops::{Index, IndexMut};
+
+// TODO: Document usage, specifically how to make a qualified name and why it exists.
+#[derive(Default, Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
+pub struct QualifiedName {
+ // TODO: Make this Option<String> where default is "::".
+ pub separator: String,
+ pub items: Vec<String>,
+}
+
+impl QualifiedName {
+ pub(crate) fn from_raw(value: &BNQualifiedName) -> Self {
+ // TODO: This could be improved...
+ let raw_names = unsafe { std::slice::from_raw_parts(value.name, value.nameCount) };
+ let items = raw_names
+ .iter()
+ .filter_map(|&raw_name| raw_to_string(raw_name as *const _))
+ .collect();
+ let separator = raw_to_string(value.join).unwrap();
+ Self { items, separator }
+ }
+
+ pub(crate) fn from_owned_raw(value: BNQualifiedName) -> Self {
+ let result = Self::from_raw(&value);
+ Self::free_raw(value);
+ result
+ }
+
+ pub fn into_raw(value: Self) -> BNQualifiedName {
+ let bn_join = BnString::new(&value.separator);
+ BNQualifiedName {
+ // NOTE: Leaking string list must be freed by core or us!
+ name: strings_to_string_list(&value.items),
+ // NOTE: Leaking string must be freed by core or us!
+ join: BnString::into_raw(bn_join),
+ nameCount: value.items.len(),
+ }
+ }
+
+ pub(crate) fn free_raw(value: BNQualifiedName) {
+ unsafe { BnString::free_raw(value.join) };
+ unsafe { BNFreeStringList(value.name, value.nameCount) };
+ }
+
+ pub fn new(items: Vec<String>) -> Self {
+ Self::new_with_separator(items, "::".to_string())
+ }
+
+ pub fn new_with_separator(items: Vec<String>, separator: String) -> Self {
+ Self { items, separator }
+ }
+
+ pub fn with_item(&self, item: impl Into<String>) -> Self {
+ let mut items = self.items.clone();
+ items.push(item.into());
+ Self::new_with_separator(items, self.separator.clone())
+ }
+
+ pub fn push(&mut self, item: String) {
+ self.items.push(item);
+ }
+
+ pub fn pop(&mut self) -> Option<String> {
+ self.items.pop()
+ }
+
+ pub fn insert(&mut self, index: usize, item: String) {
+ if index <= self.items.len() {
+ self.items.insert(index, item);
+ }
+ }
+
+ pub fn split_last(&self) -> Option<(String, QualifiedName)> {
+ self.items.split_last().map(|(a, b)| {
+ (
+ a.to_owned(),
+ QualifiedName::new_with_separator(b.to_vec(), self.separator.clone()),
+ )
+ })
+ }
+
+ /// Replaces all occurrences of a substring with another string in all items of the `QualifiedName`
+ /// and returns an owned version of the modified `QualifiedName`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use binaryninja::types::QualifiedName;
+ ///
+ /// let qualified_name =
+ /// QualifiedName::new(vec!["my::namespace".to_string(), "mytype".to_string()]);
+ /// let replaced = qualified_name.replace("my", "your");
+ /// assert_eq!(
+ /// replaced.items,
+ /// vec!["your::namespace".to_string(), "yourtype".to_string()]
+ /// );
+ /// ```
+ pub fn replace(&self, from: &str, to: &str) -> Self {
+ Self {
+ items: self
+ .items
+ .iter()
+ .map(|item| item.replace(from, to))
+ .collect(),
+ separator: self.separator.clone(),
+ }
+ }
+
+ /// Returns the last item, or `None` if it is empty.
+ pub fn last(&self) -> Option<&String> {
+ self.items.last()
+ }
+
+ /// Returns a mutable reference to the last item, or `None` if it is empty.
+ pub fn last_mut(&mut self) -> Option<&mut String> {
+ self.items.last_mut()
+ }
+
+ pub fn len(&self) -> usize {
+ self.items.len()
+ }
+
+ /// A [`QualifiedName`] is empty if it has no items.
+ ///
+ /// If you want to know if the unqualified name is empty (i.e. no characters)
+ /// you must first convert the qualified name to unqualified via the `to_string` method.
+ pub fn is_empty(&self) -> bool {
+ self.items.is_empty()
+ }
+}
+
+impl From<String> for QualifiedName {
+ fn from(value: String) -> Self {
+ Self {
+ items: vec![value],
+ // TODO: See comment in struct def.
+ separator: String::from("::"),
+ }
+ }
+}
+
+impl From<&str> for QualifiedName {
+ fn from(value: &str) -> Self {
+ Self::from(value.to_string())
+ }
+}
+
+impl From<&String> for QualifiedName {
+ fn from(value: &String) -> Self {
+ Self::from(value.to_owned())
+ }
+}
+
+impl From<Cow<'_, str>> for QualifiedName {
+ fn from(value: Cow<'_, str>) -> Self {
+ Self::from(value.to_string())
+ }
+}
+
+impl From<Vec<String>> for QualifiedName {
+ fn from(value: Vec<String>) -> Self {
+ Self::new(value)
+ }
+}
+
+impl From<Vec<&str>> for QualifiedName {
+ fn from(value: Vec<&str>) -> Self {
+ value
+ .iter()
+ .map(ToString::to_string)
+ .collect::<Vec<_>>()
+ .into()
+ }
+}
+
+impl From<QualifiedName> for String {
+ fn from(value: QualifiedName) -> Self {
+ value.to_string()
+ }
+}
+
+impl Index<usize> for QualifiedName {
+ type Output = String;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self.items[index]
+ }
+}
+
+impl IndexMut<usize> for QualifiedName {
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ &mut self.items[index]
+ }
+}
+
+impl Display for QualifiedName {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.items.join(&self.separator))
+ }
+}
+
+impl CoreArrayProvider for QualifiedName {
+ type Raw = BNQualifiedName;
+ type Context = ();
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for QualifiedName {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeTypeNameList(raw, count);
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ QualifiedName::from_raw(raw)
+ }
+}
diff --git a/rust/src/types.rs b/rust/src/types.rs
index cf7b6f1a..417dc554 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -43,11 +43,9 @@ use crate::{
};
use crate::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE};
-use crate::string::{raw_to_string, strings_to_string_list};
+use crate::string::raw_to_string;
use crate::variable::{Variable, VariableSourceType};
-use std::borrow::Cow;
use std::num::NonZeroUsize;
-use std::ops::{Index, IndexMut};
use std::{
collections::HashSet,
fmt::{Debug, Display, Formatter},
@@ -68,6 +66,10 @@ pub use structure::{
BaseStructure, InheritedStructureMember, Structure, StructureBuilder, StructureMember,
};
+#[deprecated(note = "Use crate::qualified_name::QualifiedName instead")]
+// Re-export QualifiedName so that we do not break public consumers.
+pub use crate::qualified_name::QualifiedName;
+
pub type StructureType = BNStructureVariant;
pub type ReferenceType = BNReferenceType;
pub type TypeClass = BNTypeClass;
@@ -1238,221 +1240,6 @@ impl Debug for NamedTypeReference {
}
}
-// TODO: Document usage, specifically how to make a qualified name and why it exists.
-#[derive(Default, Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
-pub struct QualifiedName {
- // TODO: Make this Option<String> where default is "::".
- pub separator: String,
- pub items: Vec<String>,
-}
-
-impl QualifiedName {
- pub(crate) fn from_raw(value: &BNQualifiedName) -> Self {
- // TODO: This could be improved...
- let raw_names = unsafe { std::slice::from_raw_parts(value.name, value.nameCount) };
- let items = raw_names
- .iter()
- .filter_map(|&raw_name| raw_to_string(raw_name as *const _))
- .collect();
- let separator = raw_to_string(value.join).unwrap();
- Self { items, separator }
- }
-
- pub(crate) fn from_owned_raw(value: BNQualifiedName) -> Self {
- let result = Self::from_raw(&value);
- Self::free_raw(value);
- result
- }
-
- pub fn into_raw(value: Self) -> BNQualifiedName {
- let bn_join = BnString::new(&value.separator);
- BNQualifiedName {
- // NOTE: Leaking string list must be freed by core or us!
- name: strings_to_string_list(&value.items),
- // NOTE: Leaking string must be freed by core or us!
- join: BnString::into_raw(bn_join),
- nameCount: value.items.len(),
- }
- }
-
- pub(crate) fn free_raw(value: BNQualifiedName) {
- unsafe { BnString::free_raw(value.join) };
- unsafe { BNFreeStringList(value.name, value.nameCount) };
- }
-
- pub fn new(items: Vec<String>) -> Self {
- Self::new_with_separator(items, "::".to_string())
- }
-
- pub fn new_with_separator(items: Vec<String>, separator: String) -> Self {
- Self { items, separator }
- }
-
- pub fn with_item(&self, item: impl Into<String>) -> Self {
- let mut items = self.items.clone();
- items.push(item.into());
- Self::new_with_separator(items, self.separator.clone())
- }
-
- pub fn push(&mut self, item: String) {
- self.items.push(item);
- }
-
- pub fn pop(&mut self) -> Option<String> {
- self.items.pop()
- }
-
- pub fn insert(&mut self, index: usize, item: String) {
- if index <= self.items.len() {
- self.items.insert(index, item);
- }
- }
-
- pub fn split_last(&self) -> Option<(String, QualifiedName)> {
- self.items.split_last().map(|(a, b)| {
- (
- a.to_owned(),
- QualifiedName::new_with_separator(b.to_vec(), self.separator.clone()),
- )
- })
- }
-
- /// Replaces all occurrences of a substring with another string in all items of the `QualifiedName`
- /// and returns an owned version of the modified `QualifiedName`.
- ///
- /// # Example
- ///
- /// ```
- /// use binaryninja::types::QualifiedName;
- ///
- /// let qualified_name =
- /// QualifiedName::new(vec!["my::namespace".to_string(), "mytype".to_string()]);
- /// let replaced = qualified_name.replace("my", "your");
- /// assert_eq!(
- /// replaced.items,
- /// vec!["your::namespace".to_string(), "yourtype".to_string()]
- /// );
- /// ```
- pub fn replace(&self, from: &str, to: &str) -> Self {
- Self {
- items: self
- .items
- .iter()
- .map(|item| item.replace(from, to))
- .collect(),
- separator: self.separator.clone(),
- }
- }
-
- /// Returns the last item, or `None` if it is empty.
- pub fn last(&self) -> Option<&String> {
- self.items.last()
- }
-
- /// Returns a mutable reference to the last item, or `None` if it is empty.
- pub fn last_mut(&mut self) -> Option<&mut String> {
- self.items.last_mut()
- }
-
- pub fn len(&self) -> usize {
- self.items.len()
- }
-
- /// A [`QualifiedName`] is empty if it has no items.
- ///
- /// If you want to know if the unqualified name is empty (i.e. no characters)
- /// you must first convert the qualified name to unqualified via the `to_string` method.
- pub fn is_empty(&self) -> bool {
- self.items.is_empty()
- }
-}
-
-impl From<String> for QualifiedName {
- fn from(value: String) -> Self {
- Self {
- items: vec![value],
- // TODO: See comment in struct def.
- separator: String::from("::"),
- }
- }
-}
-
-impl From<&str> for QualifiedName {
- fn from(value: &str) -> Self {
- Self::from(value.to_string())
- }
-}
-
-impl From<&String> for QualifiedName {
- fn from(value: &String) -> Self {
- Self::from(value.to_owned())
- }
-}
-
-impl From<Cow<'_, str>> for QualifiedName {
- fn from(value: Cow<'_, str>) -> Self {
- Self::from(value.to_string())
- }
-}
-
-impl From<Vec<String>> for QualifiedName {
- fn from(value: Vec<String>) -> Self {
- Self::new(value)
- }
-}
-
-impl From<Vec<&str>> for QualifiedName {
- fn from(value: Vec<&str>) -> Self {
- value
- .iter()
- .map(ToString::to_string)
- .collect::<Vec<_>>()
- .into()
- }
-}
-
-impl From<QualifiedName> for String {
- fn from(value: QualifiedName) -> Self {
- value.to_string()
- }
-}
-
-impl Index<usize> for QualifiedName {
- type Output = String;
-
- fn index(&self, index: usize) -> &Self::Output {
- &self.items[index]
- }
-}
-
-impl IndexMut<usize> for QualifiedName {
- fn index_mut(&mut self, index: usize) -> &mut Self::Output {
- &mut self.items[index]
- }
-}
-
-impl Display for QualifiedName {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", self.items.join(&self.separator))
- }
-}
-
-impl CoreArrayProvider for QualifiedName {
- type Raw = BNQualifiedName;
- type Context = ();
- type Wrapped<'a> = Self;
-}
-
-unsafe impl CoreArrayProviderInner for QualifiedName {
- unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
- BNFreeTypeNameList(raw, count);
- }
-
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- QualifiedName::from_raw(raw)
- }
-}
-
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct QualifiedNameAndType {
pub name: QualifiedName,