Implement bit-fields.

This commit is contained in:
Stephen Chung
2021-06-02 14:29:18 +08:00
parent 25e99af07e
commit 71684f5e2a
11 changed files with 497 additions and 97 deletions

View File

@@ -1,7 +1,7 @@
#![allow(non_snake_case)]
use crate::def_package;
use crate::plugin::*;
use crate::{def_package, EvalAltResult, INT};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
@@ -59,6 +59,8 @@ def_package!(crate:LogicPackage:"Logical operators.", lib, {
}
set_exported_fn!(lib, "!", not);
combine_with_exported_module!(lib, "bit_field", bit_field_functions);
});
// Logic operators
@@ -87,8 +89,6 @@ gen_cmp_functions!(float => f64);
#[cfg(not(feature = "no_float"))]
#[export_module]
mod f32_functions {
use crate::INT;
#[rhai_fn(name = "==")]
pub fn eq_if(x: INT, y: f32) -> bool {
(x as f32) == (y as f32)
@@ -142,8 +142,6 @@ mod f32_functions {
#[cfg(not(feature = "no_float"))]
#[export_module]
mod f64_functions {
use crate::INT;
#[rhai_fn(name = "==")]
pub fn eq_if(x: INT, y: f64) -> bool {
(x as f64) == (y as f64)
@@ -193,3 +191,159 @@ mod f64_functions {
(x as f64) <= (y as f64)
}
}
#[export_module]
mod bit_field_functions {
const BITS: usize = std::mem::size_of::<INT>() * 8;
#[rhai_fn(return_raw)]
pub fn get_bit(value: INT, index: INT) -> Result<bool, Box<EvalAltResult>> {
if index >= 0 {
let offset = index as usize;
if offset >= BITS {
EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into()
} else {
Ok((value & (1 << offset)) != 0)
}
} else if let Some(abs_index) = index.checked_abs() {
let offset = abs_index as usize;
// Count from end if negative
if offset > BITS {
EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into()
} else {
Ok((value & (1 << (BITS - offset))) != 0)
}
} else {
EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into()
}
}
#[rhai_fn(return_raw)]
pub fn set_bit(value: &mut INT, index: INT, new_value: bool) -> Result<(), Box<EvalAltResult>> {
if index >= 0 {
let offset = index as usize;
if offset >= BITS {
EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into()
} else {
let mask = 1 << offset;
if new_value {
*value |= mask;
} else {
*value &= !mask;
}
Ok(())
}
} else if let Some(abs_index) = index.checked_abs() {
let offset = abs_index as usize;
// Count from end if negative
if offset > BITS {
EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into()
} else {
let mask = 1 << offset;
if new_value {
*value |= mask;
} else {
*value &= !mask;
}
Ok(())
}
} else {
EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into()
}
}
#[rhai_fn(return_raw)]
pub fn get_bits(value: INT, index: INT, bits: INT) -> Result<INT, Box<EvalAltResult>> {
if bits < 1 {
return Ok(0);
}
let offset = if index >= 0 {
let offset = index as usize;
if offset >= BITS {
return EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into();
}
offset
} else if let Some(abs_index) = index.checked_abs() {
let offset = abs_index as usize;
// Count from end if negative
if offset > BITS {
return EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into();
}
BITS - offset
} else {
return EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into();
};
let bits = if offset + bits as usize > BITS {
BITS - offset
} else {
bits as usize
};
let mut base = 1;
let mut mask = 0;
for _ in 0..bits {
mask |= base;
base <<= 1;
}
Ok(((value & (mask << index)) >> index) & mask)
}
#[rhai_fn(return_raw)]
pub fn set_bits(
value: &mut INT,
index: INT,
bits: INT,
new_value: INT,
) -> Result<(), Box<EvalAltResult>> {
if bits < 1 {
return Ok(());
}
let offset = if index >= 0 {
let offset = index as usize;
if offset >= BITS {
return EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into();
}
offset
} else if let Some(abs_index) = index.checked_abs() {
let offset = abs_index as usize;
// Count from end if negative
if offset > BITS {
return EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into();
}
BITS - offset
} else {
return EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into();
};
let bits = if offset + bits as usize > BITS {
BITS - offset
} else {
bits as usize
};
let mut base = 1;
let mut mask = 0;
for _ in 0..bits {
mask |= base;
base <<= 1;
}
*value &= !(mask << index);
*value |= (new_value & mask) << index;
Ok(())
}
}