use std::fmt::Display;
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive;
use vpi_sys::{PLI_INT32, PLI_UINT32};
use crate::{Handle, Property, Time};
#[derive(Debug)]
pub enum Value {
BinStr(String),
OctStr(String),
HexStr(String),
DecStr(String),
Scalar(ScalarValue),
Int(i32),
Real(f64),
String(String),
Vector(Vec<ScalarValue>),
Strength(StrengthValue),
Time(Time),
ObjType(i32),
Suppress,
ShortInt(i16),
LongInt(i64),
ShortReal(f32),
RawTwoState(Vec<bool>), RawFourState(Vec<ScalarValue>), }
impl Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::BinStr(s) | Value::OctStr(s) | Value::HexStr(s) | Value::DecStr(s) => {
write!(f, "{s}")
}
Value::Scalar(scalar) => write!(f, "{scalar}"),
Value::Int(i) => write!(f, "{i}"),
Value::Real(r) => write!(f, "{r}"),
Value::String(s) => write!(f, "\"{s}\""),
Value::Vector(vec) => {
write!(
f,
"{}",
vec.iter().map(|s| format!("{s}")).collect::<String>()
)
}
Value::Strength(strength) => write!(f, "{strength}"),
Value::Time(time) => write!(f, "{time}"),
Value::ObjType(obj_type) => write!(f, "ObjType({obj_type})"), Value::Suppress => write!(f, "Suppress"),
Value::ShortInt(i) => write!(f, "{i}"),
Value::LongInt(i) => write!(f, "{i}"),
Value::ShortReal(r) => write!(f, "{r}"),
Value::RawTwoState(vec) => {
write!(
f,
"{}",
vec.iter()
.map(|b| if *b { '1' } else { '0' })
.collect::<String>()
)
}
Value::RawFourState(vec) => {
write!(
f,
"{}",
vec.iter().map(|s| format!("{s}")).collect::<String>()
)
}
}
}
}
#[repr(u32)]
#[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone)]
pub enum ValueType {
BinStr = vpi_sys::vpiBinStrVal,
OctStr = vpi_sys::vpiOctStrVal,
HexStr = vpi_sys::vpiHexStrVal,
DecStr = vpi_sys::vpiDecStrVal,
Scalar = vpi_sys::vpiScalarVal,
Int = vpi_sys::vpiIntVal,
Real = vpi_sys::vpiRealVal,
String = vpi_sys::vpiStringVal,
Vector = vpi_sys::vpiVectorVal,
Strength = vpi_sys::vpiStrengthVal,
Time = vpi_sys::vpiTimeVal,
ObjType = vpi_sys::vpiObjTypeVal,
Suppress = vpi_sys::vpiSuppressVal,
ShortInt = vpi_sys::vpiShortIntVal,
LongInt = vpi_sys::vpiLongIntVal,
ShortReal = vpi_sys::vpiShortRealVal,
RawTwoState = vpi_sys::vpiRawTwoStateVal,
RawFourState = vpi_sys::vpiRawFourStateVal,
}
impl std::fmt::Display for ValueType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let type_name = match self {
ValueType::BinStr => "Binary String",
ValueType::OctStr => "Octal String",
ValueType::HexStr => "Hexadecimal String",
ValueType::DecStr => "Decimal String",
ValueType::Scalar => "Scalar",
ValueType::Int => "Integer",
ValueType::Real => "Real",
ValueType::String => "String",
ValueType::Vector => "Vector",
ValueType::Strength => "Strength",
ValueType::Time => "Time",
ValueType::ObjType => "Object Type",
ValueType::Suppress => "Suppress",
ValueType::ShortInt => "Short Integer",
ValueType::LongInt => "Long Integer",
ValueType::ShortReal => "Short Real",
ValueType::RawTwoState => "Raw Two-State Vector",
ValueType::RawFourState => "Raw Four-State Vector",
};
write!(f, "{type_name}")
}
}
#[repr(u32)]
#[derive(FromPrimitive, ToPrimitive, Copy, Clone, Debug, PartialEq)]
pub enum ScalarValue {
Zero = vpi_sys::vpi0,
One = vpi_sys::vpi1,
Z = vpi_sys::vpiZ,
X = vpi_sys::vpiX,
H = vpi_sys::vpiH,
L = vpi_sys::vpiL,
DontCare = vpi_sys::vpiDontCare,
NoChange = vpi_sys::vpiNoChange,
}
impl Display for ScalarValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", char::from(*self))
}
}
impl From<ScalarValue> for char {
fn from(value: ScalarValue) -> Self {
match value {
ScalarValue::Zero => '0',
ScalarValue::One => '1',
ScalarValue::X => 'X',
ScalarValue::Z => 'Z',
ScalarValue::H => 'H',
ScalarValue::L => 'L',
ScalarValue::DontCare => '-',
ScalarValue::NoChange => 'N',
}
}
}
#[derive(Debug)]
pub struct StrengthValue {
logic: ScalarValue,
strength0: StrengthEncoding,
strength1: StrengthEncoding,
}
impl Display for StrengthValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} ({}, {})", self.logic, self.strength0, self.strength1)
}
}
impl From<vpi_sys::t_vpi_strengthval> for StrengthValue {
fn from(strength: vpi_sys::t_vpi_strengthval) -> Self {
let logic = ScalarValue::from_u32(strength.logic as u32).unwrap_or(ScalarValue::DontCare);
let strength0 = StrengthEncoding::from_bits_truncate(strength.s0 as u32);
let strength1 = StrengthEncoding::from_bits_truncate(strength.s1 as u32);
Self {
logic,
strength0,
strength1,
}
}
}
bitflags::bitflags! {
#[derive(Debug)]
pub struct StrengthEncoding: u32 {
const SupplyDrive = vpi_sys::vpiSupplyDrive;
const StrongDrive = vpi_sys::vpiStrongDrive;
const PullDrive = vpi_sys::vpiPullDrive;
const LargeCharge = vpi_sys::vpiLargeCharge;
const WeakDrive = vpi_sys::vpiWeakDrive;
const MediumCharge = vpi_sys::vpiMediumCharge;
const SmallCharge = vpi_sys::vpiSmallCharge;
const HiZ = vpi_sys::vpiHiZ;
}
}
impl Display for StrengthEncoding {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut strengths = Vec::new();
if self.contains(StrengthEncoding::SupplyDrive) {
strengths.push("SupplyDrive");
}
if self.contains(StrengthEncoding::StrongDrive) {
strengths.push("StrongDrive");
}
if self.contains(StrengthEncoding::PullDrive) {
strengths.push("PullDrive");
}
if self.contains(StrengthEncoding::LargeCharge) {
strengths.push("LargeCharge");
}
if self.contains(StrengthEncoding::WeakDrive) {
strengths.push("WeakDrive");
}
if self.contains(StrengthEncoding::MediumCharge) {
strengths.push("MediumCharge");
}
if self.contains(StrengthEncoding::SmallCharge) {
strengths.push("SmallCharge");
}
if self.contains(StrengthEncoding::HiZ) {
strengths.push("HiZ");
}
write!(f, "{}", strengths.join(" | "))
}
}
bitflags::bitflags! {
pub struct PutValueFlags: u32 {
const ReturnEvent = vpi_sys::vpiReturnEvent;
const UserAllocFlag = vpi_sys::vpiUserAllocFlag;
const OneValue = vpi_sys::vpiOneValue;
const PropagateOff = vpi_sys::vpiPropagateOff;
}
}
#[must_use]
pub fn vector_value_to_scalar_vector(
vec: &[vpi_sys::t_vpi_vecval],
size: usize,
) -> Vec<ScalarValue> {
let mut result = Vec::with_capacity(size);
for bit_index in 0..size {
let word_index = bit_index / 32;
let bit_position = bit_index % 32;
if word_index >= vec.len() {
result.push(ScalarValue::Zero);
continue;
}
let vecval = &vec[word_index];
let a_bit = (vecval.aval >> bit_position) & 1;
let b_bit = (vecval.bval >> bit_position) & 1;
let encoded = (a_bit << 1) | b_bit;
let scalar = match encoded {
0 => ScalarValue::Zero,
1 => ScalarValue::Z,
2 => ScalarValue::One,
3 => ScalarValue::X,
_ => ScalarValue::DontCare, };
result.push(scalar);
}
result.reverse(); result
}
#[must_use]
pub(crate) fn decode_vpi_value(
raw_value: vpi_sys::t_vpi_value,
obj: vpi_sys::vpiHandle,
) -> Option<Value> {
match raw_value.format as u32 {
vpi_sys::vpiBinStrVal => {
let c_str = unsafe { std::ffi::CStr::from_ptr(raw_value.value.str_) };
Some(Value::BinStr(c_str.to_str().unwrap_or("").to_string()))
}
vpi_sys::vpiOctStrVal => {
let c_str = unsafe { std::ffi::CStr::from_ptr(raw_value.value.str_) };
Some(Value::OctStr(c_str.to_str().unwrap_or("").to_string()))
}
vpi_sys::vpiHexStrVal => {
let c_str = unsafe { std::ffi::CStr::from_ptr(raw_value.value.str_) };
Some(Value::HexStr(c_str.to_str().unwrap_or("").to_string()))
}
vpi_sys::vpiDecStrVal => {
let c_str = unsafe { std::ffi::CStr::from_ptr(raw_value.value.str_) };
Some(Value::DecStr(c_str.to_str().unwrap_or("").to_string()))
}
vpi_sys::vpiScalarVal => Some(Value::Scalar(
ScalarValue::from_u32(unsafe { raw_value.value.integer } as u32)
.unwrap_or(ScalarValue::DontCare),
)),
vpi_sys::vpiIntVal => Some(Value::Int(unsafe { raw_value.value.integer })),
vpi_sys::vpiRealVal => Some(Value::Real(unsafe { raw_value.value.real })),
vpi_sys::vpiStringVal => {
let c_str = unsafe { std::ffi::CStr::from_ptr(raw_value.value.str_) };
Some(Value::String(c_str.to_str().unwrap_or("").to_string()))
}
vpi_sys::vpiObjTypeVal => Some(Value::ObjType(unsafe { raw_value.value.integer })),
vpi_sys::vpiVectorVal => {
let vec_ptr = unsafe { raw_value.value.vector };
if vec_ptr.is_null() {
Some(Value::Vector(vec![]))
} else {
let size = if obj.is_null() {
0usize
} else {
unsafe { vpi_sys::vpi_get(vpi_sys::vpiSize as i32, obj) as usize }
};
let num_words = size.div_ceil(32);
let vec = unsafe { std::slice::from_raw_parts(vec_ptr, num_words) };
Some(Value::Vector(vector_value_to_scalar_vector(vec, size)))
}
}
vpi_sys::vpiStrengthVal => {
let strength: vpi_sys::t_vpi_strengthval = unsafe { *raw_value.value.strength };
Some(Value::Strength(StrengthValue::from(strength)))
}
vpi_sys::vpiTimeVal => {
let vpi_time: vpi_sys::t_vpi_time = unsafe { *raw_value.value.time };
Some(Value::Time(Time::from(vpi_time)))
}
vpi_sys::vpiShortIntVal => Some(Value::ShortInt(unsafe { raw_value.value.integer } as i16)),
_ => None,
}
}
#[cfg(feature = "bigint")]
#[must_use]
pub fn scalar_vector_to_biguint(bits: &[ScalarValue]) -> Option<num_bigint::BigUint> {
let mut result = num_bigint::BigUint::ZERO;
for bit in bits {
result <<= 1u32;
match bit {
ScalarValue::Zero => {}
ScalarValue::One => result |= num_bigint::BigUint::from(1u32),
_ => return None,
}
}
Some(result)
}
#[must_use]
pub fn uint64_to_scalar_vector(value: u64, bits: usize) -> Vec<ScalarValue> {
(0..bits)
.rev()
.map(|i| {
if (value >> i) & 1 == 1 {
ScalarValue::One
} else {
ScalarValue::Zero
}
})
.collect()
}
#[must_use]
pub fn scalar_vector_to_uint64(bits: &[ScalarValue]) -> Option<u64> {
if bits.len() > 64 {
return None;
}
let mut result: u64 = 0;
for bit in bits {
result <<= 1;
match bit {
ScalarValue::Zero => {}
ScalarValue::One => result |= 1,
_ => return None,
}
}
Some(result)
}
#[cfg(feature = "bigint")]
#[must_use]
pub fn biguint_to_scalar_vector(value: &num_bigint::BigUint, bits: usize) -> Vec<ScalarValue> {
(0..bits)
.rev()
.map(|i| {
if value.bit(i as u64) {
ScalarValue::One
} else {
ScalarValue::Zero
}
})
.collect()
}
#[must_use]
pub fn int64_to_scalar_vector(value: i64, bits: usize) -> Vec<ScalarValue> {
uint64_to_scalar_vector(value as u64, bits)
}
#[must_use]
pub fn scalar_vector_to_int64(bits: &[ScalarValue]) -> Option<i64> {
if bits.is_empty() || bits.len() > 64 {
return None;
}
let unsigned = scalar_vector_to_uint64(bits)?;
let shift = 64 - bits.len();
Some((unsigned << shift) as i64 >> shift)
}
#[cfg(feature = "bigint")]
#[must_use]
pub fn bigint_to_scalar_vector(value: &num_bigint::BigInt, bits: usize) -> Vec<ScalarValue> {
use num_bigint::Sign;
let unsigned: num_bigint::BigUint = if value.sign() == Sign::Minus {
let modulus = num_bigint::BigUint::from(1u32) << bits;
let mag = value.magnitude();
modulus - mag
} else {
value.magnitude().clone()
};
biguint_to_scalar_vector(&unsigned, bits)
}
#[cfg(feature = "bigint")]
#[must_use]
pub fn scalar_vector_to_bigint(bits: &[ScalarValue]) -> Option<num_bigint::BigInt> {
if bits.is_empty() {
return None;
}
let unsigned = scalar_vector_to_biguint(bits)?;
if bits[0] == ScalarValue::One {
let modulus = num_bigint::BigUint::from(1u32) << bits.len();
Some(num_bigint::BigInt::from(unsigned) - num_bigint::BigInt::from(modulus))
} else {
Some(num_bigint::BigInt::from(unsigned))
}
}
impl Handle {
#[must_use]
pub fn get_value(&self, format: ValueType) -> Option<Value> {
if self.is_null() {
return None;
}
let mut value = vpi_sys::t_vpi_value {
format: format as i32,
value: vpi_sys::t_vpi_value__bindgen_ty_1 { integer: 0 },
};
unsafe { vpi_sys::vpi_get_value(self.as_raw(), &raw mut value) };
decode_vpi_value(value, self.as_raw())
}
#[must_use]
pub fn get_value_array(&self, format: ValueType) -> Option<Vec<Value>> {
if self.is_null() {
return None;
}
let size =
unsafe { vpi_sys::vpi_get(vpi_sys::vpiSize as PLI_INT32, self.as_raw()) } as usize;
if size == 0 {
return Some(Vec::new());
}
match format {
ValueType::Int => {
let mut integers: Vec<i32> = vec![0; size];
let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
format: vpi_sys::vpiIntVal,
flags: 0,
value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
integers: integers.as_mut_ptr(),
},
};
let mut index = 0;
unsafe {
vpi_sys::vpi_get_value_array(
self.as_raw(),
&raw mut arrayvalue,
&raw mut index,
size as PLI_UINT32,
);
}
Some(integers.into_iter().map(Value::Int).collect::<Vec<Value>>())
}
ValueType::Real => {
let mut reals: Vec<f64> = vec![0.0; size];
let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
format: vpi_sys::vpiRealVal,
flags: 0,
value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
reals: reals.as_mut_ptr(),
},
};
let mut index = 0;
unsafe {
vpi_sys::vpi_get_value_array(
self.as_raw(),
&raw mut arrayvalue,
&raw mut index,
size as PLI_UINT32,
);
}
Some(reals.into_iter().map(Value::Real).collect::<Vec<Value>>())
}
ValueType::Time => {
let mut times: Vec<vpi_sys::t_vpi_time> = vec![
vpi_sys::t_vpi_time {
type_: 0,
high: 0,
low: 0,
real: 0.0,
};
size
];
let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
format: vpi_sys::vpiTimeVal,
flags: 0,
value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
times: times.as_mut_ptr(),
},
};
let mut index = 0;
unsafe {
vpi_sys::vpi_get_value_array(
self.as_raw(),
&raw mut arrayvalue,
&raw mut index,
size as PLI_UINT32,
);
}
Some(
times
.into_iter()
.map(|t| {
let vpi_time = vpi_sys::s_vpi_time {
type_: t.type_,
high: t.high,
low: t.low,
real: t.real,
};
Value::Time(Time::from(vpi_time))
})
.collect::<Vec<Value>>(),
)
}
ValueType::ShortInt => {
let mut shortints: Vec<i16> = vec![0; size];
let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
format: vpi_sys::vpiShortIntVal,
flags: 0,
value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
shortints: shortints.as_mut_ptr(),
},
};
let mut index = 0;
unsafe {
vpi_sys::vpi_get_value_array(
self.as_raw(),
&raw mut arrayvalue,
&raw mut index,
size as PLI_UINT32,
);
}
Some(
shortints
.into_iter()
.map(Value::ShortInt)
.collect::<Vec<Value>>(),
)
}
ValueType::LongInt => {
let mut longints: Vec<i64> = vec![0; size];
let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
format: vpi_sys::vpiLongIntVal,
flags: 0,
value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
longints: longints.as_mut_ptr(),
},
};
let mut index = 0;
unsafe {
vpi_sys::vpi_get_value_array(
self.as_raw(),
&raw mut arrayvalue,
&raw mut index,
size as PLI_UINT32,
);
}
Some(
longints
.into_iter()
.map(Value::LongInt)
.collect::<Vec<Value>>(),
)
}
ValueType::ShortReal => {
let mut shortreals: Vec<f32> = vec![0.0; size];
let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
format: vpi_sys::vpiShortRealVal,
flags: 0,
value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
shortreals: shortreals.as_mut_ptr(),
},
};
let mut index = 0;
unsafe {
vpi_sys::vpi_get_value_array(
self.as_raw(),
&raw mut arrayvalue,
&raw mut index,
size as PLI_UINT32,
);
}
Some(
shortreals
.into_iter()
.map(Value::ShortReal)
.collect::<Vec<Value>>(),
)
}
ValueType::Vector => {
let mut values = Vec::with_capacity(size);
for _ in 0..size {
if let Some(val) = self.get_value(ValueType::Vector) {
values.push(val);
}
}
Some(values)
}
ValueType::Scalar => {
let mut rawvals: Vec<vpi_sys::PLI_BYTE8> = vec![0; size];
let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
format: vpi_sys::vpiScalarVal,
flags: 0,
value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
rawvals: rawvals.as_mut_ptr(),
},
};
let mut index = 0;
unsafe {
vpi_sys::vpi_get_value_array(
self.as_raw(),
&raw mut arrayvalue,
&raw mut index,
size as PLI_UINT32,
);
}
Some(
rawvals
.into_iter()
.filter_map(|v| ScalarValue::from_u32(v as u32).map(Value::Scalar))
.collect::<Vec<Value>>(),
)
}
_ => {
Some(Vec::new())
}
}
}
#[must_use]
pub fn is_array(&self) -> bool {
if self.is_null() {
return false;
}
self.get_bool(Property::Array) == Some(true)
}
}
#[cfg(test)]
mod tests {
use super::{
int64_to_scalar_vector, scalar_vector_to_int64, scalar_vector_to_uint64,
uint64_to_scalar_vector, vector_value_to_scalar_vector, ScalarValue, StrengthEncoding,
Value, ValueType,
};
fn scalar_vec_to_string(values: Vec<ScalarValue>) -> String {
values.into_iter().map(|value| value.to_string()).collect()
}
#[test]
fn vector_value_decodes_ab_encoding_and_reverses_bit_order() {
let vec = [vpi_sys::t_vpi_vecval {
aval: 0b1010,
bval: 0b1100,
}];
let decoded = vector_value_to_scalar_vector(&vec, 4);
assert_eq!(scalar_vec_to_string(decoded), "XZ10");
}
#[test]
fn vector_value_uses_zero_when_words_are_missing() {
let decoded = vector_value_to_scalar_vector(&[], 3);
assert_eq!(scalar_vec_to_string(decoded), "000");
}
#[test]
fn raw_two_state_display_renders_binary_string() {
let value = Value::RawTwoState(vec![true, false, true, true, false]);
assert_eq!(value.to_string(), "10110");
}
#[test]
fn raw_four_state_display_renders_scalar_symbols() {
let value = Value::RawFourState(vec![
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::X,
ScalarValue::Z,
ScalarValue::DontCare,
ScalarValue::NoChange,
]);
assert_eq!(value.to_string(), "01XZ-N");
}
#[test]
fn strength_encoding_display_joins_active_flags_in_order() {
let strength = StrengthEncoding::StrongDrive | StrengthEncoding::HiZ;
assert_eq!(strength.to_string(), "StrongDrive | HiZ");
}
#[test]
fn value_type_display_has_human_readable_labels() {
assert_eq!(ValueType::RawFourState.to_string(), "Raw Four-State Vector");
assert_eq!(ValueType::ShortInt.to_string(), "Short Integer");
}
#[test]
fn scalar_vector_to_uint64_converts_binary_bits() {
let bits = vec![
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::One,
];
assert_eq!(scalar_vector_to_uint64(&bits), Some(0b1011));
}
#[test]
fn scalar_vector_to_uint64_all_zeros() {
let bits = vec![ScalarValue::Zero; 8];
assert_eq!(scalar_vector_to_uint64(&bits), Some(0));
}
#[test]
fn scalar_vector_to_uint64_returns_none_for_x_bit() {
let bits = vec![ScalarValue::One, ScalarValue::X, ScalarValue::Zero];
assert_eq!(scalar_vector_to_uint64(&bits), None);
}
#[test]
fn scalar_vector_to_uint64_returns_none_for_z_bit() {
let bits = vec![ScalarValue::Zero, ScalarValue::Z];
assert_eq!(scalar_vector_to_uint64(&bits), None);
}
#[test]
fn scalar_vector_to_uint64_returns_none_for_over_64_bits() {
let bits = vec![ScalarValue::Zero; 65];
assert_eq!(scalar_vector_to_uint64(&bits), None);
}
#[test]
fn scalar_vector_to_uint64_accepts_exactly_64_bits() {
let mut bits = vec![ScalarValue::Zero; 63];
bits.push(ScalarValue::One);
assert_eq!(scalar_vector_to_uint64(&bits), Some(1));
}
#[test]
fn uint64_to_scalar_vector_converts_value() {
assert_eq!(
uint64_to_scalar_vector(0b1011, 4),
vec![
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::One
]
);
}
#[test]
fn uint64_to_scalar_vector_pads_with_zeros() {
assert_eq!(
uint64_to_scalar_vector(0b101, 6),
vec![
ScalarValue::Zero,
ScalarValue::Zero,
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One,
]
);
}
#[test]
fn uint64_to_scalar_vector_truncates_high_bits() {
assert_eq!(
uint64_to_scalar_vector(0b11011, 4),
vec![
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::One
]
);
}
#[test]
fn uint64_to_scalar_vector_zero_bits_returns_empty() {
assert_eq!(uint64_to_scalar_vector(42, 0), vec![]);
}
#[test]
fn int64_to_scalar_vector_positive_value() {
assert_eq!(
int64_to_scalar_vector(5, 4),
vec![
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One
]
);
}
#[test]
fn int64_to_scalar_vector_negative_value() {
assert_eq!(
int64_to_scalar_vector(-1, 4),
vec![
ScalarValue::One,
ScalarValue::One,
ScalarValue::One,
ScalarValue::One
]
);
}
#[test]
fn int64_to_scalar_vector_min_negative() {
assert_eq!(
int64_to_scalar_vector(-8, 4),
vec![
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::Zero,
ScalarValue::Zero
]
);
}
#[test]
fn scalar_vector_to_int64_positive() {
let bits = vec![
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One,
];
assert_eq!(scalar_vector_to_int64(&bits), Some(5));
}
#[test]
fn scalar_vector_to_int64_negative() {
let bits = vec![
ScalarValue::One,
ScalarValue::One,
ScalarValue::One,
ScalarValue::One,
];
assert_eq!(scalar_vector_to_int64(&bits), Some(-1));
}
#[test]
fn scalar_vector_to_int64_min_negative() {
let bits = vec![
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::Zero,
ScalarValue::Zero,
];
assert_eq!(scalar_vector_to_int64(&bits), Some(-8));
}
#[test]
fn scalar_vector_to_int64_returns_none_for_empty() {
assert_eq!(scalar_vector_to_int64(&[]), None);
}
#[test]
fn scalar_vector_to_int64_returns_none_for_over_64_bits() {
let bits = vec![ScalarValue::Zero; 65];
assert_eq!(scalar_vector_to_int64(&bits), None);
}
#[test]
fn scalar_vector_to_int64_returns_none_for_x_bit() {
let bits = vec![ScalarValue::One, ScalarValue::X];
assert_eq!(scalar_vector_to_int64(&bits), None);
}
#[cfg(feature = "bigint")]
mod bigint_tests {
use num_bigint::{BigInt, BigUint};
use super::super::{
bigint_to_scalar_vector, biguint_to_scalar_vector, scalar_vector_to_bigint,
scalar_vector_to_biguint, ScalarValue,
};
#[test]
fn scalar_vector_to_biguint_converts_binary_bits() {
let bits = vec![
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::One,
];
assert_eq!(
scalar_vector_to_biguint(&bits),
Some(BigUint::from(0b1011u32))
);
}
#[test]
fn scalar_vector_to_biguint_all_zeros() {
let bits = vec![ScalarValue::Zero; 8];
assert_eq!(scalar_vector_to_biguint(&bits), Some(BigUint::ZERO));
}
#[test]
fn scalar_vector_to_biguint_empty_slice() {
assert_eq!(scalar_vector_to_biguint(&[]), Some(BigUint::ZERO));
}
#[test]
fn scalar_vector_to_biguint_returns_none_for_x_bit() {
let bits = vec![ScalarValue::One, ScalarValue::X, ScalarValue::Zero];
assert_eq!(scalar_vector_to_biguint(&bits), None);
}
#[test]
fn scalar_vector_to_biguint_returns_none_for_z_bit() {
let bits = vec![ScalarValue::Zero, ScalarValue::Z];
assert_eq!(scalar_vector_to_biguint(&bits), None);
}
#[test]
fn scalar_vector_to_biguint_exceeds_64_bits() {
let mut bits = vec![ScalarValue::Zero; 64];
bits.push(ScalarValue::One);
assert_eq!(scalar_vector_to_biguint(&bits), Some(BigUint::from(1u32)));
}
#[test]
fn biguint_to_scalar_vector_converts_value() {
assert_eq!(
biguint_to_scalar_vector(&BigUint::from(0b1011u32), 4),
vec![
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::One
]
);
}
#[test]
fn biguint_to_scalar_vector_pads_with_zeros() {
assert_eq!(
biguint_to_scalar_vector(&BigUint::from(0b101u32), 6),
vec![
ScalarValue::Zero,
ScalarValue::Zero,
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One,
]
);
}
#[test]
fn biguint_to_scalar_vector_truncates_high_bits() {
assert_eq!(
biguint_to_scalar_vector(&BigUint::from(0b11011u32), 4),
vec![
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::One
]
);
}
#[test]
fn biguint_to_scalar_vector_zero_bits_returns_empty() {
assert_eq!(biguint_to_scalar_vector(&BigUint::from(42u32), 0), vec![]);
}
#[test]
fn biguint_to_scalar_vector_exceeds_64_bits() {
let value = BigUint::from(1u32) << 64u32;
let mut expected = vec![ScalarValue::One];
expected.extend(vec![ScalarValue::Zero; 64]);
assert_eq!(biguint_to_scalar_vector(&value, 65), expected);
}
#[test]
fn bigint_to_scalar_vector_positive_value() {
assert_eq!(
bigint_to_scalar_vector(&BigInt::from(5), 4),
vec![
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One
]
);
}
#[test]
fn bigint_to_scalar_vector_negative_one() {
assert_eq!(
bigint_to_scalar_vector(&BigInt::from(-1), 4),
vec![
ScalarValue::One,
ScalarValue::One,
ScalarValue::One,
ScalarValue::One
]
);
}
#[test]
fn bigint_to_scalar_vector_large_negative() {
let expected = vec![ScalarValue::One; 65];
assert_eq!(bigint_to_scalar_vector(&BigInt::from(-1), 65), expected);
}
#[test]
fn scalar_vector_to_bigint_positive() {
let bits = vec![
ScalarValue::Zero,
ScalarValue::One,
ScalarValue::Zero,
ScalarValue::One,
];
assert_eq!(scalar_vector_to_bigint(&bits), Some(BigInt::from(5)));
}
#[test]
fn scalar_vector_to_bigint_negative_one() {
let bits = vec![
ScalarValue::One,
ScalarValue::One,
ScalarValue::One,
ScalarValue::One,
];
assert_eq!(scalar_vector_to_bigint(&bits), Some(BigInt::from(-1)));
}
#[test]
fn scalar_vector_to_bigint_large_negative() {
let bits = vec![ScalarValue::One; 65];
assert_eq!(scalar_vector_to_bigint(&bits), Some(BigInt::from(-1)));
}
#[test]
fn scalar_vector_to_bigint_returns_none_for_empty() {
assert_eq!(scalar_vector_to_bigint(&[]), None);
}
#[test]
fn scalar_vector_to_bigint_returns_none_for_x_bit() {
let bits = vec![ScalarValue::One, ScalarValue::X];
assert_eq!(scalar_vector_to_bigint(&bits), None);
}
}
}