use std::borrow::Cow;
use std::cell::Cell;
use std::cmp;
use std::rc::Rc;
use std::usize;
use crate::file::FileHash;
use crate::location::{self, FrameLocation, Location, Piece, Register};
use crate::namespace::Namespace;
use crate::range::Range;
use crate::source::Source;
use crate::types::{Type, TypeOffset};
use crate::{Address, Size};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct VariableOffset(usize);
impl VariableOffset {
#[inline]
pub(crate) fn new(offset: usize) -> VariableOffset {
debug_assert!(VariableOffset(offset) != VariableOffset::none());
VariableOffset(offset)
}
#[inline]
pub(crate) fn none() -> VariableOffset {
VariableOffset(usize::MAX)
}
}
impl Default for VariableOffset {
#[inline]
fn default() -> Self {
VariableOffset::none()
}
}
#[derive(Debug, Default)]
pub struct Variable<'input> {
pub(crate) id: Cell<usize>,
pub(crate) offset: VariableOffset,
pub(crate) namespace: Option<Rc<Namespace<'input>>>,
pub(crate) name: Option<&'input str>,
pub(crate) linkage_name: Option<&'input str>,
pub(crate) symbol_name: Option<&'input str>,
pub(crate) ty: TypeOffset,
pub(crate) source: Source<'input>,
pub(crate) address: Address,
pub(crate) size: Size,
pub(crate) declaration: bool,
}
impl<'input> Variable<'input> {
#[inline]
pub fn id(&self) -> usize {
self.id.get()
}
#[inline]
pub fn set_id(&self, id: usize) {
self.id.set(id)
}
pub fn namespace(&self) -> Option<&Namespace> {
self.namespace.as_ref().map(|x| &**x)
}
#[inline]
pub fn name(&self) -> Option<&str> {
self.name
}
#[inline]
pub fn linkage_name(&self) -> Option<&str> {
self.linkage_name
}
#[inline]
pub fn symbol_name(&self) -> Option<&str> {
self.symbol_name
}
#[inline]
pub fn ty<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
Type::from_offset(hash, self.ty)
}
#[inline]
pub fn source(&self) -> &Source<'input> {
&self.source
}
#[inline]
pub fn address(&self) -> Option<u64> {
self.address.get()
}
pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
if self.size.is_some() {
self.size.get()
} else {
self.ty(hash).and_then(|t| t.byte_size(hash))
}
}
pub fn range(&self, hash: &FileHash) -> Option<Range> {
match (self.address(), self.byte_size(hash)) {
(Some(begin), Some(size)) => {
if size != 0 {
Some(Range {
begin,
end: begin + size,
})
} else {
None
}
}
_ => None,
}
}
#[inline]
pub fn is_declaration(&self) -> bool {
self.declaration
}
pub fn cmp_id(
_hash_a: &FileHash,
a: &Variable,
_hash_b: &FileHash,
b: &Variable,
) -> cmp::Ordering {
Namespace::cmp_ns_and_name(a.namespace(), a.name(), b.namespace(), b.name())
}
}
#[derive(Debug, Default, Clone)]
pub struct LocalVariable<'input> {
pub(crate) offset: VariableOffset,
pub(crate) name: Option<&'input str>,
pub(crate) ty: TypeOffset,
pub(crate) source: Source<'input>,
pub(crate) address: Address,
pub(crate) size: Size,
pub(crate) locations: Vec<(Range, Piece)>,
}
impl<'input> LocalVariable<'input> {
#[inline]
pub fn name(&self) -> Option<&'input str> {
self.name
}
#[inline]
pub fn type_offset(&self) -> TypeOffset {
self.ty
}
#[inline]
pub fn ty<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
Type::from_offset(hash, self.ty)
}
#[inline]
pub fn source(&self) -> &Source<'input> {
&self.source
}
#[inline]
pub fn address(&self) -> Option<u64> {
self.address.get()
}
pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
if self.size.is_some() {
self.size.get()
} else {
self.ty(hash).and_then(|t| t.byte_size(hash))
}
}
pub fn registers<'a>(&'a self) -> impl Iterator<Item = (Range, Register)> + 'a {
location::registers(&self.locations)
}
pub fn register_offsets<'a>(&'a self) -> impl Iterator<Item = (Range, Register, i64)> + 'a {
location::register_offsets(&self.locations)
}
pub fn frame_locations<'a>(&'a self) -> impl Iterator<Item = FrameLocation> + 'a {
self.locations.iter().filter_map(|(_, piece)| {
if piece.is_value {
return None;
}
match piece.location {
Location::FrameOffset { offset } | Location::CfaOffset { offset } => {
Some(FrameLocation {
offset,
bit_size: piece.bit_size,
})
}
_ => None,
}
})
}
pub fn cmp_id(_hash_a: &FileHash, a: &Self, _hash_b: &FileHash, b: &Self) -> cmp::Ordering {
a.name.cmp(&b.name)
}
}