diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c0d1ee4..878bdc07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ Script-breaking changes * `is` is (pun intended) now a reserved keyword to prepare for possible future type checking expressions (e.g. `x is "string"`). +Breaking changes +---------------- + +* `LogicPackage` is removed from `CorePackage`. +* Bit-field functions are moved into a new `BitFieldPackage` (used to be in `LogicPackage`) which makes more sense. + New features ------------ diff --git a/src/packages/bit_field.rs b/src/packages/bit_field.rs new file mode 100644 index 00000000..57155f68 --- /dev/null +++ b/src/packages/bit_field.rs @@ -0,0 +1,198 @@ +#![allow(non_snake_case)] + +use crate::plugin::*; +use crate::{def_package, ExclusiveRange, InclusiveRange, Position, RhaiResultOf, ERR, INT}; +#[cfg(feature = "no_std")] +use std::prelude::v1::*; + +def_package! { + /// Package of basic bit-field utilities. + crate::BitFieldPackage => |lib| { + lib.standard = true; + + combine_with_exported_module!(lib, "bit_field", bit_field_functions); + } +} + +#[export_module] +mod bit_field_functions { + const BITS: usize = std::mem::size_of::() * 8; + + #[rhai_fn(return_raw)] + pub fn get_bit(value: INT, index: INT) -> RhaiResultOf { + if index >= 0 { + let offset = index as usize; + + if offset >= BITS { + Err(ERR::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 { + Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()) + } else { + Ok((value & (1 << (BITS - offset))) != 0) + } + } else { + Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()) + } + } + #[rhai_fn(return_raw)] + pub fn set_bit(value: &mut INT, index: INT, new_value: bool) -> RhaiResultOf<()> { + if index >= 0 { + let offset = index as usize; + + if offset >= BITS { + Err(ERR::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 { + Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()) + } else { + let mask = 1 << offset; + if new_value { + *value |= mask; + } else { + *value &= !mask; + } + Ok(()) + } + } else { + Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()) + } + } + #[rhai_fn(name = "get_bits", return_raw)] + pub fn get_bits_range(value: INT, range: ExclusiveRange) -> RhaiResultOf { + let from = INT::max(range.start, 0); + let to = INT::max(range.end, from); + get_bits(value, from, to - from) + } + #[rhai_fn(name = "get_bits", return_raw)] + pub fn get_bits_range_inclusive(value: INT, range: InclusiveRange) -> RhaiResultOf { + let from = INT::max(*range.start(), 0); + let to = INT::max(*range.end(), from - 1); + get_bits(value, from, to - from + 1) + } + #[rhai_fn(return_raw)] + pub fn get_bits(value: INT, index: INT, bits: INT) -> RhaiResultOf { + if bits < 1 { + return Ok(0); + } + + let offset = if index >= 0 { + let offset = index as usize; + + if offset >= BITS { + return Err(ERR::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 Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()); + } + BITS - offset + } else { + return Err(ERR::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(name = "set_bits", return_raw)] + pub fn set_bits_range( + value: &mut INT, + range: ExclusiveRange, + new_value: INT, + ) -> RhaiResultOf<()> { + let from = INT::max(range.start, 0); + let to = INT::max(range.end, from); + set_bits(value, from, to - from, new_value) + } + #[rhai_fn(name = "set_bits", return_raw)] + pub fn set_bits_range_inclusive( + value: &mut INT, + range: InclusiveRange, + new_value: INT, + ) -> RhaiResultOf<()> { + let from = INT::max(*range.start(), 0); + let to = INT::max(*range.end(), from - 1); + set_bits(value, from, to - from + 1, new_value) + } + #[rhai_fn(return_raw)] + pub fn set_bits(value: &mut INT, index: INT, bits: INT, new_value: INT) -> RhaiResultOf<()> { + if bits < 1 { + return Ok(()); + } + + let offset = if index >= 0 { + let offset = index as usize; + + if offset >= BITS { + return Err(ERR::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 Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()); + } + BITS - offset + } else { + return Err(ERR::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(()) + } +} diff --git a/src/packages/lang_core.rs b/src/packages/lang_core.rs index 400b1332..a84b6628 100644 --- a/src/packages/lang_core.rs +++ b/src/packages/lang_core.rs @@ -16,6 +16,10 @@ def_package! { #[export_module] mod core_functions { + #[rhai_fn(name = "!")] + pub fn not(x: bool) -> bool { + !x + } #[rhai_fn(name = "tag", get = "tag", pure)] pub fn get_tag(value: &mut Dynamic) -> INT { value.tag() as INT diff --git a/src/packages/logic.rs b/src/packages/logic.rs index fb87a5f9..860adcda 100644 --- a/src/packages/logic.rs +++ b/src/packages/logic.rs @@ -1,7 +1,7 @@ #![allow(non_snake_case)] use crate::plugin::*; -use crate::{def_package, ExclusiveRange, InclusiveRange, RhaiResultOf, ERR, INT}; +use crate::{def_package, INT}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -61,19 +61,9 @@ def_package! { reg_functions!(lib += float; f64); combine_with_exported_module!(lib, "f64", f64_functions); } - - set_exported_fn!(lib, "!", not); - - combine_with_exported_module!(lib, "bit_field", bit_field_functions); } } -// Logic operators -#[export_fn] -fn not(x: bool) -> bool { - !x -} - #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] gen_cmp_functions!(numbers => i8, u8, i16, u16, i32, u32, u64); @@ -196,186 +186,3 @@ mod f64_functions { (x as f64) <= (y as f64) } } - -#[export_module] -mod bit_field_functions { - const BITS: usize = std::mem::size_of::() * 8; - - #[rhai_fn(return_raw)] - pub fn get_bit(value: INT, index: INT) -> RhaiResultOf { - if index >= 0 { - let offset = index as usize; - - if offset >= BITS { - Err(ERR::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 { - Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()) - } else { - Ok((value & (1 << (BITS - offset))) != 0) - } - } else { - Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()) - } - } - #[rhai_fn(return_raw)] - pub fn set_bit(value: &mut INT, index: INT, new_value: bool) -> RhaiResultOf<()> { - if index >= 0 { - let offset = index as usize; - - if offset >= BITS { - Err(ERR::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 { - Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()) - } else { - let mask = 1 << offset; - if new_value { - *value |= mask; - } else { - *value &= !mask; - } - Ok(()) - } - } else { - Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()) - } - } - #[rhai_fn(name = "get_bits", return_raw)] - pub fn get_bits_range(value: INT, range: ExclusiveRange) -> RhaiResultOf { - let from = INT::max(range.start, 0); - let to = INT::max(range.end, from); - get_bits(value, from, to - from) - } - #[rhai_fn(name = "get_bits", return_raw)] - pub fn get_bits_range_inclusive(value: INT, range: InclusiveRange) -> RhaiResultOf { - let from = INT::max(*range.start(), 0); - let to = INT::max(*range.end(), from - 1); - get_bits(value, from, to - from + 1) - } - #[rhai_fn(return_raw)] - pub fn get_bits(value: INT, index: INT, bits: INT) -> RhaiResultOf { - if bits < 1 { - return Ok(0); - } - - let offset = if index >= 0 { - let offset = index as usize; - - if offset >= BITS { - return Err(ERR::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 Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()); - } - BITS - offset - } else { - return Err(ERR::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(name = "set_bits", return_raw)] - pub fn set_bits_range( - value: &mut INT, - range: ExclusiveRange, - new_value: INT, - ) -> RhaiResultOf<()> { - let from = INT::max(range.start, 0); - let to = INT::max(range.end, from); - set_bits(value, from, to - from, new_value) - } - #[rhai_fn(name = "set_bits", return_raw)] - pub fn set_bits_range_inclusive( - value: &mut INT, - range: InclusiveRange, - new_value: INT, - ) -> RhaiResultOf<()> { - let from = INT::max(*range.start(), 0); - let to = INT::max(*range.end(), from - 1); - set_bits(value, from, to - from + 1, new_value) - } - #[rhai_fn(return_raw)] - pub fn set_bits(value: &mut INT, index: INT, bits: INT, new_value: INT) -> RhaiResultOf<()> { - if bits < 1 { - return Ok(()); - } - - let offset = if index >= 0 { - let offset = index as usize; - - if offset >= BITS { - return Err(ERR::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 Err(ERR::ErrorBitFieldBounds(BITS, index, Position::NONE).into()); - } - BITS - offset - } else { - return Err(ERR::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(()) - } -} diff --git a/src/packages/mod.rs b/src/packages/mod.rs index 7f73e774..0b8bc6f3 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -4,6 +4,7 @@ use crate::{Module, Shared}; pub(crate) mod arithmetic; pub(crate) mod array_basic; +mod bit_field; pub(crate) mod blob_basic; mod fn_basic; mod iter_basic; @@ -20,6 +21,7 @@ mod time_basic; pub use arithmetic::ArithmeticPackage; #[cfg(not(feature = "no_index"))] pub use array_basic::BasicArrayPackage; +pub use bit_field::BitFieldPackage; #[cfg(not(feature = "no_index"))] pub use blob_basic::BasicBlobPackage; pub use fn_basic::BasicFnPackage; diff --git a/src/packages/pkg_core.rs b/src/packages/pkg_core.rs index dc106dee..c006b0a1 100644 --- a/src/packages/pkg_core.rs +++ b/src/packages/pkg_core.rs @@ -10,7 +10,6 @@ def_package! { /// /// * [`LanguageCorePackage`][super::LanguageCorePackage] /// * [`ArithmeticPackage`][super::ArithmeticPackage] - /// * [`LogicPackage`][super::LogicPackage] /// * [`BasicStringPackage`][super::BasicStringPackage] /// * [`BasicIteratorPackage`][super::BasicIteratorPackage] /// * [`BasicFnPackage`][super::BasicFnPackage] @@ -19,7 +18,6 @@ def_package! { super::LanguageCorePackage::init(lib); super::ArithmeticPackage::init(lib); - super::LogicPackage::init(lib); super::BasicStringPackage::init(lib); super::BasicIteratorPackage::init(lib); super::BasicFnPackage::init(lib); diff --git a/src/packages/pkg_std.rs b/src/packages/pkg_std.rs index 012aa7d8..b388b379 100644 --- a/src/packages/pkg_std.rs +++ b/src/packages/pkg_std.rs @@ -9,6 +9,8 @@ def_package! { /// # Contents /// /// * [`CorePackage`][super::CorePackage] + /// * [`BitFieldPackage`][super::BitFieldPackage] + /// * [`LogicPackage`][super::LogicPackage] /// * [`BasicMathPackage`][super::BasicMathPackage] /// * [`BasicArrayPackage`][super::BasicArrayPackage] /// * [`BasicBlobPackage`][super::BasicBlobPackage] @@ -19,6 +21,8 @@ def_package! { lib.standard = true; super::CorePackage::init(lib); + super::BitFieldPackage::init(lib); + super::LogicPackage::init(lib); super::BasicMathPackage::init(lib); #[cfg(not(feature = "no_index"))] super::BasicArrayPackage::init(lib);