1use std::ffi::CString;
2use std::fmt::Display;
3
4use num_derive::{FromPrimitive, ToPrimitive};
5use num_traits::FromPrimitive;
6use vpi_sys::PLI_INT32;
7
8#[cfg(feature = "verilator")]
9use crate::scalar_vector_to_vecval;
10
11use crate::{Handle, LogicVal, LogicVec, Property, Time};
12
13#[derive(Debug, Clone, PartialEq)]
15pub enum Value {
16 BinStr(String),
18 OctStr(String),
20 HexStr(String),
22 DecStr(String),
24 Scalar(LogicVal),
26 Int(i32),
28 Real(f64),
30 String(String),
32 Vector(LogicVec),
34 Strength(StrengthValue),
36 Time(Time),
38 ObjType(i32),
46 Suppress,
48 ShortInt(i16),
50 LongInt(i64),
52 ShortReal(f32),
54 #[cfg(feature = "verilator")]
56 RawTwoState(Vec<bool>), #[cfg(feature = "verilator")]
59 RawFourState(LogicVec), }
61
62impl Display for Value {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 match self {
65 Value::BinStr(s) | Value::OctStr(s) | Value::HexStr(s) | Value::DecStr(s) => {
66 write!(f, "{s}")
67 }
68 Value::Scalar(scalar) => write!(f, "{scalar}"),
69 Value::Int(i) => write!(f, "{i}"),
70 Value::Real(r) => write!(f, "{r}"),
71 Value::String(s) => write!(f, "\"{s}\""),
72 Value::Vector(vec) => write!(f, "{vec}"),
73 Value::Strength(strength) => write!(f, "{strength}"),
74 Value::Time(time) => write!(f, "{time}"),
75 Value::ObjType(obj_type) => write!(f, "ObjType({obj_type})"), Value::Suppress => write!(f, "Suppress"),
77 Value::ShortInt(i) => write!(f, "{i}"),
78 Value::LongInt(i) => write!(f, "{i}"),
79 Value::ShortReal(r) => write!(f, "{r}"),
80 #[cfg(feature = "verilator")]
81 Value::RawTwoState(vec) => {
82 write!(
83 f,
84 "{}",
85 vec.iter()
86 .map(|b| if *b { '1' } else { '0' })
87 .collect::<String>()
88 )
89 }
90 #[cfg(feature = "verilator")]
91 Value::RawFourState(vec) => write!(f, "{vec}"),
92 }
93 }
94}
95
96#[repr(u32)]
97#[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone, PartialEq, Eq)]
98pub enum ValueType {
100 BinStr = vpi_sys::vpiBinStrVal,
102 OctStr = vpi_sys::vpiOctStrVal,
104 HexStr = vpi_sys::vpiHexStrVal,
106 DecStr = vpi_sys::vpiDecStrVal,
108 Scalar = vpi_sys::vpiScalarVal,
110 Int = vpi_sys::vpiIntVal,
112 Real = vpi_sys::vpiRealVal,
114 String = vpi_sys::vpiStringVal,
116 Vector = vpi_sys::vpiVectorVal,
118 Strength = vpi_sys::vpiStrengthVal,
120 Time = vpi_sys::vpiTimeVal,
122 ObjType = vpi_sys::vpiObjTypeVal,
129 Suppress = vpi_sys::vpiSuppressVal,
131 ShortInt = vpi_sys::vpiShortIntVal,
133 LongInt = vpi_sys::vpiLongIntVal,
135 ShortReal = vpi_sys::vpiShortRealVal,
137 #[cfg(feature = "verilator")]
139 RawTwoState = vpi_sys::vpiRawTwoStateVal,
140 #[cfg(feature = "verilator")]
142 RawFourState = vpi_sys::vpiRawFourStateVal,
143}
144
145impl std::fmt::Display for ValueType {
146 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147 let type_name = match self {
148 ValueType::BinStr => "Binary String",
149 ValueType::OctStr => "Octal String",
150 ValueType::HexStr => "Hexadecimal String",
151 ValueType::DecStr => "Decimal String",
152 ValueType::Scalar => "Scalar",
153 ValueType::Int => "Integer",
154 ValueType::Real => "Real",
155 ValueType::String => "String",
156 ValueType::Vector => "Vector",
157 ValueType::Strength => "Strength",
158 ValueType::Time => "Time",
159 ValueType::ObjType => "Object Type",
160 ValueType::Suppress => "Suppress",
161 ValueType::ShortInt => "Short Integer",
162 ValueType::LongInt => "Long Integer",
163 ValueType::ShortReal => "Short Real",
164 #[cfg(feature = "verilator")]
165 ValueType::RawTwoState => "Raw Two-State Vector",
166 #[cfg(feature = "verilator")]
167 ValueType::RawFourState => "Raw Four-State Vector",
168 };
169 write!(f, "{type_name}")
170 }
171}
172
173#[derive(Debug, Clone, PartialEq)]
174pub struct StrengthValue {
176 logic: LogicVal,
178 strength0: Strength,
180 strength1: Strength,
182}
183
184impl Display for StrengthValue {
185 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186 write!(
187 f,
188 "{} ({}0, {}1)",
189 self.logic, self.strength0, self.strength1
190 )
191 }
192}
193
194impl StrengthValue {
195 #[must_use]
197 pub fn new(logic: LogicVal, strength0: Strength, strength1: Strength) -> Self {
198 Self {
199 logic,
200 strength0,
201 strength1,
202 }
203 }
204}
205
206impl From<vpi_sys::t_vpi_strengthval> for StrengthValue {
207 fn from(strength: vpi_sys::t_vpi_strengthval) -> Self {
208 let logic = LogicVal::from_u32(strength.logic as u32).unwrap_or(LogicVal::DontCare);
209 let strength0 = Strength::from_u32(strength.s0 as u32).unwrap_or(Strength::HiZ);
210 let strength1 = Strength::from_u32(strength.s1 as u32).unwrap_or(Strength::HiZ);
211 Self {
212 logic,
213 strength0,
214 strength1,
215 }
216 }
217}
218
219#[repr(u32)]
220#[derive(FromPrimitive, ToPrimitive, Copy, Clone, Debug, PartialEq, Eq)]
221pub enum Strength {
223 SupplyDrive = vpi_sys::vpiSupplyDrive,
225 StrongDrive = vpi_sys::vpiStrongDrive,
227 PullDrive = vpi_sys::vpiPullDrive,
229 LargeCharge = vpi_sys::vpiLargeCharge,
231 WeakDrive = vpi_sys::vpiWeakDrive,
233 MediumCharge = vpi_sys::vpiMediumCharge,
235 SmallCharge = vpi_sys::vpiSmallCharge,
237 HiZ = vpi_sys::vpiHiZ,
239}
240
241#[repr(i32)]
243#[derive(Copy, Clone, Debug, PartialEq, Eq)]
244pub enum PutValueDelay {
245 NoDelay = vpi_sys::vpiNoDelay as i32,
247 Inertial = vpi_sys::vpiInertialDelay as i32,
249 Transport = vpi_sys::vpiTransportDelay as i32,
251 PureTransport = vpi_sys::vpiPureTransportDelay as i32,
253}
254
255struct PutValuePayload {
256 raw: vpi_sys::t_vpi_value,
258 _string: Option<CString>,
260 _vector: Option<Vec<vpi_sys::t_vpi_vecval>>,
262 _time: Option<Box<vpi_sys::s_vpi_time>>,
264 _strength: Option<Box<vpi_sys::t_vpi_strengthval>>,
266}
267
268#[cfg(feature = "value_array")]
269struct PutValueArrayPayload {
270 raw: vpi_sys::t_vpi_arrayvalue,
272 _integers: Option<Vec<i32>>,
274 _shortints: Option<Vec<i16>>,
276 _longints: Option<Vec<i64>>,
278 _times: Option<Vec<vpi_sys::t_vpi_time>>,
280 _reals: Option<Vec<f64>>,
282 _shortreals: Option<Vec<f32>>,
284}
285
286fn cstring_lossy_no_nul(s: &str) -> CString {
287 let bytes: Vec<u8> = s.bytes().filter(|b| *b != 0).collect();
288 CString::new(bytes).expect("string was sanitized to exclude interior NUL")
289}
290
291fn encode_value_for_put(value: &Value) -> PutValuePayload {
292 let mut payload = PutValuePayload {
293 raw: vpi_sys::t_vpi_value {
294 format: 0,
295 value: vpi_sys::t_vpi_value__bindgen_ty_1 { integer: 0 },
296 },
297 _string: None,
298 _vector: None,
299 _time: None,
300 _strength: None,
301 };
302
303 match value {
304 Value::BinStr(s) => {
305 let cstr = cstring_lossy_no_nul(s);
306 payload.raw.format = vpi_sys::vpiBinStrVal as i32;
307 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
308 str_: cstr.as_ptr().cast_mut(),
309 };
310 payload._string = Some(cstr);
311 }
312 Value::OctStr(s) => {
313 let cstr = cstring_lossy_no_nul(s);
314 payload.raw.format = vpi_sys::vpiOctStrVal as i32;
315 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
316 str_: cstr.as_ptr().cast_mut(),
317 };
318 payload._string = Some(cstr);
319 }
320 Value::HexStr(s) => {
321 let cstr = cstring_lossy_no_nul(s);
322 payload.raw.format = vpi_sys::vpiHexStrVal as i32;
323 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
324 str_: cstr.as_ptr().cast_mut(),
325 };
326 payload._string = Some(cstr);
327 }
328 Value::DecStr(s) => {
329 let cstr = cstring_lossy_no_nul(s);
330 payload.raw.format = vpi_sys::vpiDecStrVal as i32;
331 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
332 str_: cstr.as_ptr().cast_mut(),
333 };
334 payload._string = Some(cstr);
335 }
336 Value::Scalar(s) => {
337 payload.raw.format = vpi_sys::vpiScalarVal as i32;
338 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 { scalar: *s as i32 };
339 }
340 Value::Int(v) => {
341 payload.raw.format = vpi_sys::vpiIntVal as i32;
342 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 { integer: *v };
343 }
344 Value::Real(v) => {
345 payload.raw.format = vpi_sys::vpiRealVal as i32;
346 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 { real: *v };
347 }
348 Value::String(s) => {
349 let cstr = cstring_lossy_no_nul(s);
350 payload.raw.format = vpi_sys::vpiStringVal as i32;
351 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
352 str_: cstr.as_ptr().cast_mut(),
353 };
354 payload._string = Some(cstr);
355 }
356 Value::Vector(vec) => {
357 let mut vector = vec.as_vecval();
358 payload.raw.format = vpi_sys::vpiVectorVal as i32;
359 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
360 vector: vector.as_mut_ptr(),
361 };
362 payload._vector = Some(vector);
363 }
364 Value::Strength(s) => {
365 let mut strength = Box::new(vpi_sys::t_vpi_strengthval {
366 logic: s.logic as i32,
367 s0: s.strength0 as i32,
368 s1: s.strength1 as i32,
369 });
370 payload.raw.format = vpi_sys::vpiStrengthVal as i32;
371 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
372 strength: strength.as_mut(),
373 };
374 payload._strength = Some(strength);
375 }
376 Value::Time(t) => {
377 let mut time = Box::new(vpi_sys::s_vpi_time::from(t));
378 payload.raw.format = vpi_sys::vpiTimeVal as i32;
379 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
380 time: time.as_mut(),
381 };
382 payload._time = Some(time);
383 }
384 Value::ObjType(v) => {
385 payload.raw.format = vpi_sys::vpiObjTypeVal as i32;
386 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 { integer: *v };
387 }
388 Value::Suppress => {
389 payload.raw.format = vpi_sys::vpiSuppressVal as i32;
390 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 { integer: 0 };
391 }
392 Value::ShortInt(v) => {
393 payload.raw.format = vpi_sys::vpiShortIntVal as i32;
394 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
395 integer: i32::from(*v),
396 };
397 }
398 Value::LongInt(v) => {
399 let cstr = cstring_lossy_no_nul(&v.to_string());
400 payload.raw.format = vpi_sys::vpiDecStrVal as i32;
401 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
402 str_: cstr.as_ptr().cast_mut(),
403 };
404 payload._string = Some(cstr);
405 }
406 Value::ShortReal(v) => {
407 payload.raw.format = vpi_sys::vpiRealVal as i32;
408 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
409 real: f64::from(*v),
410 };
411 }
412 #[cfg(feature = "verilator")]
413 Value::RawTwoState(bits) => {
414 let scalar_bits: Vec<LogicVal> = bits
415 .iter()
416 .map(|bit| if *bit { LogicVal::One } else { LogicVal::Zero })
417 .collect();
418 let mut vector = scalar_vector_to_vecval(&scalar_bits);
419 payload.raw.format = vpi_sys::vpiVectorVal as i32;
420 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
421 vector: vector.as_mut_ptr(),
422 };
423 payload._vector = Some(vector);
424 }
425 #[cfg(feature = "verilator")]
426 Value::RawFourState(vec) => {
427 let mut vector = vec.as_vecval();
428 payload.raw.format = vpi_sys::vpiVectorVal as i32;
429 payload.raw.value = vpi_sys::t_vpi_value__bindgen_ty_1 {
430 vector: vector.as_mut_ptr(),
431 };
432 payload._vector = Some(vector);
433 }
434 }
435
436 payload
437}
438
439#[cfg(feature = "value_array")]
440fn encode_value_array_for_put(
441 values: impl AsRef<[Value]>,
442 flags: PutValueArrayFlags,
443) -> Option<PutValueArrayPayload> {
444 let values = values.as_ref();
445 let mut payload = PutValueArrayPayload {
446 raw: vpi_sys::t_vpi_arrayvalue {
447 format: 0,
448 flags: flags.bits(),
449 value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
450 integers: std::ptr::null_mut(),
451 },
452 },
453 _integers: None,
454 _shortints: None,
455 _longints: None,
456 _times: None,
457 _reals: None,
458 _shortreals: None,
459 };
460
461 match values.first()? {
462 Value::Int(_) => {
463 let integers: Option<Vec<i32>> = values
464 .iter()
465 .map(|value| match value {
466 Value::Int(integer) => Some(*integer),
467 _ => None,
468 })
469 .collect();
470 let mut integers = integers?;
471 payload.raw.format = vpi_sys::vpiIntVal;
472 payload.raw.value = vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
473 integers: integers.as_mut_ptr(),
474 };
475 payload._integers = Some(integers);
476 }
477 Value::ShortInt(_) => {
478 let shortints: Option<Vec<i16>> = values
479 .iter()
480 .map(|value| match value {
481 Value::ShortInt(integer) => Some(*integer),
482 _ => None,
483 })
484 .collect();
485 let mut shortints = shortints?;
486 payload.raw.format = vpi_sys::vpiShortIntVal;
487 payload.raw.value = vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
488 shortints: shortints.as_mut_ptr(),
489 };
490 payload._shortints = Some(shortints);
491 }
492 Value::LongInt(_) => {
493 let longints: Option<Vec<i64>> = values
494 .iter()
495 .map(|value| match value {
496 Value::LongInt(integer) => Some(*integer),
497 _ => None,
498 })
499 .collect();
500 let mut longints = longints?;
501 payload.raw.format = vpi_sys::vpiLongIntVal;
502 payload.raw.value = vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
503 longints: longints.as_mut_ptr(),
504 };
505 payload._longints = Some(longints);
506 }
507 Value::Real(_) => {
508 let reals: Option<Vec<f64>> = values
509 .iter()
510 .map(|value| match value {
511 Value::Real(real) => Some(*real),
512 _ => None,
513 })
514 .collect();
515 let mut reals = reals?;
516 payload.raw.format = vpi_sys::vpiRealVal;
517 payload.raw.value = vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
518 reals: reals.as_mut_ptr(),
519 };
520 payload._reals = Some(reals);
521 }
522 Value::ShortReal(_) => {
523 let shortreals: Option<Vec<f32>> = values
524 .iter()
525 .map(|value| match value {
526 Value::ShortReal(real) => Some(*real),
527 _ => None,
528 })
529 .collect();
530 let mut shortreals = shortreals?;
531 payload.raw.format = vpi_sys::vpiShortRealVal;
532 payload.raw.value = vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
533 shortreals: shortreals.as_mut_ptr(),
534 };
535 payload._shortreals = Some(shortreals);
536 }
537 Value::Time(_) => {
538 let times: Option<Vec<vpi_sys::t_vpi_time>> = values
539 .iter()
540 .map(|value| match value {
541 Value::Time(time) => {
542 let time = vpi_sys::s_vpi_time::from(time);
543 Some(vpi_sys::t_vpi_time {
544 type_: time.type_,
545 high: time.high,
546 low: time.low,
547 real: time.real,
548 })
549 }
550 _ => None,
551 })
552 .collect();
553 let mut times = times?;
554 payload.raw.format = vpi_sys::vpiTimeVal;
555 payload.raw.value = vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
556 times: times.as_mut_ptr(),
557 };
558 payload._times = Some(times);
559 }
560 _ => return None,
561 }
562
563 Some(payload)
564}
565
566impl Display for Strength {
567 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
568 let name = match self {
569 Strength::SupplyDrive => "supply",
570 Strength::StrongDrive => "strong",
571 Strength::PullDrive => "pull",
572 Strength::LargeCharge => "large",
573 Strength::WeakDrive => "weak",
574 Strength::MediumCharge => "medium",
575 Strength::SmallCharge => "small",
576 Strength::HiZ => "highz",
577 };
578 write!(f, "{name}")
579 }
580}
581
582bitflags::bitflags! {
583 pub struct PutValueFlags: u32 {
585 const ReturnEvent = vpi_sys::vpiReturnEvent;
587 const UserAllocFlag = vpi_sys::vpiUserAllocFlag;
589 const OneValue = vpi_sys::vpiOneValue;
591 const PropagateOff = vpi_sys::vpiPropagateOff;
593 }
594}
595
596bitflags::bitflags! {
597 pub struct PutValueArrayFlags: u32 {
599 const UserAllocFlag = vpi_sys::vpiUserAllocFlag;
601 const OneValue = vpi_sys::vpiOneValue;
603 const PropagateOff = vpi_sys::vpiPropagateOff;
605 }
606}
607
608#[must_use]
613pub(crate) fn decode_vpi_value(
614 raw_value: vpi_sys::t_vpi_value,
615 obj: vpi_sys::vpiHandle,
616) -> Option<Value> {
617 match raw_value.format as u32 {
618 vpi_sys::vpiBinStrVal => {
619 let c_str = unsafe { std::ffi::CStr::from_ptr(raw_value.value.str_) };
620 Some(Value::BinStr(c_str.to_str().unwrap_or("").to_string()))
621 }
622 vpi_sys::vpiOctStrVal => {
623 let c_str = unsafe { std::ffi::CStr::from_ptr(raw_value.value.str_) };
624 Some(Value::OctStr(c_str.to_str().unwrap_or("").to_string()))
625 }
626 vpi_sys::vpiHexStrVal => {
627 let c_str = unsafe { std::ffi::CStr::from_ptr(raw_value.value.str_) };
628 Some(Value::HexStr(c_str.to_str().unwrap_or("").to_string()))
629 }
630 vpi_sys::vpiDecStrVal => {
631 let c_str = unsafe { std::ffi::CStr::from_ptr(raw_value.value.str_) };
632 Some(Value::DecStr(c_str.to_str().unwrap_or("").to_string()))
633 }
634 vpi_sys::vpiScalarVal => Some(Value::Scalar(
635 LogicVal::from_u32(unsafe { raw_value.value.integer } as u32)
636 .unwrap_or(LogicVal::DontCare),
637 )),
638 vpi_sys::vpiIntVal => Some(Value::Int(unsafe { raw_value.value.integer })),
639 vpi_sys::vpiRealVal => Some(Value::Real(unsafe { raw_value.value.real })),
640 vpi_sys::vpiStringVal => {
641 let c_str = unsafe { std::ffi::CStr::from_ptr(raw_value.value.str_) };
642 Some(Value::String(c_str.to_str().unwrap_or("").to_string()))
643 }
644 vpi_sys::vpiObjTypeVal => Some(Value::ObjType(unsafe { raw_value.value.integer })),
645 vpi_sys::vpiVectorVal => {
646 let vec_ptr = unsafe { raw_value.value.vector };
647 if vec_ptr.is_null() {
648 Some(Value::Vector(LogicVec::empty()))
649 } else {
650 let size = if obj.is_null() {
651 0usize
652 } else {
653 unsafe { vpi_sys::vpi_get(vpi_sys::vpiSize as i32, obj) as usize }
654 };
655 let num_words = size.div_ceil(32);
656 let vec = unsafe { std::slice::from_raw_parts(vec_ptr, num_words) };
657 Some(Value::Vector(LogicVec::from_vecval(vec, size)))
658 }
659 }
660 vpi_sys::vpiStrengthVal => {
661 let strength: vpi_sys::t_vpi_strengthval = unsafe { *raw_value.value.strength };
662 Some(Value::Strength(StrengthValue::from(strength)))
663 }
664 vpi_sys::vpiTimeVal => {
665 let vpi_time: vpi_sys::t_vpi_time = unsafe { *raw_value.value.time };
666 Some(Value::Time(Time::from(vpi_time)))
667 }
668 vpi_sys::vpiShortIntVal => Some(Value::ShortInt(unsafe { raw_value.value.integer } as i16)),
669 _ => None,
670 }
671}
672
673#[must_use]
683pub fn value_array_to_string_array(
684 values: impl AsRef<[Value]>,
685 format: ValueType,
686) -> Option<Vec<String>> {
687 let values = values.as_ref();
688 match format {
689 ValueType::BinStr => values
690 .iter()
691 .map(|value| match value {
692 Value::BinStr(s) => Some(s.clone()),
693 _ => None,
694 })
695 .collect(),
696 ValueType::OctStr => values
697 .iter()
698 .map(|value| match value {
699 Value::OctStr(s) => Some(s.clone()),
700 _ => None,
701 })
702 .collect(),
703 ValueType::HexStr => values
704 .iter()
705 .map(|value| match value {
706 Value::HexStr(s) => Some(s.clone()),
707 _ => None,
708 })
709 .collect(),
710 ValueType::DecStr => values
711 .iter()
712 .map(|value| match value {
713 Value::DecStr(s) => Some(s.clone()),
714 _ => None,
715 })
716 .collect(),
717 ValueType::String => values
718 .iter()
719 .map(|value| match value {
720 Value::String(s) => Some(s.clone()),
721 _ => None,
722 })
723 .collect(),
724 ValueType::Vector => values
725 .iter()
726 .map(|value| match value {
727 Value::Vector(_) => Some(value.to_string()),
728 _ => None,
729 })
730 .collect(),
731 #[cfg(feature = "verilator")]
732 ValueType::RawTwoState => values
733 .iter()
734 .map(|value| match value {
735 Value::RawTwoState(_) => Some(value.to_string()),
736 _ => None,
737 })
738 .collect(),
739 #[cfg(feature = "verilator")]
740 ValueType::RawFourState => values
741 .iter()
742 .map(|value| match value {
743 Value::RawFourState(_) => Some(value.to_string()),
744 _ => None,
745 })
746 .collect(),
747 _ => None,
748 }
749}
750
751#[must_use]
756pub fn value_array_to_int_array(values: impl AsRef<[Value]>) -> Option<Vec<i32>> {
757 let values = values.as_ref();
758
759 values
760 .iter()
761 .map(|value| match value {
762 Value::Int(v) => Some(*v),
763 _ => None,
764 })
765 .collect()
766}
767
768#[must_use]
773pub fn value_array_to_shortint_array(values: impl AsRef<[Value]>) -> Option<Vec<i16>> {
774 let values = values.as_ref();
775
776 values
777 .iter()
778 .map(|value| match value {
779 Value::ShortInt(v) => Some(*v),
780 _ => None,
781 })
782 .collect()
783}
784
785#[must_use]
790pub fn value_array_to_longint_array(values: impl AsRef<[Value]>) -> Option<Vec<i64>> {
791 let values = values.as_ref();
792
793 values
794 .iter()
795 .map(|value| match value {
796 Value::LongInt(v) => Some(*v),
797 _ => None,
798 })
799 .collect()
800}
801
802#[must_use]
807pub fn value_array_to_real_array(values: impl AsRef<[Value]>) -> Option<Vec<f64>> {
808 let values = values.as_ref();
809
810 values
811 .iter()
812 .map(|value| match value {
813 Value::Real(v) => Some(*v),
814 _ => None,
815 })
816 .collect()
817}
818
819#[must_use]
824pub fn value_array_to_shortreal_array(values: impl AsRef<[Value]>) -> Option<Vec<f32>> {
825 let values = values.as_ref();
826
827 values
828 .iter()
829 .map(|value| match value {
830 Value::ShortReal(v) => Some(*v),
831 _ => None,
832 })
833 .collect()
834}
835
836#[must_use]
841pub fn value_array_to_scalar_array(values: impl AsRef<[Value]>) -> Option<Vec<LogicVal>> {
842 let values = values.as_ref();
843
844 values
845 .iter()
846 .map(|value| match value {
847 Value::Scalar(v) => Some(*v),
848 _ => None,
849 })
850 .collect()
851}
852
853#[must_use]
858pub fn value_array_to_time_array(values: impl AsRef<[Value]>) -> Option<Vec<Time>> {
859 let values = values.as_ref();
860
861 values
862 .iter()
863 .map(|value| match value {
864 Value::Time(v) => Some(v.clone()),
865 _ => None,
866 })
867 .collect()
868}
869
870#[must_use]
875pub fn value_array_to_strength_array(values: impl AsRef<[Value]>) -> Option<Vec<StrengthValue>> {
876 let values = values.as_ref();
877
878 values
879 .iter()
880 .map(|value| match value {
881 Value::Strength(v) => Some(v.clone()),
882 _ => None,
883 })
884 .collect()
885}
886
887#[must_use]
906pub fn string_array_to_value_array(
907 values: impl AsRef<[String]>,
908 format: ValueType,
909) -> Option<Vec<Value>> {
910 let values = values.as_ref();
911 match format {
912 ValueType::BinStr => Some(values.iter().cloned().map(Value::BinStr).collect()),
913 ValueType::OctStr => Some(values.iter().cloned().map(Value::OctStr).collect()),
914 ValueType::HexStr => Some(values.iter().cloned().map(Value::HexStr).collect()),
915 ValueType::DecStr => Some(values.iter().cloned().map(Value::DecStr).collect()),
916 ValueType::String => Some(values.iter().cloned().map(Value::String).collect()),
917 ValueType::Vector => values
918 .iter()
919 .map(|value| LogicVec::try_from_str(value).map(Value::Vector))
920 .collect(),
921 #[cfg(feature = "verilator")]
922 ValueType::RawTwoState => values
923 .iter()
924 .map(|value| {
925 value
926 .chars()
927 .map(|c| match c {
928 '0' => Some(false),
929 '1' => Some(true),
930 _ => None,
931 })
932 .collect::<Option<Vec<bool>>>()
933 .map(Value::RawTwoState)
934 })
935 .collect(),
936 #[cfg(feature = "verilator")]
937 ValueType::RawFourState => values
938 .iter()
939 .map(|value| LogicVec::try_from_str(value).map(Value::RawFourState))
940 .collect(),
941 _ => None,
942 }
943}
944
945#[must_use]
949pub fn int_array_to_value_array(values: impl AsRef<[i32]>) -> Vec<Value> {
950 values.as_ref().iter().copied().map(Value::Int).collect()
951}
952
953#[must_use]
957pub fn shortint_array_to_value_array(values: impl AsRef<[i16]>) -> Vec<Value> {
958 values
959 .as_ref()
960 .iter()
961 .copied()
962 .map(Value::ShortInt)
963 .collect()
964}
965
966#[must_use]
970pub fn longint_array_to_value_array(values: impl AsRef<[i64]>) -> Vec<Value> {
971 values
972 .as_ref()
973 .iter()
974 .copied()
975 .map(Value::LongInt)
976 .collect()
977}
978
979#[must_use]
983pub fn real_array_to_value_array(values: impl AsRef<[f64]>) -> Vec<Value> {
984 values.as_ref().iter().copied().map(Value::Real).collect()
985}
986
987#[must_use]
991pub fn shortreal_array_to_value_array(values: impl AsRef<[f32]>) -> Vec<Value> {
992 values
993 .as_ref()
994 .iter()
995 .copied()
996 .map(Value::ShortReal)
997 .collect()
998}
999
1000#[must_use]
1004pub fn scalar_array_to_value_array(values: impl AsRef<[LogicVal]>) -> Vec<Value> {
1005 values.as_ref().iter().copied().map(Value::Scalar).collect()
1006}
1007
1008#[must_use]
1012pub fn time_array_to_value_array(values: impl AsRef<[Time]>) -> Vec<Value> {
1013 values.as_ref().iter().cloned().map(Value::Time).collect()
1014}
1015
1016#[must_use]
1020pub fn strength_array_to_value_array(values: impl AsRef<[StrengthValue]>) -> Vec<Value> {
1021 values
1022 .as_ref()
1023 .iter()
1024 .cloned()
1025 .map(Value::Strength)
1026 .collect()
1027}
1028
1029#[cfg(feature = "bigint")]
1035#[must_use]
1036pub fn scalar_vector_to_biguint(bits: impl AsRef<[LogicVal]>) -> Option<num_bigint::BigUint> {
1037 let mut result = num_bigint::BigUint::ZERO;
1038 for bit in bits.as_ref() {
1039 result <<= 1u32;
1040 match bit {
1041 LogicVal::Zero => {}
1042 LogicVal::One => result |= num_bigint::BigUint::from(1u32),
1043 _ => return None,
1044 }
1045 }
1046 Some(result)
1047}
1048
1049#[must_use]
1055#[deprecated(
1056 since = "0.5.0",
1057 note = "Use `LogicVec::from_uint(value)` instead of this function."
1058)]
1059pub fn uint64_to_scalar_vector(value: u64, bits: usize) -> Vec<LogicVal> {
1060 (0..bits)
1061 .rev()
1062 .map(|i| {
1063 if (value >> i) & 1 == 1 {
1064 LogicVal::One
1065 } else {
1066 LogicVal::Zero
1067 }
1068 })
1069 .collect()
1070}
1071
1072#[must_use]
1079pub fn scalar_vector_to_uint64(bits: impl AsRef<[LogicVal]>) -> Option<u64> {
1080 let bits = bits.as_ref();
1081 if bits.len() > 64 {
1082 return None;
1083 }
1084 let mut result: u64 = 0;
1085 for bit in bits {
1086 result <<= 1;
1087 match bit {
1088 LogicVal::Zero => {}
1089 LogicVal::One => result |= 1,
1090 _ => return None,
1091 }
1092 }
1093 Some(result)
1094}
1095
1096#[must_use]
1101#[deprecated(
1102 since = "0.5.0",
1103 note = "Use `LogicVec::from(bits).to_string()` instead of this function."
1104)]
1105pub fn scalar_vector_to_string(bits: impl AsRef<[LogicVal]>) -> String {
1106 LogicVec::from(bits.as_ref()).to_string()
1107}
1108
1109#[must_use]
1115#[deprecated(
1116 since = "0.5.0",
1117 note = "Use `LogicVec::from_str(bits)` instead of this function."
1118)]
1119pub fn string_to_scalar_vector(bits: &str) -> Option<Vec<LogicVal>> {
1120 bits.chars()
1121 .map(|c| match c {
1122 '0' => Some(LogicVal::Zero),
1123 '1' => Some(LogicVal::One),
1124 'X' | 'x' => Some(LogicVal::X),
1125 'Z' | 'z' => Some(LogicVal::Z),
1126 'H' | 'h' => Some(LogicVal::H),
1127 'L' | 'l' => Some(LogicVal::L),
1128 '-' => Some(LogicVal::DontCare),
1129 _ => None,
1130 })
1131 .collect()
1132}
1133
1134#[cfg(feature = "bigint")]
1140#[must_use]
1141#[deprecated(
1142 since = "0.5.0",
1143 note = "Use `LogicVec::from_biguint(value)` instead of this function."
1144)]
1145pub fn biguint_to_scalar_vector(value: &num_bigint::BigUint, bits: usize) -> Vec<LogicVal> {
1146 (0..bits)
1147 .rev()
1148 .map(|i| {
1149 if value.bit(i as u64) {
1150 LogicVal::One
1151 } else {
1152 LogicVal::Zero
1153 }
1154 })
1155 .collect()
1156}
1157
1158#[must_use]
1164#[deprecated(
1165 since = "0.5.0",
1166 note = "Use `LogicVec::from_int(value, bits)` instead of this function."
1167)]
1168pub fn int64_to_scalar_vector(value: i64, bits: usize) -> Vec<LogicVal> {
1169 #[allow(deprecated)]
1170 uint64_to_scalar_vector(value as u64, bits)
1171}
1172
1173#[must_use]
1180#[deprecated(
1181 since = "0.5.0",
1182 note = "Use `LogicVec::from(bits).try_into()` instead of this function."
1183)]
1184pub fn scalar_vector_to_int64(bits: impl AsRef<[LogicVal]>) -> Option<i64> {
1185 let bits = bits.as_ref();
1186 if bits.is_empty() || bits.len() > 64 {
1187 return None;
1188 }
1189 let unsigned = scalar_vector_to_uint64(bits)?;
1190 let shift = 64 - bits.len();
1192 Some((unsigned << shift) as i64 >> shift)
1193}
1194
1195#[cfg(feature = "bigint")]
1202#[must_use]
1203#[deprecated(
1204 since = "0.5.0",
1205 note = "Use `LogicVec::from_bigint(value)` instead of this function."
1206)]
1207pub fn bigint_to_scalar_vector(value: &num_bigint::BigInt, bits: usize) -> Vec<LogicVal> {
1208 use num_bigint::Sign;
1209 let unsigned: num_bigint::BigUint = if value.sign() == Sign::Minus {
1211 let modulus = num_bigint::BigUint::from(1u32) << bits;
1212 let mag = value.magnitude();
1213 modulus - mag
1214 } else {
1215 value.magnitude().clone()
1216 };
1217 #[allow(deprecated)]
1218 biguint_to_scalar_vector(&unsigned, bits)
1219}
1220
1221#[cfg(feature = "bigint")]
1228#[must_use]
1229#[deprecated(
1230 since = "0.5.0",
1231 note = "Use `LogicVec::as_bigint` instead of this function."
1232)]
1233pub fn scalar_vector_to_bigint(bits: impl AsRef<[LogicVal]>) -> Option<num_bigint::BigInt> {
1234 let bits = bits.as_ref();
1235 if bits.is_empty() {
1236 return None;
1237 }
1238 #[allow(deprecated)]
1239 let unsigned = scalar_vector_to_biguint(bits)?;
1240 if bits[0] == LogicVal::One {
1242 let modulus = num_bigint::BigUint::from(1u32) << bits.len();
1243 Some(num_bigint::BigInt::from(unsigned) - num_bigint::BigInt::from(modulus))
1244 } else {
1245 Some(num_bigint::BigInt::from(unsigned))
1246 }
1247}
1248
1249impl Handle {
1250 #[must_use]
1255 pub fn put_value(&self, value: &Value) -> Handle {
1256 self.put_value_scheduled(value, None, PutValueDelay::NoDelay, &PutValueFlags::empty())
1257 }
1258
1259 #[must_use]
1265 pub fn put_value_scheduled(
1266 &self,
1267 value: &Value,
1268 time: Option<&Time>,
1269 delay: PutValueDelay,
1270 flags: &PutValueFlags,
1271 ) -> Handle {
1272 if self.is_null() {
1273 return Handle::null();
1274 }
1275
1276 let mut payload = encode_value_for_put(value);
1277
1278 let mut raw_time_storage;
1279 let raw_time_ptr = if matches!(delay, PutValueDelay::NoDelay) {
1280 std::ptr::null_mut()
1281 } else {
1282 raw_time_storage = vpi_sys::s_vpi_time::from(&time.cloned().unwrap_or(Time::Sim(0)));
1283 &raw mut raw_time_storage
1284 };
1285
1286 let raw_flags = (delay as i32) | (flags.bits() as i32);
1287
1288 let event = unsafe {
1289 vpi_sys::vpi_put_value(self.as_raw(), &raw mut payload.raw, raw_time_ptr, raw_flags)
1290 };
1291
1292 Handle::from_raw(event)
1293 }
1294
1295 #[must_use]
1300 pub fn put_int_value(&self, value: i32) -> Handle {
1301 self.put_value(&Value::Int(value))
1302 }
1303
1304 #[must_use]
1310 #[cfg(feature = "value_array")]
1311 pub fn put_value_array(&self, values: impl AsRef<[Value]>) -> bool {
1312 self.put_value_array_with_flags(values, 0, PutValueArrayFlags::empty())
1313 }
1314
1315 #[must_use]
1320 #[cfg(feature = "value_array")]
1321 pub fn put_value_array_with_flags(
1322 &self,
1323 values: impl AsRef<[Value]>,
1324 start_index: i32,
1325 flags: PutValueArrayFlags,
1326 ) -> bool {
1327 if self.is_null() {
1328 return false;
1329 }
1330 let values = values.as_ref();
1331 if values.is_empty() {
1332 return true;
1333 }
1334
1335 let Some(mut payload) = encode_value_array_for_put(values, flags) else {
1336 return false;
1337 };
1338
1339 let Ok(num) = vpi_sys::PLI_UINT32::try_from(values.len()) else {
1340 return false;
1341 };
1342
1343 let mut index = start_index;
1344 unsafe {
1345 vpi_sys::vpi_put_value_array(self.as_raw(), &raw mut payload.raw, &raw mut index, num);
1346 }
1347 true
1348 }
1349
1350 #[must_use]
1358 #[cfg(not(feature = "value_array"))]
1359 pub fn put_value_array(&self, values: impl AsRef<[Value]>) -> bool {
1360 self.put_value_array_with_flags(values, 0, &PutValueArrayFlags::empty())
1361 }
1362
1363 #[must_use]
1377 #[cfg(not(feature = "value_array"))]
1378 pub fn put_value_array_with_flags(
1379 &self,
1380 values: impl AsRef<[Value]>,
1381 start_index: i32,
1382 flags: &PutValueArrayFlags,
1383 ) -> bool {
1384 if self.is_null() {
1385 return false;
1386 }
1387
1388 let _ = flags;
1389
1390 for (offset, value) in values.as_ref().iter().enumerate() {
1391 let Ok(offset) = i32::try_from(offset) else {
1392 return false;
1393 };
1394 let Some(index) = start_index.checked_add(offset) else {
1395 return false;
1396 };
1397
1398 let element = self.handle_by_index(index);
1399 if element.is_null() {
1400 return false;
1401 }
1402
1403 let _ = element.put_value(value);
1404 }
1405
1406 true
1407 }
1408
1409 #[must_use]
1418 pub fn get_value(&self, format: ValueType) -> Option<Value> {
1419 if self.is_null() {
1420 return None;
1421 }
1422 let mut value = vpi_sys::t_vpi_value {
1423 format: format as i32,
1424 value: vpi_sys::t_vpi_value__bindgen_ty_1 { integer: 0 },
1425 };
1426 unsafe { vpi_sys::vpi_get_value(self.as_raw(), &raw mut value) };
1427 decode_vpi_value(value, self.as_raw())
1428 }
1429
1430 #[must_use]
1452 #[cfg(feature = "value_array")]
1453 pub fn get_value_array(&self, format: ValueType) -> Option<Vec<Value>> {
1454 if self.is_null() {
1455 return None;
1456 }
1457
1458 let size =
1459 unsafe { vpi_sys::vpi_get(vpi_sys::vpiSize as PLI_INT32, self.as_raw()) } as usize;
1460
1461 if size == 0 {
1462 return Some(Vec::new());
1463 }
1464
1465 match format {
1466 ValueType::Int => {
1467 let mut integers: Vec<i32> = vec![0; size];
1468 let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
1469 format: vpi_sys::vpiIntVal,
1470 flags: 0,
1471 value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
1472 integers: integers.as_mut_ptr(),
1473 },
1474 };
1475 let mut index = 0;
1476
1477 unsafe {
1478 vpi_sys::vpi_get_value_array(
1479 self.as_raw(),
1480 &raw mut arrayvalue,
1481 &raw mut index,
1482 size as vpi_sys::PLI_UINT32,
1483 );
1484 }
1485
1486 Some(integers.into_iter().map(Value::Int).collect::<Vec<Value>>())
1487 }
1488 ValueType::Real => {
1489 let mut reals: Vec<f64> = vec![0.0; size];
1490 let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
1491 format: vpi_sys::vpiRealVal,
1492 flags: 0,
1493 value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
1494 reals: reals.as_mut_ptr(),
1495 },
1496 };
1497 let mut index = 0;
1498
1499 unsafe {
1500 vpi_sys::vpi_get_value_array(
1501 self.as_raw(),
1502 &raw mut arrayvalue,
1503 &raw mut index,
1504 size as vpi_sys::PLI_UINT32,
1505 );
1506 }
1507
1508 Some(reals.into_iter().map(Value::Real).collect::<Vec<Value>>())
1509 }
1510 ValueType::Time => {
1511 let mut times: Vec<vpi_sys::t_vpi_time> = vec![
1512 vpi_sys::t_vpi_time {
1513 type_: 0,
1514 high: 0,
1515 low: 0,
1516 real: 0.0,
1517 };
1518 size
1519 ];
1520 let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
1521 format: vpi_sys::vpiTimeVal,
1522 flags: 0,
1523 value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
1524 times: times.as_mut_ptr(),
1525 },
1526 };
1527 let mut index = 0;
1528
1529 unsafe {
1530 vpi_sys::vpi_get_value_array(
1531 self.as_raw(),
1532 &raw mut arrayvalue,
1533 &raw mut index,
1534 size as vpi_sys::PLI_UINT32,
1535 );
1536 }
1537
1538 Some(
1539 times
1540 .into_iter()
1541 .map(|t| {
1542 let vpi_time = vpi_sys::s_vpi_time {
1543 type_: t.type_,
1544 high: t.high,
1545 low: t.low,
1546 real: t.real,
1547 };
1548 Value::Time(Time::from(vpi_time))
1549 })
1550 .collect::<Vec<Value>>(),
1551 )
1552 }
1553 ValueType::ShortInt => {
1554 let mut shortints: Vec<i16> = vec![0; size];
1555 let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
1556 format: vpi_sys::vpiShortIntVal,
1557 flags: 0,
1558 value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
1559 shortints: shortints.as_mut_ptr(),
1560 },
1561 };
1562 let mut index = 0;
1563
1564 unsafe {
1565 vpi_sys::vpi_get_value_array(
1566 self.as_raw(),
1567 &raw mut arrayvalue,
1568 &raw mut index,
1569 size as vpi_sys::PLI_UINT32,
1570 );
1571 }
1572
1573 Some(
1574 shortints
1575 .into_iter()
1576 .map(Value::ShortInt)
1577 .collect::<Vec<Value>>(),
1578 )
1579 }
1580 ValueType::LongInt => {
1581 let mut longints: Vec<i64> = vec![0; size];
1582 let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
1583 format: vpi_sys::vpiLongIntVal,
1584 flags: 0,
1585 value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
1586 longints: longints.as_mut_ptr(),
1587 },
1588 };
1589 let mut index = 0;
1590
1591 unsafe {
1592 vpi_sys::vpi_get_value_array(
1593 self.as_raw(),
1594 &raw mut arrayvalue,
1595 &raw mut index,
1596 size as vpi_sys::PLI_UINT32,
1597 );
1598 }
1599
1600 Some(
1601 longints
1602 .into_iter()
1603 .map(Value::LongInt)
1604 .collect::<Vec<Value>>(),
1605 )
1606 }
1607 ValueType::ShortReal => {
1608 let mut shortreals: Vec<f32> = vec![0.0; size];
1609 let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
1610 format: vpi_sys::vpiShortRealVal,
1611 flags: 0,
1612 value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
1613 shortreals: shortreals.as_mut_ptr(),
1614 },
1615 };
1616 let mut index = 0;
1617
1618 unsafe {
1619 vpi_sys::vpi_get_value_array(
1620 self.as_raw(),
1621 &raw mut arrayvalue,
1622 &raw mut index,
1623 size as vpi_sys::PLI_UINT32,
1624 );
1625 }
1626
1627 Some(
1628 shortreals
1629 .into_iter()
1630 .map(Value::ShortReal)
1631 .collect::<Vec<Value>>(),
1632 )
1633 }
1634 ValueType::Vector => {
1635 let mut values = Vec::with_capacity(size);
1638 for _ in 0..size {
1639 if let Some(val) = self.get_value(ValueType::Vector) {
1640 values.push(val);
1641 }
1642 }
1643 Some(values)
1644 }
1645 ValueType::Scalar => {
1646 let mut rawvals: Vec<vpi_sys::PLI_BYTE8> = vec![0; size];
1648 let mut arrayvalue = vpi_sys::t_vpi_arrayvalue {
1649 format: vpi_sys::vpiScalarVal,
1650 flags: 0,
1651 value: vpi_sys::t_vpi_arrayvalue__bindgen_ty_1 {
1652 rawvals: rawvals.as_mut_ptr(),
1653 },
1654 };
1655 let mut index = 0;
1656
1657 unsafe {
1658 vpi_sys::vpi_get_value_array(
1659 self.as_raw(),
1660 &raw mut arrayvalue,
1661 &raw mut index,
1662 size as vpi_sys::PLI_UINT32,
1663 );
1664 }
1665
1666 Some(
1667 rawvals
1668 .into_iter()
1669 .filter_map(|v| LogicVal::from_u32(v as u32).map(Value::Scalar))
1670 .collect::<Vec<Value>>(),
1671 )
1672 }
1673 _ => {
1674 Some(Vec::new())
1676 }
1677 }
1678 }
1679
1680 #[must_use]
1689 #[cfg(not(feature = "value_array"))]
1690 pub fn get_value_array(&self, format: ValueType) -> Option<Vec<Value>> {
1691 if self.is_null() {
1692 return None;
1693 }
1694
1695 let raw_size = unsafe { vpi_sys::vpi_get(vpi_sys::vpiSize as PLI_INT32, self.as_raw()) };
1696 let size = usize::try_from(raw_size).ok()?;
1697
1698 let mut values = Vec::with_capacity(size);
1699 for index in 0..size {
1700 let Ok(index) = i32::try_from(index) else {
1701 return None;
1702 };
1703
1704 let element = self.handle_by_index(index);
1705 if element.is_null() {
1706 return None;
1707 }
1708
1709 let value = element.get_value(format)?;
1710 values.push(value);
1711 }
1712
1713 Some(values)
1714 }
1715
1716 #[must_use]
1718 pub fn is_array(&self) -> bool {
1719 if self.is_null() {
1720 return false;
1721 }
1722 self.get_bool(Property::Array).unwrap_or(false)
1723 }
1724}
1725
1726#[cfg(test)]
1727mod tests {
1728 use super::{
1729 cstring_lossy_no_nul, encode_value_for_put, scalar_vector_to_uint64,
1730 strength_array_to_value_array, string_array_to_value_array, time_array_to_value_array,
1731 value_array_to_int_array, value_array_to_strength_array, value_array_to_string_array,
1732 value_array_to_time_array, LogicVal, LogicVec, PutValueArrayFlags, PutValueDelay,
1733 PutValueFlags, Value, ValueType,
1734 };
1735 use crate::{Handle, Strength, StrengthValue, Time};
1736
1737 #[test]
1738 fn cstring_lossy_no_nul_strips_interior_nuls() {
1739 let cstr = cstring_lossy_no_nul("ab\0cd");
1740 assert_eq!(cstr.to_bytes(), b"abcd");
1741 }
1742
1743 #[test]
1744 fn put_value_delay_matches_vpi_constants() {
1745 assert_eq!(PutValueDelay::NoDelay as i32, vpi_sys::vpiNoDelay as i32);
1746 assert_eq!(
1747 PutValueDelay::Inertial as i32,
1748 vpi_sys::vpiInertialDelay as i32
1749 );
1750 assert_eq!(
1751 PutValueDelay::Transport as i32,
1752 vpi_sys::vpiTransportDelay as i32
1753 );
1754 assert_eq!(
1755 PutValueDelay::PureTransport as i32,
1756 vpi_sys::vpiPureTransportDelay as i32
1757 );
1758 }
1759
1760 #[test]
1761 fn put_value_flags_empty_is_zero() {
1762 assert_eq!(PutValueFlags::empty().bits(), 0);
1763 }
1764
1765 #[test]
1766 fn put_value_on_null_handle_returns_null() {
1767 let h = Handle::null();
1768 let event = h.put_value(&Value::Int(7));
1769 assert!(event.is_null());
1770 }
1771
1772 #[test]
1773 fn put_value_scheduled_on_null_handle_returns_null() {
1774 let h = Handle::null();
1775 let event = h.put_value_scheduled(
1776 &Value::Int(7),
1777 Some(&Time::Sim(5)),
1778 PutValueDelay::Inertial,
1779 &PutValueFlags::ReturnEvent,
1780 );
1781 assert!(event.is_null());
1782 }
1783
1784 #[test]
1785 fn put_int_value_on_null_handle_returns_null() {
1786 let h = Handle::null();
1787 let event = h.put_int_value(7);
1788 assert!(event.is_null());
1789 }
1790
1791 #[test]
1792 fn put_value_array_flags_empty_is_zero() {
1793 assert_eq!(PutValueArrayFlags::empty().bits(), 0);
1794 }
1795
1796 #[test]
1797 #[cfg(not(feature = "value_array"))]
1798 fn get_value_array_on_null_handle_returns_none() {
1799 let h = Handle::null();
1800 assert!(h.get_value_array(ValueType::Int).is_none());
1801 }
1802
1803 #[test]
1804 fn encode_value_for_put_string_uses_string_format_and_storage() {
1805 let payload = encode_value_for_put(&Value::String("hello".to_string()));
1806 assert_eq!(payload.raw.format, vpi_sys::vpiStringVal as i32);
1807 assert!(payload._string.is_some());
1808 assert_eq!(
1809 payload
1810 ._string
1811 .as_ref()
1812 .expect("string storage should exist")
1813 .to_bytes(),
1814 b"hello"
1815 );
1816 }
1817
1818 #[test]
1819 fn encode_value_for_put_vector_allocates_vecval_storage() {
1820 let payload = encode_value_for_put(&Value::Vector(LogicVec::from(vec![
1821 LogicVal::One,
1822 LogicVal::Zero,
1823 LogicVal::X,
1824 LogicVal::Z,
1825 ])));
1826 assert_eq!(payload.raw.format, vpi_sys::vpiVectorVal as i32);
1827 assert!(payload._vector.is_some());
1828 assert!(!payload._vector.as_ref().expect("vector storage").is_empty());
1829 }
1830
1831 #[test]
1832 fn encode_value_for_put_longint_uses_decimal_string_path() {
1833 let payload = encode_value_for_put(&Value::LongInt(-42));
1834 assert_eq!(payload.raw.format, vpi_sys::vpiDecStrVal as i32);
1835 assert_eq!(
1836 payload
1837 ._string
1838 .as_ref()
1839 .expect("longint should use string backing")
1840 .to_bytes(),
1841 b"-42"
1842 );
1843 }
1844
1845 #[test]
1846 fn encode_value_for_put_time_uses_time_format_and_storage() {
1847 let payload = encode_value_for_put(&Value::Time(Time::Sim(10)));
1848 assert_eq!(payload.raw.format, vpi_sys::vpiTimeVal as i32);
1849 assert!(payload._time.is_some());
1850 }
1851
1852 #[test]
1853 fn value_array_to_string_array_accepts_string_backed_formats() {
1854 let values = vec![
1855 Value::HexStr("AA".to_string()),
1856 Value::HexStr("10".to_string()),
1857 ];
1858 let demoted = value_array_to_string_array(&values, ValueType::HexStr);
1859 assert_eq!(demoted, Some(vec!["AA".to_string(), "10".to_string()]));
1860 }
1861
1862 #[test]
1863 fn value_array_to_string_array_rejects_non_string_format() {
1864 let values = vec![Value::String("x".to_string())];
1865 assert_eq!(value_array_to_string_array(&values, ValueType::Int), None);
1866 }
1867
1868 #[test]
1869 fn value_array_to_string_array_string_rejects_vector_variants() {
1870 let vector_values = vec![Value::Vector(LogicVec::from(vec![
1871 LogicVal::Zero,
1872 LogicVal::One,
1873 ]))];
1874 assert_eq!(
1875 value_array_to_string_array(&vector_values, ValueType::String),
1876 None
1877 );
1878 }
1879
1880 #[test]
1881 fn value_array_to_string_array_supports_vector_like_formats_directly() {
1882 let vector_values = vec![Value::Vector(LogicVec::from(vec![
1883 LogicVal::Zero,
1884 LogicVal::One,
1885 LogicVal::X,
1886 LogicVal::Z,
1887 ]))];
1888 assert_eq!(
1889 value_array_to_string_array(&vector_values, ValueType::Vector),
1890 Some(vec!["01XZ".to_string()])
1891 );
1892 }
1893
1894 #[test]
1895 fn value_array_to_int_array_rejects_mixed_values() {
1896 let values = vec![Value::Int(1), Value::ShortInt(2)];
1897 assert_eq!(value_array_to_int_array(&values), None);
1898 }
1899
1900 #[test]
1901 fn value_array_to_time_array_demotes_time_values() {
1902 let values = vec![
1903 Value::Time(Time::Sim(5)),
1904 Value::Time(Time::ScaledReal(2.5)),
1905 ];
1906 let demoted = value_array_to_time_array(&values);
1907 assert_eq!(demoted, Some(vec![Time::Sim(5), Time::ScaledReal(2.5)]));
1908 }
1909
1910 #[test]
1911 fn value_array_to_strength_array_demotes_strength_values() {
1912 let values = vec![
1913 Value::Strength(StrengthValue::new(
1914 LogicVal::One,
1915 Strength::StrongDrive,
1916 Strength::HiZ,
1917 )),
1918 Value::Strength(StrengthValue::new(
1919 LogicVal::Zero,
1920 Strength::PullDrive,
1921 Strength::WeakDrive,
1922 )),
1923 ];
1924
1925 let demoted = value_array_to_strength_array(&values);
1926 assert_eq!(
1927 demoted,
1928 Some(vec![
1929 StrengthValue::new(LogicVal::One, Strength::StrongDrive, Strength::HiZ),
1930 StrengthValue::new(LogicVal::Zero, Strength::PullDrive, Strength::WeakDrive),
1931 ])
1932 );
1933 }
1934
1935 #[test]
1936 fn value_array_to_strength_array_rejects_mixed_values() {
1937 let values = vec![
1938 Value::Strength(StrengthValue::new(
1939 LogicVal::One,
1940 Strength::StrongDrive,
1941 Strength::HiZ,
1942 )),
1943 Value::Int(3),
1944 ];
1945
1946 assert_eq!(value_array_to_strength_array(&values), None);
1947 }
1948
1949 #[test]
1950 fn string_array_to_value_array_promotes_by_requested_format() {
1951 let input = vec!["101".to_string(), "010".to_string()];
1952 let promoted = string_array_to_value_array(&input, ValueType::BinStr);
1953 assert_eq!(
1954 promoted,
1955 Some(vec![
1956 Value::BinStr("101".to_string()),
1957 Value::BinStr("010".to_string())
1958 ])
1959 );
1960 }
1961
1962 #[test]
1963 fn string_array_to_value_array_rejects_non_string_formats() {
1964 let input = vec!["1".to_string()];
1965 assert_eq!(string_array_to_value_array(&input, ValueType::Int), None);
1966 }
1967
1968 #[test]
1969 fn string_array_to_value_array_supports_vector_like_formats() {
1970 let vector_input = vec!["01XZ-".to_string()];
1971 assert_eq!(
1972 string_array_to_value_array(&vector_input, ValueType::Vector),
1973 Some(vec![Value::Vector(LogicVec::from(vec![
1974 LogicVal::Zero,
1975 LogicVal::One,
1976 LogicVal::X,
1977 LogicVal::Z,
1978 LogicVal::DontCare,
1979 ]))])
1980 );
1981 }
1982
1983 #[test]
1984 fn string_array_to_value_array_rejects_invalid_vector_like_strings() {
1985 let bad_vector = vec!["01N".to_string()];
1986 assert_eq!(
1987 string_array_to_value_array(&bad_vector, ValueType::Vector),
1988 None
1989 );
1990 }
1991
1992 #[test]
1993 fn time_array_to_value_array_round_trips_through_demotion() {
1994 let times = vec![Time::Sim(12), Time::Suppress];
1995 let promoted = time_array_to_value_array(×);
1996 let demoted = value_array_to_time_array(&promoted).expect("time demotion should succeed");
1997 assert_eq!(demoted, times);
1998 }
1999
2000 #[test]
2001 fn strength_array_to_value_array_round_trips_through_demotion() {
2002 let strengths = vec![
2003 StrengthValue::new(LogicVal::One, Strength::StrongDrive, Strength::HiZ),
2004 StrengthValue::new(LogicVal::Zero, Strength::PullDrive, Strength::WeakDrive),
2005 ];
2006
2007 let promoted = strength_array_to_value_array(&strengths);
2008 let demoted =
2009 value_array_to_strength_array(&promoted).expect("strength demotion should succeed");
2010 assert_eq!(demoted, strengths);
2011 }
2012
2013 #[test]
2014 fn strength_value_display_renders_logic_and_drive_strengths() {
2015 let value = StrengthValue::new(LogicVal::One, Strength::StrongDrive, Strength::HiZ);
2016
2017 assert_eq!(value.to_string(), "1 (strong0, highz1)");
2018 }
2019
2020 #[test]
2021 fn scalar_vector_to_string_renders_expected_symbols() {
2022 let values = vec![
2023 LogicVal::Zero,
2024 LogicVal::One,
2025 LogicVal::X,
2026 LogicVal::Z,
2027 LogicVal::DontCare,
2028 ];
2029
2030 assert_eq!(LogicVec::from(values).to_string(), "01XZ-");
2031 }
2032
2033 #[test]
2034 fn value_type_display_has_human_readable_labels() {
2035 assert_eq!(ValueType::ShortInt.to_string(), "Short Integer");
2036 }
2037
2038 #[test]
2039 fn scalar_vector_to_uint64_converts_binary_bits() {
2040 let bits = vec![LogicVal::One, LogicVal::Zero, LogicVal::One, LogicVal::One];
2041 assert_eq!(scalar_vector_to_uint64(&bits), Some(0b1011));
2042 }
2043
2044 #[test]
2045 fn scalar_vector_to_uint64_all_zeros() {
2046 let bits = vec![LogicVal::Zero; 8];
2047 assert_eq!(scalar_vector_to_uint64(&bits), Some(0));
2048 }
2049
2050 #[test]
2051 fn scalar_vector_to_uint64_returns_none_for_x_bit() {
2052 let bits = vec![LogicVal::One, LogicVal::X, LogicVal::Zero];
2053 assert_eq!(scalar_vector_to_uint64(&bits), None);
2054 }
2055
2056 #[test]
2057 fn scalar_vector_to_uint64_returns_none_for_z_bit() {
2058 let bits = vec![LogicVal::Zero, LogicVal::Z];
2059 assert_eq!(scalar_vector_to_uint64(&bits), None);
2060 }
2061
2062 #[test]
2063 fn scalar_vector_to_uint64_returns_none_for_over_64_bits() {
2064 let bits = vec![LogicVal::Zero; 65];
2065 assert_eq!(scalar_vector_to_uint64(&bits), None);
2066 }
2067
2068 #[test]
2069 fn scalar_vector_to_uint64_accepts_exactly_64_bits() {
2070 let mut bits = vec![LogicVal::Zero; 63];
2071 bits.push(LogicVal::One);
2072 assert_eq!(scalar_vector_to_uint64(&bits), Some(1));
2073 }
2074
2075 #[cfg(feature = "verilator")]
2076 mod verilator_tests {
2077 use crate::{
2078 string_array_to_value_array, value_array_to_string_array, LogicVal, LogicVec, Value,
2079 ValueType,
2080 };
2081
2082 #[test]
2083 fn value_array_to_string_array_string_rejects_vector_variants() {
2084 let raw_two_state_values = vec![Value::RawTwoState(vec![true, false])];
2085 assert_eq!(
2086 value_array_to_string_array(&raw_two_state_values, ValueType::String),
2087 None
2088 );
2089
2090 let raw_four_state_values = vec![Value::RawFourState(LogicVec::from(vec![
2091 LogicVal::One,
2092 LogicVal::DontCare,
2093 ]))];
2094 assert_eq!(
2095 value_array_to_string_array(&raw_four_state_values, ValueType::String),
2096 None
2097 );
2098 }
2099
2100 #[test]
2101 fn value_array_to_string_array_supports_vector_like_formats_directly() {
2102 let raw_two_state_values = vec![Value::RawTwoState(vec![true, false, true, true])];
2103 assert_eq!(
2104 value_array_to_string_array(&raw_two_state_values, ValueType::RawTwoState),
2105 Some(vec!["1011".to_string()])
2106 );
2107
2108 let raw_four_state_values = vec![Value::RawFourState(LogicVec::from(vec![
2109 LogicVal::One,
2110 LogicVal::Zero,
2111 LogicVal::DontCare,
2112 ]))];
2113 assert_eq!(
2114 value_array_to_string_array(&raw_four_state_values, ValueType::RawFourState),
2115 Some(vec!["10-".to_string()])
2116 );
2117 }
2118
2119 #[test]
2120 fn string_array_to_value_array_supports_vector_like_formats() {
2121 let raw_two_state_input = vec!["10110".to_string()];
2122 assert_eq!(
2123 string_array_to_value_array(&raw_two_state_input, ValueType::RawTwoState),
2124 Some(vec![Value::RawTwoState(vec![
2125 true, false, true, true, false
2126 ])])
2127 );
2128
2129 let raw_four_state_input = vec!["10-".to_string()];
2130 assert_eq!(
2131 string_array_to_value_array(&raw_four_state_input, ValueType::RawFourState),
2132 Some(vec![Value::RawFourState(LogicVec::from(vec![
2133 LogicVal::One,
2134 LogicVal::Zero,
2135 LogicVal::DontCare,
2136 ]))])
2137 );
2138 }
2139
2140 #[test]
2141 fn string_array_to_value_array_rejects_invalid_vector_like_strings() {
2142 let bad_raw_two_state = vec!["10X".to_string()];
2143 assert_eq!(
2144 string_array_to_value_array(&bad_raw_two_state, ValueType::RawTwoState),
2145 None
2146 );
2147
2148 let bad_raw_four_state = vec!["10?".to_string()];
2149 assert_eq!(
2150 string_array_to_value_array(&bad_raw_four_state, ValueType::RawFourState),
2151 None
2152 );
2153 }
2154
2155 #[test]
2156 fn raw_two_state_display_renders_binary_string() {
2157 let value = Value::RawTwoState(vec![true, false, true, true, false]);
2158
2159 assert_eq!(value.to_string(), "10110");
2160 }
2161
2162 #[test]
2163 fn raw_four_state_display_renders_scalar_symbols() {
2164 let value = Value::RawFourState(LogicVec::from(vec![
2165 LogicVal::Zero,
2166 LogicVal::One,
2167 LogicVal::X,
2168 LogicVal::Z,
2169 LogicVal::DontCare,
2170 ]));
2171
2172 assert_eq!(value.to_string(), "01XZ-");
2173 }
2174
2175 #[test]
2176 fn value_type_display_has_human_readable_labels() {
2177 assert_eq!(ValueType::RawFourState.to_string(), "Raw Four-State Vector");
2178 assert_eq!(ValueType::ShortInt.to_string(), "Short Integer");
2179 }
2180 }
2181}