From 9ade7765b55816708d286559884e2bc44081dd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20L=C3=A4ufer?= Date: Wed, 8 May 2024 09:34:06 -0400 Subject: [PATCH] stop using pub(crate) --- Cargo.toml | 2 +- src/fst.rs | 24 ++++++++++++------------ src/ghw/common.rs | 10 +++++----- src/ghw/hierarchy.rs | 6 +++--- src/ghw/mod.rs | 14 +++++++------- src/ghw/signals.rs | 2 +- src/hierarchy.rs | 38 +++++++++++++++++++------------------- src/signals.rs | 16 ++++++++-------- src/vcd.rs | 20 ++++++++++---------- src/wavemem.rs | 23 +++++++++-------------- 10 files changed, 75 insertions(+), 80 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6467d04..d5879ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "wellen" -version = "0.9.8" +version = "0.9.9" edition = "2021" authors = ["Kevin Laeufer "] description = "Fast VCD and FST library for waveform viewers written in Rust." diff --git a/src/fst.rs b/src/fst.rs index be5abaf..503870c 100644 --- a/src/fst.rs +++ b/src/fst.rs @@ -15,7 +15,7 @@ use std::io::{BufRead, Seek}; pub type Result = std::result::Result; -pub(crate) fn read_header( +pub fn read_header( filename: &str, _options: &LoadOptions, ) -> Result<(Hierarchy, ReadBodyContinuation)> { @@ -28,7 +28,7 @@ pub(crate) fn read_header( Ok((hierarchy, cont)) } -pub(crate) fn read_header_from_bytes( +pub fn read_header_from_bytes( bytes: Vec, _options: &LoadOptions, ) -> Result<(Hierarchy, ReadBodyContinuation)> { @@ -40,7 +40,7 @@ pub(crate) fn read_header_from_bytes( Ok((hierarchy, cont)) } -pub(crate) fn read_body(data: ReadBodyContinuation) -> Result<(SignalSource, TimeTable)> { +pub fn read_body(data: ReadBodyContinuation) -> Result<(SignalSource, TimeTable)> { match data.reader { Reader::File(reader) => { let time_table = reader.get_time_table().unwrap().to_vec(); @@ -59,7 +59,7 @@ pub(crate) fn read_body(data: ReadBodyContinuation) -> Result<(SignalSource, Tim } } -pub(crate) struct ReadBodyContinuation { +pub struct ReadBodyContinuation { reader: Reader, } @@ -291,14 +291,14 @@ impl SignalWriter { } #[inline] -pub(crate) fn get_len_and_meta(states: States, bits: u32) -> (usize, bool) { +pub fn get_len_and_meta(states: States, bits: u32) -> (usize, bool) { let len = (bits as usize).div_ceil(states.bits_in_a_byte()); let has_meta = (states != States::Two) && ((bits as usize) % states.bits_in_a_byte() == 0); (len, has_meta) } #[inline] -pub(crate) fn get_bytes_per_entry(len: usize, has_meta: bool) -> usize { +pub fn get_bytes_per_entry(len: usize, has_meta: bool) -> usize { if has_meta { len + 1 } else { @@ -350,7 +350,7 @@ fn expand_entries(from: States, to: States, old: &[u8], entries: usize, bits: u3 data } -pub(crate) fn push_zeros(vec: &mut Vec, len: usize) { +pub fn push_zeros(vec: &mut Vec, len: usize) { for _ in 0..len { vec.push(0); } @@ -435,7 +435,7 @@ fn convert_var_direction(tpe: FstVarDirection) -> VarDirection { /// GHDL does not seem to encode any actual information in the VHDL variable type. /// Variables are always Signal or None. -pub(crate) fn deal_with_vhdl_var_type(tpe: FstVhdlVarType, var_name: &str) { +pub fn deal_with_vhdl_var_type(tpe: FstVhdlVarType, var_name: &str) { if !matches!(tpe, FstVhdlVarType::None | FstVhdlVarType::Signal) { println!("INFO: detected a VHDL Var Type that is not Signal!: {tpe:?} for {var_name}"); } @@ -443,7 +443,7 @@ pub(crate) fn deal_with_vhdl_var_type(tpe: FstVhdlVarType, var_name: &str) { /// GHDL only uses a small combination of VCD variable and VHDL data types. /// Here we merge them together into a single VarType. -pub(crate) fn merge_vhdl_data_and_var_type(vcd: VarType, vhdl: FstVhdlDataType) -> VarType { +pub fn merge_vhdl_data_and_var_type(vcd: VarType, vhdl: FstVhdlDataType) -> VarType { match vhdl { FstVhdlDataType::None => vcd, FstVhdlDataType::Boolean => VarType::Boolean, @@ -512,7 +512,7 @@ fn convert_timescale(exponent: i8) -> Timescale { #[derive(Debug)] /// Represents an attribute which can from a FST or a VCD with extensions as generated by GTKWave or nvc. -pub(crate) enum Attribute { +pub enum Attribute { /// nvc: `misc 03 /home/oscar/test.vhdl 1` SourceLoc(HierarchyStringId, u64, bool), /// nvc: `misc 02 STD_LOGIC_VECTOR 1031` @@ -520,7 +520,7 @@ pub(crate) enum Attribute { Enum(EnumTypeId), } -pub(crate) fn parse_var_attributes( +pub fn parse_var_attributes( attributes: &mut Vec, mut var_type: VarType, var_name: &str, @@ -547,7 +547,7 @@ pub(crate) fn parse_var_attributes( Ok((type_name, var_type, enum_type)) } -pub(crate) fn parse_scope_attributes( +pub fn parse_scope_attributes( attributes: &mut Vec, h: &mut HierarchyBuilder, ) -> crate::vcd::Result<(Option, Option)> { diff --git a/src/ghw/common.rs b/src/ghw/common.rs index 69c60f6..43ed133 100644 --- a/src/ghw/common.rs +++ b/src/ghw/common.rs @@ -9,7 +9,7 @@ use std::num::NonZeroU32; use thiserror::Error; #[derive(Debug, Error)] -pub(crate) enum GhwParseError { +pub enum GhwParseError { #[error("[ghw] unsupported compression: {0}")] UnsupportedCompression(String), #[error("[ghw] unexpected header magic: {0}")] @@ -58,7 +58,7 @@ pub const GHW_END_CYCLE_SECTION: &[u8; 4] = b"ECY\x00"; pub const GHW_TAILER_LEN: usize = 12; -pub(crate) type Result = std::result::Result; +pub type Result = std::result::Result; pub fn read_directory(header: &HeaderData, input: &mut impl BufRead) -> Result> { let mut h = [0u8; 8]; @@ -83,12 +83,12 @@ pub fn read_directory(header: &HeaderData, input: &mut impl BufRead) -> Result Result<()> { +pub fn check_header_zeros(section: &'static str, header: &[u8]) -> Result<()> { if header.len() < 4 { return Err(GhwParseError::FailedToParseSection( section, diff --git a/src/ghw/hierarchy.rs b/src/ghw/hierarchy.rs index 36f99f0..a21851f 100644 --- a/src/ghw/hierarchy.rs +++ b/src/ghw/hierarchy.rs @@ -17,7 +17,7 @@ use std::collections::HashMap; use std::io::{BufRead, Seek, SeekFrom}; use std::num::NonZeroU32; -pub(crate) fn read_ghw_header(input: &mut impl BufRead) -> Result { +pub fn read_ghw_header(input: &mut impl BufRead) -> Result { // check for compression let mut comp_header = [0u8; 2]; input.read_exact(&mut comp_header)?; @@ -74,7 +74,7 @@ pub(crate) fn read_ghw_header(input: &mut impl BufRead) -> Result { /// The last 8 bytes of a finished, uncompressed file indicate where to find the directory which /// contains the offset of all sections. -pub(crate) fn try_read_directory( +pub fn try_read_directory( header: &HeaderData, input: &mut (impl BufRead + Seek), ) -> Result>> { @@ -108,7 +108,7 @@ pub(crate) fn try_read_directory( } /// Parses the beginning of the GHW file until the end of the hierarchy. -pub(crate) fn read_hierarchy( +pub fn read_hierarchy( header: &HeaderData, input: &mut impl BufRead, ) -> Result<(GhwDecodeInfo, Hierarchy)> { diff --git a/src/ghw/mod.rs b/src/ghw/mod.rs index c21daee..5eaec12 100644 --- a/src/ghw/mod.rs +++ b/src/ghw/mod.rs @@ -6,7 +6,7 @@ mod common; mod hierarchy; mod signals; -pub(crate) use crate::ghw::common::GhwParseError; +pub use crate::ghw::common::GhwParseError; use crate::ghw::common::{GhwDecodeInfo, HeaderData}; use crate::signals::SignalSource; use crate::viewers::ProgressCount; @@ -15,16 +15,16 @@ use std::io::{BufRead, Seek, SeekFrom}; use std::sync::atomic::Ordering; /// Checks header to see if we are dealing with a GHW file. -pub(crate) fn is_ghw(input: &mut (impl BufRead + Seek)) -> bool { +pub fn is_ghw(input: &mut (impl BufRead + Seek)) -> bool { let is_ghw = hierarchy::read_ghw_header(input).is_ok(); // try to reset input let _ = input.seek(SeekFrom::Start(0)); is_ghw } -pub(crate) type Result = std::result::Result; +pub type Result = std::result::Result; -pub(crate) fn read_header( +pub fn read_header( filename: &str, options: &LoadOptions, ) -> Result<(Hierarchy, ReadBodyContinuation, u64)> { @@ -39,7 +39,7 @@ pub(crate) fn read_header( Ok((hierarchy, cont, body_len)) } -pub(crate) fn read_header_from_bytes( +pub fn read_header_from_bytes( bytes: Vec, options: &LoadOptions, ) -> Result<(Hierarchy, ReadBodyContinuation, u64)> { @@ -53,7 +53,7 @@ pub(crate) fn read_header_from_bytes( Ok((hierarchy, cont, body_len)) } -pub(crate) fn read_body( +pub fn read_body( data: ReadBodyContinuation, hierarchy: &Hierarchy, progress: Option, @@ -77,7 +77,7 @@ pub(crate) fn read_body( Ok((source, time_table)) } -pub(crate) struct ReadBodyContinuation { +pub struct ReadBodyContinuation { header: HeaderData, decode_info: GhwDecodeInfo, input: Input, diff --git a/src/ghw/signals.rs b/src/ghw/signals.rs index 4bd92ff..bc4d33d 100644 --- a/src/ghw/signals.rs +++ b/src/ghw/signals.rs @@ -9,7 +9,7 @@ use crate::{Hierarchy, SignalRef, TimeTable}; use std::io::BufRead; /// Reads the GHW signal values. `input` should be advanced until right after the end of hierarchy -pub(crate) fn read_signals( +pub fn read_signals( header: &HeaderData, decode_info: GhwDecodeInfo, hierarchy: &Hierarchy, diff --git a/src/hierarchy.rs b/src/hierarchy.rs index 1e0b3d2..619ab61 100644 --- a/src/hierarchy.rs +++ b/src/hierarchy.rs @@ -97,7 +97,7 @@ impl Default for ScopeRef { #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] -pub(crate) struct HierarchyStringId(NonZeroU32); +pub struct HierarchyStringId(NonZeroU32); impl HierarchyStringId { #[inline] @@ -202,7 +202,7 @@ pub enum VarDirection { } impl VarDirection { - pub(crate) fn vcd_default() -> Self { + pub fn vcd_default() -> Self { VarDirection::Unknown } } @@ -212,7 +212,7 @@ impl VarDirection { pub struct VarIndex(NonZeroU64); impl VarIndex { - pub(crate) fn new(msb: i32, lsb: i32) -> Self { + pub fn new(msb: i32, lsb: i32) -> Self { let value = ((msb as u64) << 32) | ((lsb as u64) & (u32::MAX as u64)); Self(NonZeroU64::new(value + 1).unwrap()) } @@ -282,10 +282,10 @@ pub struct Var { /// slices of other signals, and thus we only save the data of the larger signal. #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] -pub(crate) struct SignalSlice { - pub(crate) msb: u32, - pub(crate) lsb: u32, - pub(crate) sliced_signal: SignalRef, +pub struct SignalSlice { + pub msb: u32, + pub lsb: u32, + pub sliced_signal: SignalRef, } const SCOPE_SEPARATOR: char = '.'; @@ -359,7 +359,7 @@ impl Var { _ => false, } } - pub(crate) fn signal_tpe(&self) -> SignalType { + pub fn signal_tpe(&self) -> SignalType { self.signal_tpe } } @@ -551,7 +551,7 @@ impl<'a> Iterator for HierarchyScopeRefIterator<'a> { #[derive(Debug, PartialEq, Copy, Clone)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] -pub(crate) struct SourceLocId(NonZeroU16); +pub struct SourceLocId(NonZeroU16); impl SourceLocId { #[inline] @@ -576,7 +576,7 @@ struct SourceLoc { #[derive(Debug, PartialEq, Copy, Clone)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] -pub(crate) struct EnumTypeId(NonZeroU16); +pub struct EnumTypeId(NonZeroU16); impl EnumTypeId { #[inline] @@ -737,18 +737,18 @@ impl Hierarchy { } impl Hierarchy { - pub(crate) fn num_unique_signals(&self) -> usize { + pub fn num_unique_signals(&self) -> usize { self.signal_idx_to_var.len() } /// Retrieves the length of a signal identified by its id by looking up a /// variable that refers to the signal. - pub(crate) fn get_signal_tpe(&self, signal_idx: SignalRef) -> Option { + pub fn get_signal_tpe(&self, signal_idx: SignalRef) -> Option { let var_id = (*self.signal_idx_to_var.get(signal_idx.index())?)?; Some(self.get(var_id).signal_tpe) } - pub(crate) fn get_slice_info(&self, signal_idx: SignalRef) -> Option { + pub fn get_slice_info(&self, signal_idx: SignalRef) -> Option { self.slices.get(&signal_idx).copied() } } @@ -822,7 +822,7 @@ pub struct HierarchyBuilder { const EMPTY_STRING: HierarchyStringId = HierarchyStringId(unsafe { NonZeroU32::new_unchecked(1) }); impl HierarchyBuilder { - pub(crate) fn new(file_type: FileFormat) -> Self { + pub fn new(file_type: FileFormat) -> Self { // we start with a fake entry in the scope stack to keep track of multiple items in the top scope let scope_stack = vec![ScopeStackEntry { scope_id: usize::MAX, @@ -866,7 +866,7 @@ impl HierarchyBuilder { } } - pub(crate) fn add_string(&mut self, value: String) -> HierarchyStringId { + pub fn add_string(&mut self, value: String) -> HierarchyStringId { if value.is_empty() { return EMPTY_STRING; } @@ -877,11 +877,11 @@ impl HierarchyBuilder { sym } - pub(crate) fn get_str(&self, id: HierarchyStringId) -> &str { + pub fn get_str(&self, id: HierarchyStringId) -> &str { &self.strings[id.index()] } - pub(crate) fn add_source_loc( + pub fn add_source_loc( &mut self, path: HierarchyStringId, line: u64, @@ -896,7 +896,7 @@ impl HierarchyBuilder { sym } - pub(crate) fn add_enum_type( + pub fn add_enum_type( &mut self, name: HierarchyStringId, mapping: Vec<(HierarchyStringId, HierarchyStringId)>, @@ -1144,7 +1144,7 @@ impl HierarchyBuilder { self.meta.comments.push(comment); } - pub(crate) fn add_slice( + pub fn add_slice( &mut self, signal_ref: SignalRef, msb: u32, diff --git a/src/signals.rs b/src/signals.rs index b56cd38..ecc653d 100644 --- a/src/signals.rs +++ b/src/signals.rs @@ -64,7 +64,7 @@ impl<'a> SignalValue<'a> { } /// Returns the states per bit. Returns None if the value is a real or string. - pub(crate) fn states(&self) -> Option { + pub fn states(&self) -> Option { match self { SignalValue::Binary(_, _) => Some(States::Two), SignalValue::FourValue(_, _) => Some(States::Four), @@ -141,7 +141,7 @@ fn n_state_to_bit_string(states: States, data: &[u8], bits: u32) -> String { /// Specifies the encoding of a signal. #[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] -pub(crate) enum SignalEncoding { +pub enum SignalEncoding { /// Bitvector of length N (u32) with 2, 4 or 9 states. /// If `meta_byte` is `true`, each sequence of data bytes is preceded by a meta-byte indicating whether the states /// are reduced by 1 (Four -> Two, Nine -> Four) or by 2 (Nine -> Two). @@ -175,7 +175,7 @@ impl Debug for Signal { } impl Signal { - pub(crate) fn new_fixed_len( + pub fn new_fixed_len( idx: SignalRef, time_indices: Vec, encoding: SignalEncoding, @@ -195,7 +195,7 @@ impl Signal { } } - pub(crate) fn new_var_len( + pub fn new_var_len( idx: SignalRef, time_indices: Vec, strings: Vec, @@ -282,7 +282,7 @@ impl<'a> Iterator for SignalChangeIterator<'a> { } } -pub(crate) struct BitVectorBuilder { +pub struct BitVectorBuilder { max_states: States, bits: u32, len: usize, @@ -372,7 +372,7 @@ impl BitVectorBuilder { } } -pub(crate) fn slice_signal(id: SignalRef, signal: &Signal, msb: u32, lsb: u32) -> Signal { +pub fn slice_signal(id: SignalRef, signal: &Signal, msb: u32, lsb: u32) -> Signal { debug_assert!(msb >= lsb); if let SignalChangeData::FixedLength { encoding: SignalEncoding::BitVector { max_states, .. }, @@ -621,7 +621,7 @@ impl SignalChangeData { } } -pub(crate) trait SignalSourceImplementation { +pub trait SignalSourceImplementation { /// Loads new signals. /// Many implementations take advantage of loading multiple signals at a time. fn load_signals( @@ -639,7 +639,7 @@ pub struct SignalSource { } impl SignalSource { - pub(crate) fn new(inner: Box) -> Self { + pub fn new(inner: Box) -> Self { Self { inner } } diff --git a/src/vcd.rs b/src/vcd.rs index 9b6381d..5374644 100644 --- a/src/vcd.rs +++ b/src/vcd.rs @@ -16,7 +16,7 @@ use std::io::{BufRead, Seek}; use std::sync::atomic::Ordering; #[derive(Debug, thiserror::Error)] -pub(crate) enum VcdParseError { +pub enum VcdParseError { #[error("[vcd] failed to parse length: `{0}` for variable `{1}`")] VcdVarLengthParsing(String, String), #[error("[vcd] failed to parse variable name: `{0}`")] @@ -47,9 +47,9 @@ pub(crate) enum VcdParseError { Io(#[from] std::io::Error), } -pub(crate) type Result = std::result::Result; +pub type Result = std::result::Result; -pub(crate) fn read_header( +pub fn read_header( filename: &str, options: &LoadOptions, ) -> Result<(Hierarchy, ReadBodyContinuation, u64)> { @@ -67,7 +67,7 @@ pub(crate) fn read_header( Ok((hierarchy, cont, body_len)) } -pub(crate) fn read_header_from_bytes( +pub fn read_header_from_bytes( bytes: Vec, options: &LoadOptions, ) -> Result<(Hierarchy, ReadBodyContinuation, u64)> { @@ -83,7 +83,7 @@ pub(crate) fn read_header_from_bytes( Ok((hierarchy, cont, body_len)) } -pub(crate) struct ReadBodyContinuation { +pub struct ReadBodyContinuation { multi_thread: bool, header_len: usize, lookup: IdLookup, @@ -95,7 +95,7 @@ enum Input { File(memmap2::Mmap), } -pub(crate) fn read_body( +pub fn read_body( data: ReadBodyContinuation, hierarchy: &Hierarchy, progress: Option, @@ -308,7 +308,7 @@ fn read_hierarchy( /// 1. the variable name /// 2. the bit index /// 3. any extra scopes generated by a multidimensional arrays -pub(crate) fn parse_name(name: &[u8]) -> Result<(String, Option, Vec)> { +pub fn parse_name(name: &[u8]) -> Result<(String, Option, Vec)> { let last = match name.last() { // special case for empty name None => return Ok(("".to_string(), None, vec![])), @@ -687,7 +687,7 @@ impl VcdCmd { } /// Tries to guess whether this input could be a VCD by looking at the first token. -pub(crate) fn is_vcd(input: &mut (impl BufRead + Seek)) -> bool { +pub fn is_vcd(input: &mut (impl BufRead + Seek)) -> bool { let is_vcd = matches!(internal_is_vcd(input), Ok(true)); // try to reset input let _ = input.seek(std::io::SeekFrom::Start(0)); @@ -832,12 +832,12 @@ enum HeaderCmd<'a> { const MIN_CHUNK_SIZE: usize = 8 * 1024; #[inline] -pub(crate) fn usize_div_ceil(a: usize, b: usize) -> usize { +pub fn usize_div_ceil(a: usize, b: usize) -> usize { (a + b - 1) / b } #[inline] -pub(crate) fn u32_div_ceil(a: u32, b: u32) -> u32 { +pub fn u32_div_ceil(a: u32, b: u32) -> u32 { (a + b - 1) / b } diff --git a/src/wavemem.rs b/src/wavemem.rs index 770a62a..51976d3 100644 --- a/src/wavemem.rs +++ b/src/wavemem.rs @@ -321,7 +321,7 @@ fn load_fixed_len_signal( debug_assert_eq!(out.len(), time_indices.len() * bytes_per_entry); } -pub(crate) fn check_if_changed_and_truncate(bytes_per_entry: usize, out: &mut Vec) -> bool { +pub fn check_if_changed_and_truncate(bytes_per_entry: usize, out: &mut Vec) -> bool { let changed = if out.len() < 2 * bytes_per_entry { true } else { @@ -914,7 +914,7 @@ fn expand_special_vector_cases(value: &[u8], len: usize) -> Option> { #[derive(Debug, TryFromPrimitive, Clone, Copy, PartialEq)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] #[derive(Default)] -pub(crate) enum States { +pub enum States { #[default] Two = 0, Four = 1, @@ -931,13 +931,13 @@ impl States { States::Nine } } - pub(crate) fn join(a: Self, b: Self) -> Self { + pub fn join(a: Self, b: Self) -> Self { let num = std::cmp::max(a as u8, b as u8); Self::try_from_primitive(num).unwrap() } /// Returns how many bits are needed in order to encode one bit of state. #[inline] - pub(crate) fn bits(&self) -> usize { + pub fn bits(&self) -> usize { match self { States::Two => 1, States::Four => 2, @@ -946,7 +946,7 @@ impl States { } #[inline] - pub(crate) fn mask(&self) -> u8 { + pub fn mask(&self) -> u8 { match self { States::Two => 0x1, States::Four => 0x3, @@ -956,7 +956,7 @@ impl States { /// Returns how many signal bits can be encoded in a u8. #[inline] - pub(crate) fn bits_in_a_byte(&self) -> usize { + pub fn bits_in_a_byte(&self) -> usize { 8 / self.bits() } } @@ -1024,7 +1024,7 @@ fn compress_template( } #[inline] -pub(crate) fn check_states(value: &[u8]) -> Option { +pub fn check_states(value: &[u8]) -> Option { let mut union = 0; for cc in value.iter() { union |= bit_char_to_num(*cc)?; @@ -1033,7 +1033,7 @@ pub(crate) fn check_states(value: &[u8]) -> Option { } #[inline] -pub(crate) fn bit_char_to_num(value: u8) -> Option { +pub fn bit_char_to_num(value: u8) -> Option { match value { // Value shared with 2 and 4-state logic b'0' | b'1' => Some(value - b'0'), // strong 0 / strong 1 @@ -1063,12 +1063,7 @@ fn try_write_1_bit_9_state(time_index_delta: u16, value: u8, data: &mut Vec) } #[inline] -pub(crate) fn write_n_state( - states: States, - value: &[u8], - data: &mut Vec, - meta_data: Option, -) { +pub fn write_n_state(states: States, value: &[u8], data: &mut Vec, meta_data: Option) { let states_bits = states.bits(); debug_assert!(states_bits == 1 || states_bits == 2 || states_bits == 4); let bits = value.len() * states_bits;