use crate::{Dynamic, Position, RhaiResultOf};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
borrow::Borrow,
ops::{Deref, DerefMut},
};
#[cfg(not(feature = "no_index"))]
#[inline]
#[allow(
clippy::cast_sign_loss,
clippy::absurd_extreme_comparisons,
clippy::cast_possible_truncation
)]
pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (usize, usize) {
let start = if start < 0 {
let abs_start = start.unsigned_abs();
if abs_start as u64 > crate::MAX_USIZE_INT as u64 {
0
} else {
length - usize::min(abs_start as usize, length)
}
} else if start > crate::MAX_USIZE_INT || start as usize >= length {
return (length, 0);
} else {
start as usize
};
let len = if len <= 0 {
0
} else if len > crate::MAX_USIZE_INT || len as usize > length - start {
length - start
} else {
len as usize
};
(start, len)
}
#[inline]
#[allow(dead_code)]
#[allow(
clippy::cast_sign_loss,
clippy::cast_possible_truncation,
clippy::absurd_extreme_comparisons
)]
pub fn calc_index<E>(
length: usize,
start: crate::INT,
negative_count_from_end: bool,
err_func: impl FnOnce() -> Result<usize, E>,
) -> Result<usize, E> {
if start < 0 && negative_count_from_end {
let abs_start = start.unsigned_abs();
return Ok(if abs_start as u64 > crate::MAX_USIZE_INT as u64 {
0
} else {
length - usize::min(abs_start as usize, length)
});
}
if start <= crate::MAX_USIZE_INT && (start as usize) < length {
return Ok(start as usize);
}
err_func()
}
#[derive(Debug)]
#[must_use]
pub enum Target<'a> {
RefMut(&'a mut Dynamic),
#[cfg(not(feature = "no_closure"))]
SharedValue {
guard: crate::types::dynamic::DynamicWriteLock<'a, Dynamic>,
shared_value: Dynamic,
},
TempValue(Dynamic),
#[cfg(not(feature = "no_index"))]
Bit {
source: &'a mut Dynamic,
value: Dynamic,
bit: u8,
},
#[cfg(not(feature = "no_index"))]
BitField {
source: &'a mut Dynamic,
value: Dynamic,
mask: crate::INT,
shift: u8,
},
#[cfg(not(feature = "no_index"))]
BlobByte {
source: &'a mut Dynamic,
value: Dynamic,
index: usize,
},
#[cfg(not(feature = "no_index"))]
StringChar {
source: &'a mut Dynamic,
value: Dynamic,
index: usize,
},
}
impl<'a> Target<'a> {
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn is_ref(&self) -> bool {
match self {
Self::RefMut(..) => true,
#[cfg(not(feature = "no_closure"))]
Self::SharedValue { .. } => true,
Self::TempValue(..) => false,
#[cfg(not(feature = "no_index"))]
Self::Bit { .. }
| Self::BitField { .. }
| Self::BlobByte { .. }
| Self::StringChar { .. } => false,
}
}
#[inline]
#[must_use]
pub const fn is_temp_value(&self) -> bool {
match self {
Self::RefMut(..) => false,
#[cfg(not(feature = "no_closure"))]
Self::SharedValue { .. } => false,
Self::TempValue(..) => true,
#[cfg(not(feature = "no_index"))]
Self::Bit { .. }
| Self::BitField { .. }
| Self::BlobByte { .. }
| Self::StringChar { .. } => false,
}
}
#[inline]
#[must_use]
pub fn is_shared(&self) -> bool {
#[cfg(not(feature = "no_closure"))]
return match self {
Self::RefMut(r) => r.is_shared(),
Self::SharedValue { .. } => true,
Self::TempValue(value) => value.is_shared(),
#[cfg(not(feature = "no_index"))]
Self::Bit { .. }
| Self::BitField { .. }
| Self::BlobByte { .. }
| Self::StringChar { .. } => false,
};
#[cfg(feature = "no_closure")]
return false;
}
#[inline]
pub fn take_or_clone(self) -> Dynamic {
match self {
Self::RefMut(r) => r.clone(), #[cfg(not(feature = "no_closure"))]
Self::SharedValue { shared_value, .. } => shared_value, Self::TempValue(value) => value, #[cfg(not(feature = "no_index"))]
Self::Bit { value, .. } => value, #[cfg(not(feature = "no_index"))]
Self::BitField { value, .. } => value, #[cfg(not(feature = "no_index"))]
Self::BlobByte { value, .. } => value, #[cfg(not(feature = "no_index"))]
Self::StringChar { value, .. } => value, }
}
#[inline(always)]
#[must_use]
pub fn take_ref(self) -> Option<&'a mut Dynamic> {
match self {
Self::RefMut(r) => Some(r),
_ => None,
}
}
#[inline(always)]
pub fn into_owned(self) -> Self {
match self {
Self::RefMut(r) => Self::TempValue(r.clone()),
#[cfg(not(feature = "no_closure"))]
Self::SharedValue { shared_value, .. } => Self::TempValue(shared_value),
_ => self,
}
}
#[allow(dead_code)]
#[inline]
pub fn source(&self) -> &Dynamic {
match self {
Self::RefMut(r) => r,
#[cfg(not(feature = "no_closure"))]
Self::SharedValue { guard, .. } => guard,
Self::TempValue(value) => value,
#[cfg(not(feature = "no_index"))]
Self::Bit { source, .. } => source,
#[cfg(not(feature = "no_index"))]
Self::BitField { source, .. } => source,
#[cfg(not(feature = "no_index"))]
Self::BlobByte { source, .. } => source,
#[cfg(not(feature = "no_index"))]
Self::StringChar { source, .. } => source,
}
}
#[inline]
pub fn propagate_changed_value(&mut self, _pos: Position) -> RhaiResultOf<()> {
match self {
Self::RefMut(..) | Self::TempValue(..) => (),
#[cfg(not(feature = "no_closure"))]
Self::SharedValue { .. } => (),
#[cfg(not(feature = "no_index"))]
Self::Bit { source, value, bit } => {
let new_bit = value.as_bool().map_err(|err| {
Box::new(crate::ERR::ErrorMismatchDataType(
"bool".to_string(),
err.to_string(),
_pos,
))
})?;
let value = &mut *source.write_lock::<crate::INT>().expect("`INT`");
let index = *bit;
let mask = 1 << index;
if new_bit {
*value |= mask;
} else {
*value &= !mask;
}
}
#[cfg(not(feature = "no_index"))]
Self::BitField {
source,
value,
mask,
shift,
} => {
let shift = *shift;
let mask = *mask;
let new_value = value.as_int().map_err(|err| {
Box::new(crate::ERR::ErrorMismatchDataType(
"integer".to_string(),
err.to_string(),
_pos,
))
})?;
let new_value = (new_value << shift) & mask;
let value = &mut *source.write_lock::<crate::INT>().expect("`INT`");
*value &= !mask;
*value |= new_value;
}
#[cfg(not(feature = "no_index"))]
Self::BlobByte {
source,
value,
index,
} => {
let new_byte = value.as_int().map_err(|err| {
Box::new(crate::ERR::ErrorMismatchDataType(
"INT".to_string(),
err.to_string(),
_pos,
))
})?;
let value = &mut *source.write_lock::<crate::Blob>().expect("`Blob`");
#[allow(clippy::cast_sign_loss)]
{
value[*index] = (new_byte & 0x00ff) as u8;
}
}
#[cfg(not(feature = "no_index"))]
Self::StringChar {
source,
value,
index,
} => {
let new_ch = value.as_char().map_err(|err| {
Box::new(crate::ERR::ErrorMismatchDataType(
"char".to_string(),
err.to_string(),
_pos,
))
})?;
let s = &mut *source
.write_lock::<crate::ImmutableString>()
.expect("`ImmutableString`");
*s = s
.chars()
.enumerate()
.map(|(i, ch)| if i == *index { new_ch } else { ch })
.collect();
}
}
Ok(())
}
}
impl<'a> From<&'a mut Dynamic> for Target<'a> {
#[inline]
fn from(value: &'a mut Dynamic) -> Self {
#[cfg(not(feature = "no_closure"))]
if value.is_shared() {
let shared_value = value.clone();
let guard = value.write_lock::<Dynamic>().expect("`Dynamic`");
return Self::SharedValue {
guard,
shared_value,
};
}
Self::RefMut(value)
}
}
impl Deref for Target<'_> {
type Target = Dynamic;
#[inline]
fn deref(&self) -> &Dynamic {
match self {
Self::RefMut(r) => r,
#[cfg(not(feature = "no_closure"))]
Self::SharedValue { guard, .. } => guard,
Self::TempValue(ref value) => value,
#[cfg(not(feature = "no_index"))]
Self::Bit { ref value, .. }
| Self::BitField { ref value, .. }
| Self::BlobByte { ref value, .. }
| Self::StringChar { ref value, .. } => value,
}
}
}
impl AsRef<Dynamic> for Target<'_> {
#[inline(always)]
fn as_ref(&self) -> &Dynamic {
self
}
}
impl Borrow<Dynamic> for Target<'_> {
#[inline(always)]
fn borrow(&self) -> &Dynamic {
self
}
}
impl DerefMut for Target<'_> {
#[inline]
fn deref_mut(&mut self) -> &mut Dynamic {
match self {
Self::RefMut(r) => r,
#[cfg(not(feature = "no_closure"))]
Self::SharedValue { guard, .. } => &mut *guard,
Self::TempValue(ref mut value) => value,
#[cfg(not(feature = "no_index"))]
Self::Bit { ref mut value, .. }
| Self::BitField { ref mut value, .. }
| Self::BlobByte { ref mut value, .. }
| Self::StringChar { ref mut value, .. } => value,
}
}
}
impl AsMut<Dynamic> for Target<'_> {
#[inline(always)]
fn as_mut(&mut self) -> &mut Dynamic {
self
}
}
impl<T: Into<Dynamic>> From<T> for Target<'_> {
#[inline(always)]
fn from(value: T) -> Self {
Self::TempValue(value.into())
}
}