use idakit_sys as sys;
use super::diff::{CanonicalOptions, CanonicalType};
use super::{Type, walk_type};
use crate::Database;
use crate::error::{Error, Result};
impl Database {
#[inline]
#[must_use]
#[doc(alias("get_ordinal_limit"))]
pub fn named_types(&self) -> NamedTypes<'_> {
NamedTypes::new(self)
}
}
#[derive(Clone, Copy)]
#[doc(alias("get_numbered_type"))]
pub struct NamedType<'db> {
db: &'db Database,
ordinal: u32,
}
impl<'db> NamedType<'db> {
#[inline]
fn new(db: &'db Database, ordinal: u32) -> Self {
Self { db, ordinal }
}
#[inline]
#[must_use]
pub const fn ordinal(&self) -> u32 {
self.ordinal
}
#[must_use]
#[doc(alias("get_numbered_type_name"))]
pub fn name(&self) -> String {
self.db.type_name_at(self.ordinal)
}
#[doc(alias("get_numbered_type"))]
pub fn resolve(&self) -> Result<Type> {
crate::claim::ensure_kernel_thread();
match walk_type(|sink| sys::walk_type_ordinal(self.ordinal, sink)) {
Ok(Some(ty)) => Ok(ty),
Ok(None) => Err(Error::TypeNotFound { name: self.name() }),
Err(source) => Err(Error::Extract { address: 0, source }),
}
}
pub fn canonical(&self) -> Result<CanonicalType> {
Ok(self.resolve()?.canonical())
}
pub fn canonical_with(&self, opts: CanonicalOptions) -> Result<CanonicalType> {
Ok(self.resolve()?.canonical_with(opts))
}
}
impl std::fmt::Debug for NamedType<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NamedType")
.field("ordinal", &self.ordinal)
.finish_non_exhaustive()
}
}
key_identity!(NamedType, ordinal);
#[doc(alias("get_ordinal_limit"))]
pub struct NamedTypes<'db> {
db: &'db Database,
next: u32,
limit: u32,
}
impl<'db> NamedTypes<'db> {
fn new(db: &'db Database) -> Self {
let limit = match db.type_ordinal_limit() {
u32::MAX => 0,
n => n,
};
Self { db, next: 1, limit }
}
}
impl std::fmt::Debug for NamedTypes<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NamedTypes")
.field("next", &self.next)
.field("limit", &self.limit)
.finish_non_exhaustive()
}
}
impl<'db> Iterator for NamedTypes<'db> {
type Item = NamedType<'db>;
fn next(&mut self) -> Option<Self::Item> {
while self.next < self.limit {
let candidate = NamedType::new(self.db, self.next);
self.next += 1;
if !candidate.name().is_empty() {
return Some(candidate);
}
}
None
}
}
#[cfg(test)]
mod tests {
use assert2::assert;
use super::*;
#[test]
fn named_type_identity_compares_by_ordinal() {
let db = Database::new();
assert!(NamedType::new(&db, 3) == NamedType::new(&db, 3));
assert!(NamedType::new(&db, 3) != NamedType::new(&db, 4));
}
#[test]
fn named_type_debug_renders_the_ordinal() {
let db = Database::new();
let ty = NamedType::new(&db, 7);
assert!(format!("{ty:?}") == "NamedType { ordinal: 7, .. }");
}
#[test]
fn named_types_debug_renders_progress() {
let db = Database::new();
let iter = NamedTypes {
db: &db,
next: 1,
limit: 5,
};
assert!(format!("{iter:?}") == "NamedTypes { next: 1, limit: 5, .. }");
}
}