param: good enough parsing of bitfields
This commit is contained in:
parent
da80ff1d9a
commit
15dd0b2cb8
28
Cargo.lock
generated
28
Cargo.lock
generated
|
@ -114,6 +114,14 @@ dependencies = [
|
||||||
"syn 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
|
@ -395,6 +403,7 @@ dependencies = [
|
||||||
"nom 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nom 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"strum_macros 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -463,6 +472,17 @@ name = "strsim"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
|
@ -481,6 +501,11 @@ dependencies = [
|
||||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
@ -540,6 +565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28"
|
"checksum encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28"
|
||||||
"checksum flate2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42"
|
"checksum flate2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42"
|
||||||
"checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6"
|
"checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6"
|
||||||
|
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||||
"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
|
"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
|
||||||
"checksum indoc 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "79255cf29f5711995ddf9ec261b4057b1deb34e66c90656c201e41376872c544"
|
"checksum indoc 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "79255cf29f5711995ddf9ec261b4057b1deb34e66c90656c201e41376872c544"
|
||||||
"checksum indoc-impl 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "54554010aa3d17754e484005ea0022f1c93839aabc627c2c55f3d7b47206134c"
|
"checksum indoc-impl 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "54554010aa3d17754e484005ea0022f1c93839aabc627c2c55f3d7b47206134c"
|
||||||
|
@ -580,8 +606,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
"checksum smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
||||||
"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
|
"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
|
||||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
|
"checksum strum_macros 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c"
|
||||||
"checksum syn 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1b5e337360b1fae433c59fcafa0c6b77c605e92540afa5221a7b81a9eca91d"
|
"checksum syn 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1b5e337360b1fae433c59fcafa0c6b77c605e92540afa5221a7b81a9eca91d"
|
||||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
|
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||||
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||||
"checksum unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "63f18aa3b0e35fed5a0048f029558b1518095ffe2a0a31fb87c93dece93a4993"
|
"checksum unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "63f18aa3b0e35fed5a0048f029558b1518095ffe2a0a31fb87c93dece93a4993"
|
||||||
|
|
|
@ -18,6 +18,7 @@ flate2 = "1.0"
|
||||||
nom = "5"
|
nom = "5"
|
||||||
num-bigint = "0.2"
|
num-bigint = "0.2"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
|
strum_macros = "0.18"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["bindings/python"]
|
members = ["bindings/python"]
|
||||||
|
|
|
@ -222,7 +222,7 @@ fn cmd_param(args: &ArgMatches) -> i32 {
|
||||||
match unpackers::paramdef::load_paramdef_file(paramdef_path) {
|
match unpackers::paramdef::load_paramdef_file(paramdef_path) {
|
||||||
Ok(paramdef) => {
|
Ok(paramdef) => {
|
||||||
match unpackers::param::load_param_file(file_path, Some(¶mdef)) {
|
match unpackers::param::load_param_file(file_path, Some(¶mdef)) {
|
||||||
Ok(param) => { unpackers::param::print_param(¶m); 0 }
|
Ok(param) => { unpackers::param::print_param_with_def(¶m, ¶mdef); 0 }
|
||||||
Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 }
|
Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,7 +230,7 @@ fn cmd_param(args: &ArgMatches) -> i32 {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match unpackers::param::load_param_file(file_path, None) {
|
match unpackers::param::load_param_file(file_path, None) {
|
||||||
Ok(param) => { unpackers::param::print_param_no_data(¶m); 0 }
|
Ok(param) => { unpackers::param::print_param(¶m); 0 }
|
||||||
Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 }
|
Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::fmt::{self, Debug};
|
||||||
|
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
use nom::bytes::complete::take;
|
use nom::bytes::complete::take;
|
||||||
use nom::multi::count;
|
use nom::multi::count;
|
||||||
|
@ -6,7 +8,7 @@ use nom::sequence::tuple;
|
||||||
|
|
||||||
use crate::parsers::common::{sjis_to_string, take_cstring, take_cstring_from, VarSizeInt};
|
use crate::parsers::common::{sjis_to_string, take_cstring, take_cstring_from, VarSizeInt};
|
||||||
use crate::parsers::paramdef;
|
use crate::parsers::paramdef;
|
||||||
use crate::utils::bin::has_flag;
|
use crate::utils::bin::{has_flag, mask};
|
||||||
|
|
||||||
const FLAGS2D_UNK1: u8 = 0b00000001;
|
const FLAGS2D_UNK1: u8 = 0b00000001;
|
||||||
const FLAGS2D_32B_OFS_DATA: u8 = 0b00000010;
|
const FLAGS2D_32B_OFS_DATA: u8 = 0b00000010;
|
||||||
|
@ -104,7 +106,35 @@ pub struct ParamRow {
|
||||||
pub ofs_data: VarSizeInt,
|
pub ofs_data: VarSizeInt,
|
||||||
pub ofs_name: VarSizeInt,
|
pub ofs_name: VarSizeInt,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<ParamRowValue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(strum_macros::IntoStaticStr)]
|
||||||
|
pub enum ParamRowValue {
|
||||||
|
S8(i8), U8(u8), S16(i16), U16(u16), S32(i32), U32(u32), F32(f32), UNK(Vec<u8>)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for ParamRowValue {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let name: &str = self.into();
|
||||||
|
write!(f, "{}: {}", name, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Could be probably be done better with a macro...
|
||||||
|
impl fmt::Display for ParamRowValue {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ParamRowValue::S8(i) => fmt::Display::fmt(&i, f),
|
||||||
|
ParamRowValue::U8(i) => fmt::Display::fmt(&i, f),
|
||||||
|
ParamRowValue::S16(i) => fmt::Display::fmt(&i, f),
|
||||||
|
ParamRowValue::U16(i) => fmt::Display::fmt(&i, f),
|
||||||
|
ParamRowValue::S32(i) => fmt::Display::fmt(&i, f),
|
||||||
|
ParamRowValue::U32(i) => fmt::Display::fmt(&i, f),
|
||||||
|
ParamRowValue::F32(i) => fmt::Display::fmt(&i, f),
|
||||||
|
ParamRowValue::UNK(i) => fmt::Debug::fmt(&i, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_row<'a>(i: &'a[u8], header: &ParamHeader) -> IResult<&'a[u8], ParamRow> {
|
fn parse_row<'a>(i: &'a[u8], header: &ParamHeader) -> IResult<&'a[u8], ParamRow> {
|
||||||
|
@ -122,6 +152,83 @@ fn parse_row<'a>(i: &'a[u8], header: &ParamHeader) -> IResult<&'a[u8], ParamRow>
|
||||||
Ok((i, ParamRow { id, ofs_data, ofs_name, name: None, data: vec!() }))
|
Ok((i, ParamRow { id, ofs_data, ofs_name, name: None, data: vec!() }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_row_data<'a>(
|
||||||
|
i: &'a[u8],
|
||||||
|
header: &ParamHeader,
|
||||||
|
paramdef: ¶mdef::Paramdef
|
||||||
|
) -> IResult<&'a[u8], Vec<ParamRowValue>> {
|
||||||
|
let use_be = header.use_be();
|
||||||
|
let mut data = vec!();
|
||||||
|
let mut bitfield = 0u16; // Current bitfield being parsed. u16 is largest handled type.
|
||||||
|
let mut remaining_bits = 0; // Remaining bits in bitfield.
|
||||||
|
let mut data_slice = i;
|
||||||
|
for field in ¶mdef.fields {
|
||||||
|
let bit_size = field.bit_size();
|
||||||
|
let value = if bit_size == 0 {
|
||||||
|
let (rest, value) = parse_row_value(data_slice, &field.display_type,
|
||||||
|
field.byte_count as usize, use_be)?;
|
||||||
|
data_slice = rest;
|
||||||
|
remaining_bits = 0;
|
||||||
|
value
|
||||||
|
} else {
|
||||||
|
// Bitfield parsing. If it's the first bitfield in a series, get the containing bytes
|
||||||
|
// in the bitfield var.
|
||||||
|
if remaining_bits == 0 {
|
||||||
|
let (rest, bf) = take(field.byte_count as usize)(data_slice)?;
|
||||||
|
bitfield = match field.display_type.as_str() {
|
||||||
|
"u8" => { remaining_bits = 8; le_u8(bf).map(|(_, v)| v as u16)? }
|
||||||
|
"dummy8" => { remaining_bits = 8; le_u8(bf).map(|(_, v)| v as u16)? }
|
||||||
|
"u16" => {
|
||||||
|
remaining_bits = 16;
|
||||||
|
(if use_be { be_u16 } else { le_u16 }) (bf) .map(|(_, v)| v)?
|
||||||
|
}
|
||||||
|
e => panic!("Unhandled PARAMDEF type {}", e),
|
||||||
|
};
|
||||||
|
data_slice = rest;
|
||||||
|
}
|
||||||
|
// Parse masked bits.
|
||||||
|
let value = bitfield & mask(bit_size as usize) as u16;
|
||||||
|
// Shift bitfield so next values can be parsed directly with a bitmask.
|
||||||
|
bitfield >>= bit_size;
|
||||||
|
remaining_bits -= bit_size;
|
||||||
|
match field.display_type.as_str() {
|
||||||
|
"u8" => ParamRowValue::U8(value as u8),
|
||||||
|
"dummy8" => ParamRowValue::U8(value as u8),
|
||||||
|
"u16" => ParamRowValue::U16(value),
|
||||||
|
e => panic!("Unhandled PARAMDEF type {}", e),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
data.push(value);
|
||||||
|
}
|
||||||
|
Ok((i, data))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_row_value<'a>(
|
||||||
|
i: &'a[u8],
|
||||||
|
type_str: &str,
|
||||||
|
num_bytes: usize,
|
||||||
|
use_be: bool
|
||||||
|
) -> IResult<&'a[u8], ParamRowValue> {
|
||||||
|
Ok(match type_str {
|
||||||
|
"s8" => le_i8(i)
|
||||||
|
.map(|(i, v)| (i, ParamRowValue::S8(v)))?,
|
||||||
|
"u8" => le_u8(i)
|
||||||
|
.map(|(i, v)| (i, ParamRowValue::U8(v)))?,
|
||||||
|
"s16" => (if use_be { be_i16 } else { le_i16 }) (i)
|
||||||
|
.map(|(i, v)| (i, ParamRowValue::S16(v)))?,
|
||||||
|
"u16" => (if use_be { be_u16 } else { le_u16 }) (i)
|
||||||
|
.map(|(i, v)| (i, ParamRowValue::U16(v)))?,
|
||||||
|
"s32" => (if use_be { be_i32 } else { le_i32 }) (i)
|
||||||
|
.map(|(i, v)| (i, ParamRowValue::S32(v)))?,
|
||||||
|
"u32" => (if use_be { be_u32 } else { le_u32 }) (i)
|
||||||
|
.map(|(i, v)| (i, ParamRowValue::U32(v)))?,
|
||||||
|
"f32" => (if use_be { be_f32 } else { le_f32 }) (i)
|
||||||
|
.map(|(i, v)| (i, ParamRowValue::F32(v)))?,
|
||||||
|
_ => take(num_bytes)(i)
|
||||||
|
.map(|(i, v)| (i, ParamRowValue::UNK(v.to_vec())))?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Param {
|
pub struct Param {
|
||||||
pub header: ParamHeader,
|
pub header: ParamHeader,
|
||||||
|
@ -151,14 +258,16 @@ pub fn parse<'a>(i: &'a[u8], paramdef: Option<¶mdef::Paramdef>) -> IResult<&
|
||||||
}
|
}
|
||||||
|
|
||||||
if paramdef.is_some() {
|
if paramdef.is_some() {
|
||||||
let row_size = paramdef.unwrap().row_size();
|
let def = paramdef.unwrap();
|
||||||
|
let row_size = def.row_size();
|
||||||
for row in &mut rows {
|
for row in &mut rows {
|
||||||
let ofs_data = row.ofs_data.u64_if(header.has_u64_ofs_data()) as usize;
|
let ofs_data = row.ofs_data.u64_if(header.has_u64_ofs_data()) as usize;
|
||||||
if ofs_data == 0 {
|
if ofs_data == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let ofs_data_end = ofs_data + row_size;
|
let ofs_data_end = ofs_data + row_size;
|
||||||
row.data = full_file[ofs_data..ofs_data_end].to_vec();
|
let (_, data) = parse_row_data(&full_file[ofs_data..ofs_data_end], &header, &def)?;
|
||||||
|
row.data = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub fn load_param(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Print a PARAM's name and number of rows.
|
||||||
fn print_param_intro(param: ¶m::Param) {
|
fn print_param_intro(param: ¶m::Param) {
|
||||||
println!(
|
println!(
|
||||||
"{} -- {}",
|
"{} -- {}",
|
||||||
|
@ -43,16 +44,23 @@ fn print_param_intro(param: ¶m::Param) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_param_no_data(param: ¶m::Param) {
|
/// Print simple information about a PARAM.
|
||||||
print_param_intro(param);
|
|
||||||
for row in ¶m.rows {
|
|
||||||
println!(" - [{}] {}", row.id, row.name.as_ref().unwrap_or(&String::from("<noname>")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print_param(param: ¶m::Param) {
|
pub fn print_param(param: ¶m::Param) {
|
||||||
print_param_intro(param);
|
print_param_intro(param);
|
||||||
for row in ¶m.rows {
|
for row in ¶m.rows {
|
||||||
println!("{:?}", row);
|
println!(" - [{}] {}", row.id, row.name.as_ref().unwrap_or(&String::from("<noname>")));
|
||||||
|
if row.data.len() > 0 {
|
||||||
|
println!(" {:?}", row.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print a PARAM's data using PARAMDEF fields.
|
||||||
|
pub fn print_param_with_def(param: ¶m::Param, paramdef: ¶mdef::Paramdef) {
|
||||||
|
print_param_intro(param);
|
||||||
|
for row in ¶m.rows {
|
||||||
|
|
||||||
|
println!("{:?}", row);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,11 @@ pub fn has_flag(i: u8, flag: u8) -> bool {
|
||||||
i & flag == flag
|
i & flag == flag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a mask for this number of bits.
|
||||||
|
pub fn mask(bit_size: usize) -> usize {
|
||||||
|
(1 << bit_size) - 1
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -16,4 +21,13 @@ mod test {
|
||||||
assert!(has_flag(0x80, 0x80));
|
assert!(has_flag(0x80, 0x80));
|
||||||
assert!(!has_flag(0x80, 0x40));
|
assert!(!has_flag(0x80, 0x40));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mask() {
|
||||||
|
assert_eq!(mask(1), 0b00000001);
|
||||||
|
assert_eq!(mask(2), 0b00000011);
|
||||||
|
assert_eq!(mask(4), 0b00001111);
|
||||||
|
assert_eq!(mask(8), 0b11111111);
|
||||||
|
assert_eq!(mask(15), 0b01111111_11111111);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue