Skip to main content

vpi/
value.rs

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/// High-level value representation returned from or written to VPI objects.
14#[derive(Debug, Clone, PartialEq)]
15pub enum Value {
16    /// Binary string value.
17    BinStr(String),
18    /// Octal string value.
19    OctStr(String),
20    /// Hexadecimal string value.
21    HexStr(String),
22    /// Decimal string value.
23    DecStr(String),
24    /// 4-state scalar value.
25    Scalar(LogicVal),
26    /// 32-bit signed integer value.
27    Int(i32),
28    /// 64-bit floating-point value.
29    Real(f64),
30    /// Plain string value.
31    String(String),
32    /// Vector of scalar bits.
33    Vector(LogicVec),
34    /// Value with drive-strength information.
35    Strength(StrengthValue),
36    /// Time value.
37    Time(Time),
38    /// Raw object type value.
39    ///
40    /// This variant is used when the simulator returns `vpiObjTypeVal`
41    /// directly. When [`ValueType::ObjType`] is requested via
42    /// [`Handle::get_value`], the simulator may instead report a more specific
43    /// value format, in which case `get_value` returns the corresponding
44    /// concrete [`Value`] variant.
45    ObjType(i32),
46    /// Suppress value transfer.
47    Suppress,
48    /// 16-bit signed integer value.
49    ShortInt(i16),
50    /// 64-bit signed integer value.
51    LongInt(i64),
52    /// 32-bit floating-point value.
53    ShortReal(f32),
54    /// Raw 2-state packed bits.
55    #[cfg(feature = "verilator")]
56    RawTwoState(Vec<bool>), // Each bit is either 0 or 1
57    /// Raw 4-state packed bits.
58    #[cfg(feature = "verilator")]
59    RawFourState(LogicVec), // Each bit can be 0, 1, X, or Z
60}
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})"), // Placeholder
76            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)]
98/// VPI value format tags used with `vpi_get_value` and related APIs.
99pub enum ValueType {
100    /// Binary string format.
101    BinStr = vpi_sys::vpiBinStrVal,
102    /// Octal string format.
103    OctStr = vpi_sys::vpiOctStrVal,
104    /// Hexadecimal string format.
105    HexStr = vpi_sys::vpiHexStrVal,
106    /// Decimal string format.
107    DecStr = vpi_sys::vpiDecStrVal,
108    /// 4-state scalar format.
109    Scalar = vpi_sys::vpiScalarVal,
110    /// 32-bit signed integer format.
111    Int = vpi_sys::vpiIntVal,
112    /// 64-bit floating-point format.
113    Real = vpi_sys::vpiRealVal,
114    /// String format.
115    String = vpi_sys::vpiStringVal,
116    /// Vector-of-bits format.
117    Vector = vpi_sys::vpiVectorVal,
118    /// Scalar-plus-strength format.
119    Strength = vpi_sys::vpiStrengthVal,
120    /// Time format.
121    Time = vpi_sys::vpiTimeVal,
122    /// Request that the simulator choose the object's native value format.
123    ///
124    /// When used with [`Handle::get_value`], the simulator can replace this
125    /// request with the actual value format for the object, so the returned
126    /// [`Value`] is typically the corresponding concrete variant rather than
127    /// [`Value::ObjType`].
128    ObjType = vpi_sys::vpiObjTypeVal,
129    /// Suppress value transfer.
130    Suppress = vpi_sys::vpiSuppressVal,
131    /// 16-bit signed integer format.
132    ShortInt = vpi_sys::vpiShortIntVal,
133    /// 64-bit signed integer format.
134    LongInt = vpi_sys::vpiLongIntVal,
135    /// 32-bit floating-point format.
136    ShortReal = vpi_sys::vpiShortRealVal,
137    /// Raw packed 2-state vector format.
138    #[cfg(feature = "verilator")]
139    RawTwoState = vpi_sys::vpiRawTwoStateVal,
140    /// Raw packed 4-state vector format.
141    #[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)]
174/// Scalar logic value plus drive strengths.
175pub struct StrengthValue {
176    /// Scalar logic state carried by the value.
177    logic: LogicVal,
178    /// Drive strength applied when the logic resolves to `0`.
179    strength0: Strength,
180    /// Drive strength applied when the logic resolves to `1`.
181    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    /// Creates a scalar value with associated drive strengths.
196    #[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)]
221/// Drive-strength and charge encodings used by VPI.
222pub enum Strength {
223    /// Supply-strength drive.
224    SupplyDrive = vpi_sys::vpiSupplyDrive,
225    /// Strong drive strength.
226    StrongDrive = vpi_sys::vpiStrongDrive,
227    /// Pull drive strength.
228    PullDrive = vpi_sys::vpiPullDrive,
229    /// Large charge strength.
230    LargeCharge = vpi_sys::vpiLargeCharge,
231    /// Weak drive strength.
232    WeakDrive = vpi_sys::vpiWeakDrive,
233    /// Medium charge strength.
234    MediumCharge = vpi_sys::vpiMediumCharge,
235    /// Small charge strength.
236    SmallCharge = vpi_sys::vpiSmallCharge,
237    /// High-impedance strength.
238    HiZ = vpi_sys::vpiHiZ,
239}
240
241/// Delay mode used with `vpi_put_value`.
242#[repr(i32)]
243#[derive(Copy, Clone, Debug, PartialEq, Eq)]
244pub enum PutValueDelay {
245    /// Apply immediately.
246    NoDelay = vpi_sys::vpiNoDelay as i32,
247    /// Apply using inertial delay semantics.
248    Inertial = vpi_sys::vpiInertialDelay as i32,
249    /// Apply using transport delay semantics.
250    Transport = vpi_sys::vpiTransportDelay as i32,
251    /// Apply using pure transport delay semantics.
252    PureTransport = vpi_sys::vpiPureTransportDelay as i32,
253}
254
255struct PutValuePayload {
256    /// Raw VPI value record passed to `vpi_put_value`.
257    raw: vpi_sys::t_vpi_value,
258    /// Backing storage for string-valued payloads referenced by `raw`.
259    _string: Option<CString>,
260    /// Backing storage for vector-valued payloads referenced by `raw`.
261    _vector: Option<Vec<vpi_sys::t_vpi_vecval>>,
262    /// Backing storage for time-valued payloads referenced by `raw`.
263    _time: Option<Box<vpi_sys::s_vpi_time>>,
264    /// Backing storage for strength-valued payloads referenced by `raw`.
265    _strength: Option<Box<vpi_sys::t_vpi_strengthval>>,
266}
267
268#[cfg(feature = "value_array")]
269struct PutValueArrayPayload {
270    /// Raw VPI array value record passed to `vpi_put_value_array`.
271    raw: vpi_sys::t_vpi_arrayvalue,
272    /// Backing storage for integer-valued payloads referenced by `raw`.
273    _integers: Option<Vec<i32>>,
274    /// Backing storage for short-integer-valued payloads referenced by `raw`.
275    _shortints: Option<Vec<i16>>,
276    /// Backing storage for long-integer-valued payloads referenced by `raw`.
277    _longints: Option<Vec<i64>>,
278    /// Backing storage for time-valued payloads referenced by `raw`.
279    _times: Option<Vec<vpi_sys::t_vpi_time>>,
280    /// Backing storage for real-valued payloads referenced by `raw`.
281    _reals: Option<Vec<f64>>,
282    /// Backing storage for short-real-valued payloads referenced by `raw`.
283    _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    /// Flags controlling behavior of `vpi_put_value`.
584    pub struct PutValueFlags: u32 {
585        /// Return an event handle for the scheduled value update.
586        const ReturnEvent = vpi_sys::vpiReturnEvent;
587        /// Indicates that associated storage is managed by user code.
588        const UserAllocFlag = vpi_sys::vpiUserAllocFlag;
589        /// Restrict the update to a single value.
590        const OneValue = vpi_sys::vpiOneValue;
591        /// Disable propagation for the value update.
592        const PropagateOff = vpi_sys::vpiPropagateOff;
593    }
594}
595
596bitflags::bitflags! {
597    /// Flags controlling behavior of `vpi_put_value_array`.
598    pub struct PutValueArrayFlags: u32 {
599        /// Indicates that associated storage is managed by user code.
600        const UserAllocFlag = vpi_sys::vpiUserAllocFlag;
601        /// Restrict the update to a single value.
602        const OneValue = vpi_sys::vpiOneValue;
603        /// Disable propagation for the value update.
604        const PropagateOff = vpi_sys::vpiPropagateOff;
605    }
606}
607
608/// Decode a raw `t_vpi_value` into a high-level [`Value`].
609///
610/// `obj` is used for value formats that require object context (for example,
611/// vector width when decoding `vpiVectorVal`).
612#[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/// Demote a homogeneous [`Value`] array to [`String`] values.
674///
675/// Supported `format` values are [`ValueType::BinStr`], [`ValueType::OctStr`],
676/// [`ValueType::HexStr`], [`ValueType::DecStr`], [`ValueType::String`],
677/// [`ValueType::Vector`], [`ValueType::RawTwoState`], and
678/// [`ValueType::RawFourState`].
679///
680/// Returns `None` when `format` is not string-backed or when any entry does
681/// not match the requested `format` variant.
682#[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/// Demote a homogeneous [`Value`] array to `i32` values.
752///
753/// Every element must be [`Value::Int`]. Returns `None` if any element has a
754/// different variant.
755#[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/// Demote a homogeneous [`Value`] array to `i16` values.
769///
770/// Every element must be [`Value::ShortInt`]. Returns `None` if any element
771/// has a different variant.
772#[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/// Demote a homogeneous [`Value`] array to `i64` values.
786///
787/// Every element must be [`Value::LongInt`]. Returns `None` if any element has
788/// a different variant.
789#[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/// Demote a homogeneous [`Value`] array to `f64` values.
803///
804/// Every element must be [`Value::Real`]. Returns `None` if any element has a
805/// different variant.
806#[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/// Demote a homogeneous [`Value`] array to `f32` values.
820///
821/// Every element must be [`Value::ShortReal`]. Returns `None` if any element
822/// has a different variant.
823#[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/// Demote a homogeneous [`Value`] array to scalar values.
837///
838/// Every element must be [`Value::Scalar`]. Returns `None` if any element has
839/// a different variant.
840#[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/// Demote a homogeneous [`Value`] array to time values.
854///
855/// Every element must be [`Value::Time`]. Returns `None` if any element has a
856/// different variant.
857#[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/// Demote a homogeneous [`Value`] array to strength values.
871///
872/// Every element must be [`Value::Strength`]. Returns `None` if any element
873/// has a different variant.
874#[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/// Promote a [`String`] array to a homogeneous [`Value`] array.
888///
889/// Supported `format` values are [`ValueType::BinStr`], [`ValueType::OctStr`],
890/// [`ValueType::HexStr`], [`ValueType::DecStr`], [`ValueType::String`],
891/// [`ValueType::Vector`], [`ValueType::RawTwoState`], and
892/// [`ValueType::RawFourState`].
893///
894/// The produced variant is determined by `format`:
895/// - [`ValueType::BinStr`] -> [`Value::BinStr`]
896/// - [`ValueType::OctStr`] -> [`Value::OctStr`]
897/// - [`ValueType::HexStr`] -> [`Value::HexStr`]
898/// - [`ValueType::DecStr`] -> [`Value::DecStr`]
899/// - [`ValueType::String`] -> [`Value::String`]
900/// - [`ValueType::Vector`] -> [`Value::Vector`] (parsed via [`string_to_scalar_vector`])
901/// - [`ValueType::RawTwoState`] -> [`Value::RawTwoState`] (`0`/`1` only)
902/// - [`ValueType::RawFourState`] -> [`Value::RawFourState`] (parsed via [`string_to_scalar_vector`])
903///
904/// Returns `None` when `format` is not string-backed.
905#[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/// Promote an `i32` array to a homogeneous [`Value`] array.
946///
947/// Produces [`Value::Int`] for each element.
948#[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/// Promote an `i16` array to a homogeneous [`Value`] array.
954///
955/// Produces [`Value::ShortInt`] for each element.
956#[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/// Promote an `i64` array to a homogeneous [`Value`] array.
967///
968/// Produces [`Value::LongInt`] for each element.
969#[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/// Promote an `f64` array to a homogeneous [`Value`] array.
980///
981/// Produces [`Value::Real`] for each element.
982#[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/// Promote an `f32` array to a homogeneous [`Value`] array.
988///
989/// Produces [`Value::ShortReal`] for each element.
990#[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/// Promote a scalar array to a homogeneous [`Value`] array.
1001///
1002/// Produces [`Value::Scalar`] for each element.
1003#[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/// Promote a time array to a homogeneous [`Value`] array.
1009///
1010/// Produces [`Value::Time`] for each element.
1011#[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/// Promote a strength array to a homogeneous [`Value`] array.
1017///
1018/// Produces [`Value::Strength`] for each element.
1019#[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/// Convert a binary-encoded [`LogicVal`] slice (MSB at index 0) to a [`num_bigint::BigUint`].
1030///
1031/// Returns `None` if any element is not a definite binary value
1032/// ([`LogicVal::Zero`] or [`LogicVal::One`]).
1033/// Any `X`, `Z`, `H`, `L`, or `DontCare` bit causes `None` to be returned.
1034#[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/// Convert a `u64` to a binary-encoded [`Vec<LogicVal>`] (MSB at index 0).
1050///
1051/// The returned vector always contains exactly `bits` elements. If `value`
1052/// requires more than `bits` bits to represent, the most-significant bits are
1053/// silently truncated.
1054#[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/// Convert a binary-encoded [`LogicVal`] slice (MSB at index 0) to a `u64`.
1073///
1074/// Returns `None` if the slice contains more than 64 bits or if any element is
1075/// not a definite binary value ([`LogicVal::Zero`] or [`LogicVal::One`]).
1076/// Any `X`, `Z`, `H`, `L`, or `DontCare` bit causes `None` to be
1077/// returned.
1078#[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/// Convert a scalar vector into a compact string representation.
1097///
1098/// Each scalar is mapped to its Verilog-style character (`0`, `1`, `X`, `Z`,
1099/// `H`, `L`, `-`) in order (MSB at index 0).
1100#[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/// Convert a scalar string into a vector of scalar values.
1110///
1111/// Accepts Verilog-style scalar symbols: `0`, `1`, `X`, `Z`, `H`, `L`, `-`,
1112/// (also lowercase `x`, `z`, `h`, `l`). Returns `None` if any
1113/// character is not a supported scalar symbol.
1114#[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/// Convert a [`num_bigint::BigUint`] to a binary-encoded [`Vec<LogicVal>`] (MSB at index 0).
1135///
1136/// The returned vector always contains exactly `bits` elements. If `value`
1137/// requires more than `bits` bits to represent, the most-significant bits are
1138/// silently truncated.
1139#[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/// Convert an `i64` to a two's-complement-encoded [`Vec<LogicVal>`] (MSB at index 0).
1159///
1160/// The returned vector always contains exactly `bits` elements. If `bits` is
1161/// smaller than needed to represent the value, the most-significant bits are
1162/// silently truncated.
1163#[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/// Convert a two's-complement-encoded [`LogicVal`] slice (MSB at index 0) to an `i64`.
1174///
1175/// Returns `None` if the slice is empty, contains more than 64 bits, or if any
1176/// element is not a definite binary value ([`LogicVal::Zero`] or
1177/// [`LogicVal::One`]). Any `X`, `Z`, `H`, `L`, or `DontCare`
1178/// bit causes `None` to be returned.
1179#[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    // Sign-extend: if the MSB is 1, fill the upper bits.
1191    let shift = 64 - bits.len();
1192    Some((unsigned << shift) as i64 >> shift)
1193}
1194
1195/// Convert a [`num_bigint::BigInt`] to a two's-complement-encoded [`Vec<LogicVal>`]
1196/// (MSB at index 0).
1197///
1198/// The returned vector always contains exactly `bits` elements. If `bits` is
1199/// smaller than needed to represent the value, the most-significant bits are
1200/// silently truncated.
1201#[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    // Two's complement: for negative numbers, add 2^bits to get the unsigned representation.
1210    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/// Convert a two's-complement-encoded [`LogicVal`] slice (MSB at index 0) to a
1222/// [`num_bigint::BigInt`].
1223///
1224/// Returns `None` if the slice is empty or if any element is not a definite
1225/// binary value ([`LogicVal::Zero`] or [`LogicVal::One`]). Any `X`, `Z`,
1226/// `H`, `L`, or `DontCare` bit causes `None` to be returned.
1227#[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 MSB is One the value is negative: subtract 2^n.
1241    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    /// Writes a value to this handle using `vpi_put_value` with no delay.
1251    ///
1252    /// Returns a null handle when this handle is null. Otherwise returns the
1253    /// event handle returned by the simulator (which may also be null).
1254    #[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    /// Writes a value to this handle using `vpi_put_value` with optional scheduling.
1260    ///
1261    /// `time` is ignored when `delay` is [`PutValueDelay::NoDelay`].
1262    /// Returns a null handle when this handle is null. Otherwise returns the
1263    /// event handle returned by the simulator (which may also be null).
1264    #[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    /// Writes an integer value to this handle using `vpi_put_value` with no delay.
1296    ///
1297    /// Returns a null handle when this handle is null. Otherwise returns the
1298    /// event handle returned by the simulator (which may also be null).
1299    #[must_use]
1300    pub fn put_int_value(&self, value: i32) -> Handle {
1301        self.put_value(&Value::Int(value))
1302    }
1303
1304    /// Writes an array of values to this handle using `vpi_put_value_array`.
1305    ///
1306    /// The input slice must be homogeneous and currently supports integer,
1307    /// short integer, long integer, real, short real, and time values.
1308    /// Returns `false` for null handles or unsupported/mixed value slices.
1309    #[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    /// Writes an array of values to this handle using `vpi_put_value_array`.
1316    ///
1317    /// `start_index` selects the first array element to update.
1318    /// Returns `false` for null handles or unsupported/mixed value slices.
1319    #[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    /// Writes an array of values to this handle.
1351    ///
1352    /// This fallback implementation is used when the `put_value_array`
1353    /// feature is disabled and applies each value element-by-element using
1354    /// [`Handle::put_value`] on `handle_by_index(start_index + i)`.
1355    /// Returns `false` for null handles or when any indexed element is
1356    /// unavailable.
1357    #[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    /// Writes an array of values to this handle.
1364    ///
1365    /// This fallback implementation is used when the `put_value_array`
1366    /// feature is disabled and applies each value element-by-element using
1367    /// [`Handle::put_value`] on `handle_by_index(start_index + i)`.
1368    ///
1369    /// `start_index` selects the first array element to update.
1370    ///
1371    /// Note: `flags` are accepted for API compatibility but are ignored by
1372    /// this fallback path.
1373    ///
1374    /// Returns `false` for null handles, out-of-range indices, or arithmetic
1375    /// overflow while advancing indices.
1376    #[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    /// Reads a value from this handle in the requested format.
1410    ///
1411    /// If `format` is [`ValueType::ObjType`], the simulator may override the
1412    /// requested format with the object's native value format. In that case,
1413    /// this method returns the matching concrete [`Value`] variant rather than
1414    /// always returning [`Value::ObjType`].
1415    ///
1416    /// Returns `None` for null handles or unsupported formats.
1417    #[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    /// Retrieve an array of values from a Verilog object (e.g., memory array, packet array).
1431    ///
1432    /// This function calls `vpi_get_value_array` to fetch multiple values at once.
1433    /// It handles various value formats and automatically allocates the necessary memory.
1434    ///
1435    /// # Arguments
1436    /// * `format` - The format of values to retrieve (Int, Real, Time, etc.)
1437    ///
1438    /// # Returns
1439    /// * `Some(Vec<Value>)` - A vector of retrieved values
1440    /// * `None` - If the handle is null or the operation fails
1441    ///
1442    /// # Example
1443    /// ```ignore
1444    /// let mem = root.scan(vpi_sys::vpiMem)?;
1445    /// if let Some(values) = mem.get_value_array(ValueType::Int) {
1446    ///     for (i, val) in values.iter().enumerate() {
1447    ///         println!("Memory[{}] = {}", i, val);
1448    ///     }
1449    /// }
1450    /// ```
1451    #[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                // For vector arrays, each element needs to be read individually
1636                // as the size calculation is different (bits per element vs. total bits)
1637                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                // For scalar arrays
1647                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                // For unsupported types, return empty vector
1675                Some(Vec::new())
1676            }
1677        }
1678    }
1679
1680    /// Retrieve an array of values by reading each indexed element.
1681    ///
1682    /// This fallback implementation is used when the `value_array` feature is
1683    /// disabled. It resolves each element with `handle_by_index(i)` and reads
1684    /// it using [`Handle::get_value`].
1685    ///
1686    /// Returns `None` if the base handle is null, if the object size is not
1687    /// available, or if any element cannot be resolved/read.
1688    #[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    /// Returns whether this handle represents an array object.
1717    #[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(&times);
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}