Skip to content

refactor(crate): refactor robustone-core#41

Merged
Plucky923 merged 9 commits intohust-open-atom-club:mainfrom
Polardist:refactor-robustone-core
Dec 1, 2025
Merged

refactor(crate): refactor robustone-core#41
Plucky923 merged 9 commits intohust-open-atom-club:mainfrom
Polardist:refactor-robustone-core

Conversation

@Polardist
Copy link
Collaborator

  • Use thiserror crate for better error handling and display format
  • Refactor architecture for graceful converting &str and String to architecture enum
  • Refactor architecture and prepare to deprecated the old ArchitectureUtils usages
  • Refactor Instruction inner detail type, remove needless Box operation for dyn trait

The robustone-core crate fmt checks, clippy checks and tests all passed.

No user facing changes.

@Polardist Polardist marked this pull request as draft November 27, 2025 08:09
@Polardist
Copy link
Collaborator Author

Polardist commented Nov 27, 2025

CC @Plucky923 , more on that, we have a trait signature

pub trait InstructionDetail: std::fmt::Debug + Send + Sync {
    /// Returns the name of the architecture that produced this detail.
    fn architecture_name(&self) -> &'static str;

    /// Returns a list of register identifiers that are read by this instruction.
    fn registers_read(&self) -> Vec<u32>;

    /// Returns a list of register identifiers that are written by this instruction.
    fn registers_written(&self) -> Vec<u32>;
}

the return Vec always dose clone, change API to return &Vec and let user to determine when to clone could be more graceful. Is it designed to clone every time in purpose ?

@Polardist Polardist marked this pull request as ready for review November 27, 2025 08:17
is_address_aligned(address, alignment)
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After the refactoring, ArchitectureUtils seems to be a redundant abstraction. Consider removing it and only provide some auxiliary functions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provide fn normalize_name and fn is_address_aligned at module level; this ArchitectureUtils structure can be removed.

Copy link
Collaborator Author

@Polardist Polardist Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provide fn normalize_name and fn is_address_aligned at module level; this ArchitectureUtils structure can be removed.

Do we have to keep normalize_name function, rather than str/String.to_arch() ? Current API provide Architecture from both &str and String.

@Plucky923
Copy link
Collaborator

CC @Plucky923 , more on that, we have a trait signature

pub trait InstructionDetail: std::fmt::Debug + Send + Sync {
    /// Returns the name of the architecture that produced this detail.
    fn architecture_name(&self) -> &'static str;

    /// Returns a list of register identifiers that are read by this instruction.
    fn registers_read(&self) -> Vec<u32>;

    /// Returns a list of register identifiers that are written by this instruction.
    fn registers_written(&self) -> Vec<u32>;
}

the return Vec always dose clone, change API to return &Vec and let user to determine when to clone could be more graceful. Is it designed to clone every time in purpose ?

I think it's like this. There should be no redundant heap allocation here. We will consider optimizing it later.

@manchangfengxu
Copy link
Contributor

CC @Plucky923 , more on that, we have a trait signature

pub trait InstructionDetail: std::fmt::Debug + Send + Sync {
    /// Returns the name of the architecture that produced this detail.
    fn architecture_name(&self) -> &'static str;

    /// Returns a list of register identifiers that are read by this instruction.
    fn registers_read(&self) -> Vec<u32>;

    /// Returns a list of register identifiers that are written by this instruction.
    fn registers_written(&self) -> Vec<u32>;
}

the return Vec always dose clone, change API to return &Vec and let user to determine when to clone could be more graceful. Is it designed to clone every time in purpose ?

According to what you said let user to determine when to clone.., can we use Cow?

A clone-on-write smart pointer.

The type Cow is a smart pointer providing clone-on-write functionality: it can enclose and provide immutable access to borrowed data, and clone the data lazily when mutation or ownership is required. The type is designed to work with general borrowed data via the Borrow trait.

@Plucky923
Copy link
Collaborator

CC @Plucky923 , more on that, we have a trait signature

pub trait InstructionDetail: std::fmt::Debug + Send + Sync {
    /// Returns the name of the architecture that produced this detail.
    fn architecture_name(&self) -> &'static str;

    /// Returns a list of register identifiers that are read by this instruction.
    fn registers_read(&self) -> Vec<u32>;

    /// Returns a list of register identifiers that are written by this instruction.
    fn registers_written(&self) -> Vec<u32>;
}

the return Vec always dose clone, change API to return &Vec and let user to determine when to clone could be more graceful. Is it designed to clone every time in purpose ?

According to what you said let user to determine when to clone.., can we use Cow?

A clone-on-write smart pointer.

The type Cow is a smart pointer providing clone-on-write functionality: it can enclose and provide immutable access to borrowed data, and clone the data lazily when mutation or ownership is required. The type is designed to work with general borrowed data via the Borrow trait.

There is no need to use Cow. Pass references or ownership directly. These contents are usually allocated and stored in memory. There's no place where they need to be copied.


// Test R-type: add x1, x2, x3
let instruction = 0b0000000_00011_00010_000_00001_0110011;
let instruction = 0b0000_0000_0011_0001_0000_0000_1011_0011;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This partitioning method doesn't show the number of digits in each field, so I'd recommend leaving it unchanged.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If leave it unchanged, clippy raise a warning

warning: digits of hex, binary or octal literal not in groups of equal size
   --> robustone-core/src/riscv/shared/encoding.rs:478:28
    |
478 |          let instruction = 0b0000000_00011_00010_000_00001_0110011;
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider: `0b0000_0000_0011_0001_0000_0000_1011_0011`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.91.0/index.html#unusual_byte_groupings
    = note: `#[warn(clippy::unusual_byte_groupings)]` on by default

I would like to follow the clippy recommandation :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clippy's inspection of binary numbers usually requires splitting every four digits. However, in this context, each split represents each part of the instruction, such as opcode, destination register, etc. Both methods are acceptable, depending on which one is more readable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see it now, I will revert these digital format changes for this PR.

@Plucky923 Plucky923 merged commit a370d11 into hust-open-atom-club:main Dec 1, 2025
8 checks passed
@Plucky923
Copy link
Collaborator

LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants