use crate::{
lldb_addr_t, lldb_user_id_t, sys, Format, SBAddress, SBData, SBError, SBFrame, SBProcess,
SBStream, SBTarget, SBThread, SBWatchpoint,
};
use std::ffi::CStr;
use std::fmt;
pub struct SBValue {
pub raw: sys::SBValueRef,
}
impl SBValue {
pub(crate) fn wrap(raw: sys::SBValueRef) -> SBValue {
SBValue { raw }
}
pub(crate) fn maybe_wrap(raw: sys::SBValueRef) -> Option<SBValue> {
if unsafe { sys::SBValueIsValid(raw) } {
Some(SBValue { raw })
} else {
None
}
}
pub fn is_valid(&self) -> bool {
unsafe { sys::SBValueIsValid(self.raw) }
}
#[allow(missing_docs)]
pub fn clear(&self) {
unsafe { sys::SBValueClear(self.raw) };
}
#[allow(missing_docs)]
pub fn error(&self) -> Option<SBError> {
SBError::maybe_wrap(unsafe { sys::SBValueGetError(self.raw) })
}
#[allow(missing_docs)]
pub fn id(&self) -> lldb_user_id_t {
unsafe { sys::SBValueGetID(self.raw) }
}
#[allow(missing_docs)]
pub fn name(&self) -> &str {
unsafe {
match CStr::from_ptr(sys::SBValueGetName(self.raw)).to_str() {
Ok(s) => s,
_ => panic!("Invalid string?"),
}
}
}
#[allow(missing_docs)]
pub fn type_name(&self) -> &str {
unsafe {
match CStr::from_ptr(sys::SBValueGetTypeName(self.raw)).to_str() {
Ok(s) => s,
_ => panic!("Invalid string?"),
}
}
}
#[allow(missing_docs)]
pub fn display_type_name(&self) -> &str {
unsafe {
match CStr::from_ptr(sys::SBValueGetDisplayTypeName(self.raw)).to_str() {
Ok(s) => s,
_ => panic!("Invalid string?"),
}
}
}
#[allow(missing_docs)]
pub fn byte_size(&self) -> usize {
unsafe { sys::SBValueGetByteSize(self.raw) }
}
#[allow(missing_docs)]
pub fn is_in_scope(&self) -> bool {
unsafe { sys::SBValueIsInScope(self.raw) }
}
#[allow(missing_docs)]
pub fn format(&self) -> Format {
unsafe { sys::SBValueGetFormat(self.raw) }
}
#[allow(missing_docs)]
pub fn set_format(&self, format: Format) {
unsafe { sys::SBValueSetFormat(self.raw, format) }
}
#[allow(missing_docs)]
pub fn value(&self) -> &str {
unsafe {
match CStr::from_ptr(sys::SBValueGetValue(self.raw)).to_str() {
Ok(s) => s,
_ => panic!("Invalid string?"),
}
}
}
#[allow(missing_docs)]
pub fn dereference(&self) -> Option<SBValue> {
SBValue::maybe_wrap(unsafe { sys::SBValueDereference(self.raw) })
}
#[allow(missing_docs)]
pub fn address_of(&self) -> Option<SBValue> {
SBValue::maybe_wrap(unsafe { sys::SBValueAddressOf(self.raw) })
}
#[allow(missing_docs)]
pub fn type_is_pointer_type(&self) -> bool {
unsafe { sys::SBValueTypeIsPointerType(self.raw) }
}
#[allow(missing_docs)]
pub fn target(&self) -> SBTarget {
SBTarget::wrap(unsafe { sys::SBValueGetTarget(self.raw) })
}
#[allow(missing_docs)]
pub fn process(&self) -> SBProcess {
SBProcess::wrap(unsafe { sys::SBValueGetProcess(self.raw) })
}
#[allow(missing_docs)]
pub fn thread(&self) -> SBThread {
SBThread::wrap(unsafe { sys::SBValueGetThread(self.raw) })
}
#[allow(missing_docs)]
pub fn frame(&self) -> SBFrame {
SBFrame::wrap(unsafe { sys::SBValueGetFrame(self.raw) })
}
pub fn children(&self) -> SBValueChildIter {
SBValueChildIter {
value: self,
idx: 0,
}
}
pub fn watch(
&self,
resolve_location: bool,
read: bool,
write: bool,
) -> Result<SBWatchpoint, SBError> {
let error = SBError::default();
let wp = unsafe { sys::SBValueWatch(self.raw, resolve_location, read, write, error.raw) };
if error.is_success() {
Ok(SBWatchpoint::wrap(wp))
} else {
Err(error)
}
}
pub fn watch_pointee(
&self,
resolve_location: bool,
read: bool,
write: bool,
) -> Result<SBWatchpoint, SBError> {
let error = SBError::default();
let wp =
unsafe { sys::SBValueWatchPointee(self.raw, resolve_location, read, write, error.raw) };
if error.is_success() {
Ok(SBWatchpoint::wrap(wp))
} else {
Err(error)
}
}
pub fn pointee_data(&self, item_idx: u32, item_count: u32) -> Option<SBData> {
SBData::maybe_wrap(unsafe { sys::SBValueGetPointeeData(self.raw, item_idx, item_count) })
}
pub fn data(&self) -> Option<SBData> {
SBData::maybe_wrap(unsafe { sys::SBValueGetData(self.raw) })
}
#[allow(missing_docs)]
pub fn set_data(&self, data: &SBData) -> Result<(), SBError> {
let error = SBError::default();
if unsafe { sys::SBValueSetData(self.raw, data.raw, error.raw) } {
Ok(())
} else {
Err(error)
}
}
#[allow(missing_docs)]
pub fn load_address(&self) -> Option<lldb_addr_t> {
let load_address = unsafe { sys::SBValueGetLoadAddress(self.raw) };
if load_address != u64::max_value() {
Some(load_address)
} else {
None
}
}
#[allow(missing_docs)]
pub fn address(&self) -> Option<SBAddress> {
SBAddress::maybe_wrap(unsafe { sys::SBValueGetAddress(self.raw) })
}
}
impl Clone for SBValue {
fn clone(&self) -> SBValue {
SBValue {
raw: unsafe { sys::CloneSBValue(self.raw) },
}
}
}
impl fmt::Debug for SBValue {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let stream = SBStream::new();
unsafe { sys::SBValueGetDescription(self.raw, stream.raw) };
write!(fmt, "SBValue {{ {} }}", stream.data())
}
}
impl Drop for SBValue {
fn drop(&mut self) {
unsafe { sys::DisposeSBValue(self.raw) };
}
}
unsafe impl Send for SBValue {}
unsafe impl Sync for SBValue {}
pub struct SBValueChildIter<'d> {
value: &'d SBValue,
idx: u32,
}
impl<'d> Iterator for SBValueChildIter<'d> {
type Item = SBValue;
fn next(&mut self) -> Option<SBValue> {
if self.idx < unsafe { sys::SBValueGetNumChildren(self.value.raw) } {
let r = Some(SBValue::wrap(unsafe {
sys::SBValueGetChildAtIndex(self.value.raw, self.idx)
}));
self.idx += 1;
r
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let sz = unsafe { sys::SBValueGetNumChildren(self.value.raw) } as usize;
(sz - self.idx as usize, Some(sz))
}
}
impl<'d> ExactSizeIterator for SBValueChildIter<'d> {}
#[cfg(feature = "graphql")]
#[graphql_object]
impl SBValue {
fn id() -> i32 {
self.id() as i32
}
fn name() -> &str {
self.name()
}
fn type_name() -> &str {
self.type_name()
}
fn display_type_name() -> &str {
self.display_type_name()
}
fn byte_size() -> i32 {
self.byte_size() as i32
}
fn is_in_scope() -> bool {
self.is_in_scope()
}
}