use clap::{Parser, ValueEnum};
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct BitOperation {
#[arg(short, long, value_enum)]
command: Command,
#[arg(short, long, value_parser = clap::value_parser!(u8).range(0..=255))]
number: u8,
#[arg(short, long, value_parser = clap::value_parser!(u8).range(0..=7))]
bit_index: u8,
}
#[derive(Debug, Clone, ValueEnum, PartialEq)]
enum Command {
Set,
Clear,
Toggle,
Check,
}
#[derive(Debug)]
enum ShiftDirection {
Left,
Right,
}
#[derive(Debug, Clone)]
enum CommandResult {
Value(u8),
State(bool),
}
fn print_usage() {
println!("Bitmask Manipulation Tool - Usage:");
println!();
println!("Commands:");
println!(" SET <number> <bit_index> - Set bit at index to 1");
println!(" CLEAR <number> <bit_index> - Clear bit at index to 0");
println!(" TOGGLE <number> <bit_index> - Flip bit at index");
println!(" CHECK <number> <bit_index> - Check if bit at index is 1");
println!();
println!("Examples:");
println!(
" bitmask-tool SET 8 3 # Result: 8 | (1 << 3) => 00001000 | 00001000 = 00001000"
);
println!(" bitmask-tool TOGGLE 8 3 # Result: 00001000 ^ 00001000 = 00000000");
println!();
println!("Notes:");
println!(" <number> must be an integer between 0 and 255 (u8).");
println!(" <bit_index> must be between 0 and 7.");
}
fn shift(n: u8, index: u8, direction: ShiftDirection) -> u8 {
match direction {
ShiftDirection::Left => n << index,
ShiftDirection::Right => n >> index,
}
}
fn set(bin: u8, bit_index: u8) -> u8 {
bin | shift(1, bit_index, ShiftDirection::Left)
}
fn clear(bin: u8, bit_index: u8) -> u8 {
bin & !shift(1, bit_index, ShiftDirection::Left)
}
fn toggle(bin: u8, bit_index: u8) -> u8 {
bin ^ shift(1, bit_index, ShiftDirection::Left)
}
fn check(bin: u8, bit_index: u8) -> bool {
(bin & shift(1, bit_index, ShiftDirection::Left)) != 0
}
fn display_bin(bin: u8, cmd: Command, bit_index: u8, result: CommandResult) {
println!("\n=== Bitmask Tool Result ===");
println!("Input Byte : {:08b} ({})", bin, bin);
println!("Command : {:?} @ Bit Index {}", cmd, bit_index);
match result {
CommandResult::Value(v) => println!("Output Byte : {:08b} ({})", v, v),
CommandResult::State(b) => println!("Bit Status : {}", b),
}
println!("============================\n");
}
fn main() {
let args = BitOperation::parse();
let result: CommandResult = match args.command {
Command::Set => CommandResult::Value(set(args.number, args.bit_index)),
Command::Clear => CommandResult::Value(clear(args.number, args.bit_index)),
Command::Toggle => CommandResult::Value(toggle(args.number, args.bit_index)),
Command::Check => CommandResult::State(check(args.number, args.bit_index)),
};
display_bin(args.number, args.command.clone(), args.bit_index, result);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_set() {
assert_eq!(set(0b00000000, 3), 0b00001000);
assert_eq!(set(0b00001000, 3), 0b00001000); }
#[test]
fn test_clear() {
assert_eq!(clear(0b11111111, 3), 0b11110111);
assert_eq!(clear(0b00000000, 3), 0b00000000);
}
#[test]
fn test_toggle() {
assert_eq!(toggle(0b00001000, 3), 0b00000000);
assert_eq!(toggle(0b00000000, 3), 0b00001000);
}
#[test]
fn test_check() {
assert_eq!(check(0b00001000, 3), true);
assert_eq!(check(0b00000000, 3), false);
}
#[test]
fn test_shift_left() {
assert_eq!(shift(1, 3, ShiftDirection::Left), 0b00001000);
}
#[test]
fn test_shift_right() {
assert_eq!(shift(0b00001000, 3, ShiftDirection::Right), 0b00000001);
}
}