Skip to main content

TypesMut

Struct TypesMut 

Source
pub struct TypesMut<'db> { /* private fields */ }
Expand description

A write cursor over the database’s local type library, from Database::types_mut.

Holds the database exclusively. Exposes define for whole declarations and edit for member surgery on an existing named type.

Implementations§

Source§

impl TypesMut<'_>

Source

pub fn define(&mut self, decl: impl AsRef<str>) -> Result<()>

Parse the C declaration(s) in decl into the database’s local type library.

A struct, union, enum, or typedef declaration becomes a named type that later set_type calls can reference by name, and that named_types then enumerates. Redeclarations are tolerated.

decl may hold several declarations. It is not atomic: on an error, declarations that parsed before the failure are already defined.

db.types_mut().define("struct Point { int x; int y; };")?;
assert!(db.named_types().any(|t| t.name() == "Point"));
§Errors

Error::TypeDefineFailed if IDA rejects any declaration (with its own diagnostics), or Error::InteriorNul if decl contains a NUL byte.

Examples found in repository?
examples/edits.rs (line 162)
158fn defining_types(idb: &mut Database) -> Result<(), Error> {
159    println!("\n== types_mut: define ==");
160
161    idb.types_mut()
162        .define("struct edit_demo_t { int id; char *name; };")?;
163    let present = idb.named_types().any(|t| t.name() == "edit_demo_t");
164    println!("  defined edit_demo_t, present in named types: {present}");
165
166    // A declaration referencing the just-defined type resolves against the local til.
167    match idb
168        .types_mut()
169        .define("typedef struct edit_demo_t edit_demo_alias;")
170    {
171        Ok(()) => println!("  typedef alias to it: ok"),
172        Err(e) => println!("  typedef alias: {e}"),
173    }
174
175    // A malformed declaration is a typed error carrying IDA's own reason.
176    match idb.types_mut().define("struct broken { not valid") {
177        Err(Error::TypeDefineFailed { reason, .. }) => {
178            println!("  malformed define -> TypeDefineFailed: {reason}");
179        }
180        other => println!("  malformed define -> unexpected {other:?}"),
181    }
182    Ok(())
183}
184
185/// Member surgery on defined types: append/retype/rename struct fields through the `member(..)`
186/// sub-cursor (with the structured rejection when a rename collides), then add and revalue enum
187/// constants through `constant(..)`. Each edit auto-saves to the local til; nothing persists past
188/// `save = false`.
189fn editing_members(idb: &mut Database) -> Result<(), Error> {
190    use idakit::types::expr;
191
192    println!("\n== types_mut: edit members ==");
193
194    idb.types_mut()
195        .define("struct edit_member_demo { int a; int b; };")?;
196
197    idb.types_mut()
198        .edit("edit_member_demo")
199        .add_member("c", expr::int32())?;
200    idb.types_mut()
201        .edit("edit_member_demo")
202        .member("a")
203        .set_type(expr::char_())?;
204    idb.types_mut()
205        .edit("edit_member_demo")
206        .member("b")
207        .rename("beta")?;
208
209    let names: Vec<String> = idb
210        .type_named("edit_member_demo")?
211        .members()
212        .unwrap_or_default()
213        .iter()
214        .map(|m| m.name.clone())
215        .collect();
216    println!("  after add + retype + rename, members: {names:?}");
217
218    // Renaming onto an existing name surfaces the structured tinfo_code.
219    match idb
220        .types_mut()
221        .edit("edit_member_demo")
222        .member("c")
223        .rename("a")
224    {
225        Err(Error::TypeWrite {
226            source: TypeWriteError::Rejected { code, .. },
227        }) => println!("  duplicate rename -> Rejected({code})"),
228        other => println!("  duplicate rename -> unexpected {other:?}"),
229    }
230
231    // Enum constants use the same cursor: add, revalue, rename.
232    idb.types_mut()
233        .define("enum edit_enum_demo { DEMO_A = 1, DEMO_B = 2 };")?;
234    idb.types_mut()
235        .edit("edit_enum_demo")
236        .add_constant("DEMO_C", 3)?;
237    idb.types_mut()
238        .edit("edit_enum_demo")
239        .constant("DEMO_A")
240        .set_value(10)?;
241    let constants: Vec<(String, u64)> = match idb.type_named("edit_enum_demo")?.shape() {
242        TypeShape::Enum { members, .. } => {
243            members.iter().map(|m| (m.name.clone(), m.value)).collect()
244        }
245        _ => Vec::new(),
246    };
247    println!("  after add + revalue, constants: {constants:?}");
248    Ok(())
249}
Source

pub fn delete(&mut self, name: impl AsRef<str>) -> Result<()>

Delete the named type name from the database’s local type library.

The til-level inverse of define: removes a struct, union, enum, or typedef entry outright. Not idempotent: deleting a name that does not exist is TypeWriteError::NoType, the same treatment MemberEdit::delete gives an unresolved member.

db.types_mut().define("struct Scratch { int x; };")?;
db.types_mut().delete("Scratch")?;
assert!(!db.named_types().any(|t| t.name() == "Scratch"));
§Errors

TypeWriteError::NoType if no type named name exists, TypeWriteError::Rejected if the kernel refuses the deletion, or Error::InteriorNul if name contains a NUL byte.

Source

pub fn rename( &mut self, name: impl AsRef<str>, new_name: impl AsRef<str>, ) -> Result<()>

Rename the named type name to new_name, in place.

Preserves the type’s ordinal and every reference to it: the underlying SDK call (rename_type) updates the til entry’s name without reallocating it.

db.types_mut().define("struct Old { int x; };")?;
db.types_mut().rename("Old", "New")?;
assert!(db.named_types().any(|t| t.name() == "New"));
assert!(!db.named_types().any(|t| t.name() == "Old"));
§Errors

TypeWriteError::NoType if no type named name exists, TypeWriteError::Rejected (e.g. TypeEditCode::DupName if new_name is already taken), or Error::InteriorNul if either name contains a NUL byte.

Source

pub fn forward_declare( &mut self, name: impl AsRef<str>, kind: AggregateKind, ) -> Result<()>

Reserve name in the local type library as an incomplete kind aggregate, with no body.

The explicit counterpart to the "struct Foo;" idiom through define: reserves the tag without describing its members, so a later define with a full body over the same name completes it. Until then, the type reads back as TypeShape::Opaque, the same shape any other unresolved or bodyless named type takes.

use idakit::types::diff::AggregateKind;

db.types_mut()
    .forward_declare("idakit_fwd_probe", AggregateKind::Struct)?;
assert!(db.named_types().any(|t| t.name() == "idakit_fwd_probe"));
§Errors

TypeWriteError::Rejected if the kernel refuses the declaration (e.g. name is already taken by an incompatible type), or Error::InteriorNul if name contains a NUL byte.

Source

pub fn edit(&mut self, name: impl Into<String>) -> TypeEdit<'_>

Open the existing named type name for member surgery.

Infallible to acquire: a missing type surfaces as TypeWriteError::NoType from the first edit, so edit(...).member(...).set_type(...) chains without an intermediate check. Each verb is a self-contained load, mutate, and auto-save against the live type.

Examples found in repository?
examples/edits.rs (line 198)
189fn editing_members(idb: &mut Database) -> Result<(), Error> {
190    use idakit::types::expr;
191
192    println!("\n== types_mut: edit members ==");
193
194    idb.types_mut()
195        .define("struct edit_member_demo { int a; int b; };")?;
196
197    idb.types_mut()
198        .edit("edit_member_demo")
199        .add_member("c", expr::int32())?;
200    idb.types_mut()
201        .edit("edit_member_demo")
202        .member("a")
203        .set_type(expr::char_())?;
204    idb.types_mut()
205        .edit("edit_member_demo")
206        .member("b")
207        .rename("beta")?;
208
209    let names: Vec<String> = idb
210        .type_named("edit_member_demo")?
211        .members()
212        .unwrap_or_default()
213        .iter()
214        .map(|m| m.name.clone())
215        .collect();
216    println!("  after add + retype + rename, members: {names:?}");
217
218    // Renaming onto an existing name surfaces the structured tinfo_code.
219    match idb
220        .types_mut()
221        .edit("edit_member_demo")
222        .member("c")
223        .rename("a")
224    {
225        Err(Error::TypeWrite {
226            source: TypeWriteError::Rejected { code, .. },
227        }) => println!("  duplicate rename -> Rejected({code})"),
228        other => println!("  duplicate rename -> unexpected {other:?}"),
229    }
230
231    // Enum constants use the same cursor: add, revalue, rename.
232    idb.types_mut()
233        .define("enum edit_enum_demo { DEMO_A = 1, DEMO_B = 2 };")?;
234    idb.types_mut()
235        .edit("edit_enum_demo")
236        .add_constant("DEMO_C", 3)?;
237    idb.types_mut()
238        .edit("edit_enum_demo")
239        .constant("DEMO_A")
240        .set_value(10)?;
241    let constants: Vec<(String, u64)> = match idb.type_named("edit_enum_demo")?.shape() {
242        TypeShape::Enum { members, .. } => {
243            members.iter().map(|m| (m.name.clone(), m.value)).collect()
244        }
245        _ => Vec::new(),
246    };
247    println!("  after add + revalue, constants: {constants:?}");
248    Ok(())
249}

Trait Implementations§

Source§

impl Debug for TypesMut<'_>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'db> !RefUnwindSafe for TypesMut<'db>

§

impl<'db> !Sync for TypesMut<'db>

§

impl<'db> !UnwindSafe for TypesMut<'db>

§

impl<'db> Freeze for TypesMut<'db>

§

impl<'db> Send for TypesMut<'db>

§

impl<'db> Unpin for TypesMut<'db>

§

impl<'db> UnsafeUnpin for TypesMut<'db>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more