Switched to a 120 max width.

This commit is contained in:
Filipe Rodrigues 2021-04-26 18:07:33 +01:00
parent 443c6f6c38
commit 53963b5a7e
83 changed files with 958 additions and 347 deletions

View File

@ -26,7 +26,13 @@ pub fn proxy_sentinel_derive(input: proc_macro::TokenStream) -> proc_macro::Toke
let mut wrapper_type = None;
for attr in &input.attrs {
match attr.parse_meta() {
Ok(syn::Meta::List(list)) if list.path.get_ident().map(|ident| ident == "proxy_sentinel").unwrap_or(false) => {
Ok(syn::Meta::List(list))
if list
.path
.get_ident()
.map(|ident| ident == "proxy_sentinel")
.unwrap_or(false) =>
{
for nested_attr in &list.nested {
match nested_attr {
syn::NestedMeta::Meta(syn::Meta::NameValue(name_value)) => match name_value.path.get_ident() {
@ -46,7 +52,8 @@ pub fn proxy_sentinel_derive(input: proc_macro::TokenStream) -> proc_macro::Toke
let sentinel_value = sentinel_value.expect("You must supply a sentinel value via `proxy_sentinel(value = ...)`");
let wrapper_type = wrapper_type.expect("You must supply the wrapper type via `proxy_sentinel(wrapper_type = ...)`");
// TODO: Do this better, it's awful
let wrapper_type: syn::TypePath = syn::parse_str(&wrapper_type.to_token_stream().to_string().trim_matches('"')).expect("");
let wrapper_type: syn::TypePath =
syn::parse_str(&wrapper_type.to_token_stream().to_string().trim_matches('"')).expect("");
//let wrapper_type = syn::parse_macro_input!(wrapper_type_token_stream as );
let struct_name = input.ident;

View File

@ -13,7 +13,9 @@ macro_rules! derive_bytes_split {
#[allow(clippy::ptr_offset_with_cast)] // `arrayref` does it
impl $crate::Bytes for $T {
type ByteArray = [u8; {0 $( + <<$U as ByteOrderExt<$crate::byteorder::$BYTEORDER>>::ByteArray as ByteArray>::SIZE )*}];
type ByteArray = [u8;
{0 $( + <<$U as ByteOrderExt<$crate::byteorder::$BYTEORDER>>::ByteArray as ByteArray>::SIZE )*}
];
type FromError = !;
type ToError = !;

View File

@ -1,6 +1,13 @@
#![doc(include = "lib.md")]
// Features
#![feature(never_type, stmt_expr_attributes, unwrap_infallible, format_args_capture, array_methods, external_doc)]
#![feature(
never_type,
stmt_expr_attributes,
unwrap_infallible,
format_args_capture,
array_methods,
external_doc
)]
// Lints
#![warn(clippy::restriction, clippy::pedantic, clippy::nursery)]
// We'll disable the ones we don't need

View File

@ -40,7 +40,10 @@ impl Sector {
subheader,
};
Ok(Self { header, data: data.into() })
Ok(Self {
header,
data: data.into(),
})
}
}

View File

@ -84,8 +84,12 @@ impl Bytes for Header {
*bytes.sync = Self::SYNC;
self.address.to_bytes(bytes.address).map_err(ToBytesError::Address)?;
*bytes.mode = 2;
self.subheader.to_bytes(bytes.subheader1).map_err(ToBytesError::SubHeader)?;
self.subheader.to_bytes(bytes.subheader2).map_err(ToBytesError::SubHeader)?;
self.subheader
.to_bytes(bytes.subheader1)
.map_err(ToBytesError::SubHeader)?;
self.subheader
.to_bytes(bytes.subheader2)
.map_err(ToBytesError::SubHeader)?;
Ok(())
}

View File

@ -57,9 +57,15 @@ impl dcb_bytes::Bytes for Address {
block: 0x1,
);
let min = BcdU8(*bytes.min).to_u8().ok_or(FromBytesError::InvalidMinute(*bytes.min))?;
let sec = BcdU8(*bytes.sec).to_u8().ok_or(FromBytesError::InvalidSecond(*bytes.sec))?;
let block = BcdU8(*bytes.block).to_u8().ok_or(FromBytesError::InvalidBlock(*bytes.block))?;
let min = BcdU8(*bytes.min)
.to_u8()
.ok_or(FromBytesError::InvalidMinute(*bytes.min))?;
let sec = BcdU8(*bytes.sec)
.to_u8()
.ok_or(FromBytesError::InvalidSecond(*bytes.sec))?;
let block = BcdU8(*bytes.block)
.to_u8()
.ok_or(FromBytesError::InvalidBlock(*bytes.block))?;
if !Self::SECS_RANGE.contains(&sec) {
return Err(FromBytesError::OutOfRangeSecond(sec));
@ -85,9 +91,15 @@ impl dcb_bytes::Bytes for Address {
return Err(ToBytesError::OutOfRangeBlock(self.block));
}
let min = BcdU8::from_u8(self.min).ok_or(ToBytesError::OutOfRangeMinute(self.min))?.0;
let sec = BcdU8::from_u8(self.sec).ok_or(ToBytesError::OutOfRangeSecond(self.sec))?.0;
let block = BcdU8::from_u8(self.block).ok_or(ToBytesError::OutOfRangeBlock(self.block))?.0;
let min = BcdU8::from_u8(self.min)
.ok_or(ToBytesError::OutOfRangeMinute(self.min))?
.0;
let sec = BcdU8::from_u8(self.sec)
.ok_or(ToBytesError::OutOfRangeSecond(self.sec))?
.0;
let block = BcdU8::from_u8(self.block)
.ok_or(ToBytesError::OutOfRangeBlock(self.block))?
.0;
*bytes.min = min;
*bytes.sec = sec;

View File

@ -78,7 +78,14 @@ impl SubMode {
/// Validates this submode
fn validate(self) -> Result<(), BytesError> {
// If more than 1 of `Audio`, `Video` or `Data` are set, return Err
if self.bitand(Self::AUDIO).bitand(Self::VIDEO).bitand(Self::DATA).bits().count_ones() > 1 {
if self
.bitand(Self::AUDIO)
.bitand(Self::VIDEO)
.bitand(Self::DATA)
.bits()
.count_ones() >
1
{
return Err(BytesError::MoreThan1VideoAudioDataSet);
}

View File

@ -70,7 +70,10 @@ impl DirEntryReader {
#[allow(clippy::single_match)] // We might add more matches in the future
match bytes.name {
[0x83, 0x52, 0x83, 0x53, 0x81, 0x5B, 0x20, 0x81, 0x60, 0x20, 0x43, 0x41, 0x52, 0x44, 0x32, 0x00] => {
log::warn!("Ignoring special directory entry: {:?}", String::from_utf8_lossy(bytes.name));
log::warn!(
"Ignoring special directory entry: {:?}",
String::from_utf8_lossy(bytes.name)
);
return Ok(None);
},
_ => (),

View File

@ -52,7 +52,9 @@ impl DirReader {
}
// And parse it
DirEntryReader::from_bytes(&entry_bytes).map_err(ReadEntryError::ParseEntry).transpose()
DirEntryReader::from_bytes(&entry_bytes)
.map_err(ReadEntryError::ParseEntry)
.transpose()
});
Ok(iter)

View File

@ -52,7 +52,8 @@ impl<L: DirWriterLister> DirWriter<L> {
if start_pos % 2048 != 0 {
return Err(WriteEntriesError::WriterNotAtSectorStart);
}
let start_sector_pos = u32::try_from(start_pos / 2048).map_err(|_err| WriteEntriesError::WriterSectorPastMax)?;
let start_sector_pos =
u32::try_from(start_pos / 2048).map_err(|_err| WriteEntriesError::WriterSectorPastMax)?;
// Get the starting sector position for the first entry.
// Note: We start right after this directory
@ -84,7 +85,9 @@ impl<L: DirWriterLister> DirWriter<L> {
file.write(writer).map_err(WriteEntriesError::WriteFile)?;
(size + 2047) / 2048
},
DirEntryWriterKind::Dir(dir) => dir.write_entries(writer).map_err(|err| WriteEntriesError::WriteDir(Box::new(err)))?,
DirEntryWriterKind::Dir(dir) => dir
.write_entries(writer)
.map_err(|err| WriteEntriesError::WriteDir(Box::new(err)))?,
};
// Update our sector pos
@ -95,7 +98,9 @@ impl<L: DirWriterLister> DirWriter<L> {
writer
.seek(SeekFrom::Start(u64::from(start_sector_pos) * 2048))
.map_err(WriteEntriesError::SeekEntries)?;
writer.write_all(&entries_bytes).map_err(WriteEntriesError::WriteEntries)?;
writer
.write_all(&entries_bytes)
.map_err(WriteEntriesError::WriteEntries)?;
// And return the number of sectors we wrote.
Ok(cur_sector_pos - start_sector_pos)

View File

@ -22,7 +22,11 @@ impl FileReader {
/// Creates a new file reader from it's extension, sector position and size.
#[must_use]
pub const fn new(extension: AsciiStrArr<0x3>, sector_pos: u32, size: u32) -> Self {
Self { extension, sector_pos, size }
Self {
extension,
sector_pos,
size,
}
}
/// Returns this file's extension
@ -75,7 +79,11 @@ pub struct FileWriter<R: io::Read> {
impl<R: io::Read> FileWriter<R> {
/// Creates a new file writer from it's extension and reader.
pub fn new(extension: AsciiStrArr<0x3>, reader: R, size: u32) -> Self {
Self { extension, reader, size }
Self {
extension,
reader,
size,
}
}
/// Returns this file's extension

View File

@ -97,7 +97,9 @@ pub struct DrvFsWriter;
impl DrvFsWriter {
/// Creates a `.DRV` filesystem
pub fn write_fs<W: io::Write + io::Seek, L: DirWriterLister>(writer: &mut W, root_entries: L) -> Result<(), WriteFsError<L::Error>> {
pub fn write_fs<W: io::Write + io::Seek, L: DirWriterLister>(
writer: &mut W, root_entries: L,
) -> Result<(), WriteFsError<L::Error>> {
// Get the root and write it
let root = DirWriter::new(root_entries);
root.write_entries(writer).map_err(WriteFsError::RootDir)?;

View File

@ -145,21 +145,28 @@ impl Data {
/// Searches all instructions for references to
/// executable data using certain heuristics.
#[must_use]
pub fn search_instructions<'a>(insts_range: Range<Pos>, insts: impl Iterator<Item = (Pos, Inst<'a>)> + Clone) -> Vec<Self> {
pub fn search_instructions<'a>(
insts_range: Range<Pos>, insts: impl Iterator<Item = (Pos, Inst<'a>)> + Clone,
) -> Vec<Self> {
// Get all possible references to data
let references: BTreeSet<Pos> = insts
.clone()
.filter_map(|(pos, inst)| match inst {
Inst::Basic(basic::Inst::Load(basic::load::Inst { offset, .. }) | basic::Inst::Store(basic::store::Inst { offset, .. })) => {
Some(pos + offset.sign_extended::<i32>())
},
Inst::Basic(
basic::Inst::Load(basic::load::Inst { offset, .. }) |
basic::Inst::Store(basic::store::Inst { offset, .. }),
) => Some(pos + offset.sign_extended::<i32>()),
Inst::Pseudo(
pseudo::Inst::LoadImm(pseudo::load_imm::Inst {
kind: pseudo::load_imm::Kind::Address(Pos(address)) | pseudo::load_imm::Kind::Word(address),
..
}) |
pseudo::Inst::Load(pseudo::load::Inst { target: Pos(address), .. }) |
pseudo::Inst::Store(pseudo::store::Inst { target: Pos(address), .. }),
pseudo::Inst::Load(pseudo::load::Inst {
target: Pos(address), ..
}) |
pseudo::Inst::Store(pseudo::store::Inst {
target: Pos(address), ..
}),
) |
Inst::Directive(Directive::Dw(address)) => Some(Pos(address)),
_ => None,

View File

@ -107,7 +107,14 @@ impl DataTable {
},
// If we can't go any deeper, go as deep as we can at the start of `next_node`
None => return Some(next_node.get_containing_deepest(next_node.data().start_pos()).unwrap_or(next_node).data()),
None => {
return Some(
next_node
.get_containing_deepest(next_node.data().start_pos())
.unwrap_or(next_node)
.data(),
)
},
}
}

View File

@ -69,7 +69,10 @@ impl DataNode {
// If it contains it, check if we can insert it there
else if node.contains(&data) {
// If `data` is heuristics and `node`'s data is known and not a marker, return Err
if data.kind().is_heuristics() && node.data.kind().is_known() && !matches!(node.data.ty(), DataType::Marker { .. }) {
if data.kind().is_heuristics() &&
node.data.kind().is_known() &&
!matches!(node.data.ty(), DataType::Marker { .. })
{
return Err(InsertError::InsertHeuristicsIntoNonMarkerKnown {
data,
known: node.data.clone(),
@ -105,7 +108,11 @@ impl DataNode {
}
// And insert it
assert_eq!(self.nodes.replace(Self::new(data)), None, "No node with this position should exist",);
assert_eq!(
self.nodes.replace(Self::new(data)),
None,
"No node with this position should exist",
);
Ok(())
}
@ -126,7 +133,10 @@ impl DataNode {
pub fn get_containing(&self, pos: Pos) -> Option<&Self> {
// Note: We search backwards as the nodes will be sorted
// by their start position
self.nodes.range(..=pos).next_back().filter(|node| node.data.contains_pos(pos))
self.nodes
.range(..=pos)
.next_back()
.filter(|node| node.data.contains_pos(pos))
}
/// Returns the deepest data node containing `pos`
@ -226,7 +236,9 @@ fn range_intersect<T: Ord>(lhs: Range<T>, rhs: Range<T>) -> bool {
///
/// It is a logical error to modify an element's order.
/// This function *might* panic if the order is changed
fn btree_set_modify<T: Ord + Borrow<Q>, Q: Ord, U>(set: &mut BTreeSet<T>, element: &Q, f: impl FnOnce(&mut T) -> U) -> U {
fn btree_set_modify<T: Ord + Borrow<Q>, Q: Ord, U>(
set: &mut BTreeSet<T>, element: &Q, f: impl FnOnce(&mut T) -> U,
) -> U {
// Take the element from the set
let mut node = set.take(element).expect("Element didn't exist");

View File

@ -79,8 +79,10 @@ impl FuncTable {
/// Creates a new list of functions from an iterator over insts
#[must_use]
#[allow(clippy::too_many_lines)] // TODO: Refactor
pub fn search_instructions<'a>(
insts_range: Range<Pos>, insts: impl Iterator<Item = (Pos, Inst<'a>)> + Clone, known_func_table: &Self, data_table: &DataTable,
insts_range: Range<Pos>, insts: impl Iterator<Item = (Pos, Inst<'a>)> + Clone, known_func_table: &Self,
data_table: &DataTable,
) -> Self {
// Get all returns
let returns: BTreeSet<Pos> = insts
@ -159,7 +161,11 @@ impl FuncTable {
// If there's a function in between us and the return, use the last tailcall instead
if let Some(next_func_pos) = function_entries.range(func_pos + 4i32..end_pos).next() {
end_pos = tailcalls.range(..next_func_pos).next_back().copied().unwrap_or(func_pos) + 8i32;
end_pos = tailcalls
.range(..next_func_pos)
.next_back()
.copied()
.unwrap_or(func_pos) + 8i32;
// If we got a tailcall before this function, just end it 2 insts
if end_pos <= func_pos {
@ -168,13 +174,22 @@ impl FuncTable {
}
// If this function would intersect any other, skip this one.
if cur_funcs.range(..=func_pos).next_back().map_or(false, |func| func.end_pos > func_pos) ||
cur_funcs.range(func_pos..).next().map_or(false, |func| func.start_pos < end_pos) ||
if cur_funcs
.range(..=func_pos)
.next_back()
.map_or(false, |func| func.end_pos > func_pos) ||
cur_funcs
.range(func_pos..)
.next()
.map_or(false, |func| func.start_pos < end_pos) ||
known_func_table
.range(..=func_pos)
.next_back()
.map_or(false, |func| func.end_pos > func_pos) ||
known_func_table.range(func_pos..).next().map_or(false, |func| func.start_pos < end_pos)
known_func_table
.range(func_pos..)
.next()
.map_or(false, |func| func.start_pos < end_pos)
{
continue;
}

View File

@ -45,7 +45,9 @@ pub enum Inst<'a> {
impl<'a> Inst<'a> {
/// Decodes an instruction from bytes and it's position.
pub fn decode(pos: Pos, bytes: &'a [u8], data_table: &'a DataTable, func_table: &'a FuncTable) -> Result<Self, DecodeError<'a>> {
pub fn decode(
pos: Pos, bytes: &'a [u8], data_table: &'a DataTable, func_table: &'a FuncTable,
) -> Result<Self, DecodeError<'a>> {
// If `bytes` is empty, return Err
if bytes.is_empty() {
return Err(DecodeError::NoBytes);
@ -96,7 +98,9 @@ impl<'a> Inst<'a> {
}
// Else read it as a directive
Directive::decode(pos, bytes).map(Self::Directive).ok_or(DecodeError::NoBytes)
Directive::decode(pos, bytes)
.map(Self::Directive)
.ok_or(DecodeError::NoBytes)
}
/// Writes an instruction

View File

@ -54,7 +54,9 @@ impl Kind {
pub fn value(self) -> i64 {
match self {
Kind::Add(value) | Kind::AddUnsigned(value) | Kind::SetLessThan(value) => i64::from(value),
Kind::SetLessThanUnsigned(value) | Kind::And(value) | Kind::Or(value) | Kind::Xor(value) => i64::from(value),
Kind::SetLessThanUnsigned(value) | Kind::And(value) | Kind::Or(value) | Kind::Xor(value) => {
i64::from(value)
},
}
}
}
@ -119,7 +121,9 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
#[rustfmt::skip]
let to_kind = match mnemonic {
"addi" => |value: i64| value.try_into().map(Kind::Add ),
@ -134,16 +138,17 @@ impl<'a> Parsable<'a> for Inst {
match *args {
// Disallow `slti` and `sltiu` in short form
[LineArg::Register(_), LineArg::Literal(_)] if ["slti", "sltiu"].contains(&mnemonic) => Err(ParseError::InvalidArguments),
[LineArg::Register(_), LineArg::Literal(_)] if ["slti", "sltiu"].contains(&mnemonic) => {
Err(ParseError::InvalidArguments)
},
// Else parse both `$dst, $lhs, value` and `$dst, value`.
[LineArg::Register(lhs @ dst), LineArg::Literal(value)] | [LineArg::Register(dst), LineArg::Register(lhs), LineArg::Literal(value)] => {
Ok(Self {
dst,
lhs,
kind: to_kind(value).map_err(|_| ParseError::LiteralOutOfRange)?,
})
},
[LineArg::Register(lhs @ dst), LineArg::Literal(value)] |
[LineArg::Register(dst), LineArg::Register(lhs), LineArg::Literal(value)] => Ok(Self {
dst,
lhs,
kind: to_kind(value).map_err(|_| ParseError::LiteralOutOfRange)?,
}),
_ => Err(ParseError::InvalidArguments),
}
}
@ -167,7 +172,11 @@ impl<'a> InstDisplay<'a> for Inst {
// only return one of them
match !matches!(kind, Kind::SetLessThan(_) | Kind::SetLessThanUnsigned(_)) && dst == lhs {
true => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::literal(value)]),
false => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(lhs), InstFmtArg::literal(value)]),
false => array::IntoIter::new([
InstFmtArg::Register(dst),
InstFmtArg::Register(lhs),
InstFmtArg::literal(value),
]),
}
}
}

View File

@ -133,7 +133,9 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
#[rustfmt::skip]
let kind = match mnemonic {
"add" => Kind::Add ,
@ -149,16 +151,19 @@ impl<'a> Parsable<'a> for Inst {
_ => return Err(ParseError::UnknownMnemonic),
};
match *args {
let inst = match *args {
// Disallow `slt` and `sltu` in short form
[LineArg::Register(_), LineArg::Register(_)] if ["slt", "sltu"].contains(&mnemonic) => Err(ParseError::InvalidArguments),
[LineArg::Register(_), LineArg::Register(_)] if ["slt", "sltu"].contains(&mnemonic) => {
return Err(ParseError::InvalidArguments)
},
// Else parse both `$dst, $lhs, $rhs` and `$dst, $rhs`.
[LineArg::Register(lhs @ dst), LineArg::Register(rhs)] | [LineArg::Register(dst), LineArg::Register(lhs), LineArg::Register(rhs)] => {
Ok(Self { dst, lhs, rhs, kind })
},
_ => Err(ParseError::InvalidArguments),
}
[LineArg::Register(lhs @ dst), LineArg::Register(rhs)] |
[LineArg::Register(dst), LineArg::Register(lhs), LineArg::Register(rhs)] => Self { dst, lhs, rhs, kind },
_ => return Err(ParseError::InvalidArguments),
};
Ok(inst)
}
}
@ -179,7 +184,11 @@ impl<'a> InstDisplay<'a> for Inst {
// only return one of them
match !matches!(kind, Kind::SetLessThan | Kind::SetLessThanUnsigned) && dst == lhs {
true => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(rhs)]),
false => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(lhs), InstFmtArg::Register(rhs)]),
false => array::IntoIter::new([
InstFmtArg::Register(dst),
InstFmtArg::Register(lhs),
InstFmtArg::Register(rhs),
]),
}
}
}

View File

@ -169,7 +169,9 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
let inst = match mnemonic {
"cop0" | "cop1" | "cop2" | "cop3" => {
let n = mnemonic[3..].parse().expect("Unable to parse 0..=3");
@ -178,13 +180,18 @@ impl<'a> Parsable<'a> for Inst {
_ => return Err(ParseError::InvalidArguments),
};
Inst { n, kind: Kind::CopN { imm } }
Inst {
n,
kind: Kind::CopN { imm },
}
},
"mfc0" | "mfc1" | "mfc2" | "mfc3" | "cfc0" | "cfc1" | "cfc2" | "cfc3" | "mtc0" | "mtc1" | "mtc2" | "mtc3" | "ctc0" | "ctc1" |
"ctc2" | "ctc3" => {
"mfc0" | "mfc1" | "mfc2" | "mfc3" | "cfc0" | "cfc1" | "cfc2" | "cfc3" | "mtc0" | "mtc1" | "mtc2" |
"mtc3" | "ctc0" | "ctc1" | "ctc2" | "ctc3" => {
let n = mnemonic[3..].parse().expect("Unable to parse 0..=3");
let (reg, imm) = match *args {
[LineArg::Register(dst), LineArg::Literal(src)] => (dst, src.try_into().map_err(|_| ParseError::LiteralOutOfRange)?),
[LineArg::Register(dst), LineArg::Literal(src)] => {
(dst, src.try_into().map_err(|_| ParseError::LiteralOutOfRange)?)
},
_ => return Err(ParseError::InvalidArguments),
};
@ -197,11 +204,19 @@ impl<'a> Parsable<'a> for Inst {
match &mnemonic[1..=1] {
"f" => Inst {
n,
kind: Kind::MoveFrom { dst: reg, src: imm, kind },
kind: Kind::MoveFrom {
dst: reg,
src: imm,
kind,
},
},
"t" => Inst {
n,
kind: Kind::MoveTo { dst: imm, src: reg, kind },
kind: Kind::MoveTo {
dst: imm,
src: reg,
kind,
},
},
_ => unreachable!(),
}
@ -209,7 +224,9 @@ impl<'a> Parsable<'a> for Inst {
"lwc0" | "lwc1" | "lwc2" | "lwc3" | "swc0" | "swc1" | "swc2" | "swc3" => {
let n = mnemonic[3..].parse().expect("Unable to parse 0..=3");
let (dst, src, offset) = match *args {
[LineArg::Literal(dst), LineArg::Register(src)] => (dst.try_into().map_err(|_| ParseError::LiteralOutOfRange)?, src, 0),
[LineArg::Literal(dst), LineArg::Register(src)] => {
(dst.try_into().map_err(|_| ParseError::LiteralOutOfRange)?, src, 0)
},
[LineArg::Literal(dst), LineArg::RegisterOffset { register: src, offset }] => (
dst.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
src,
@ -273,11 +290,19 @@ impl<'a> InstDisplay<'a> for Inst {
let &Self { kind, .. } = self;
match kind {
Kind::CopN { imm } => array::IntoIter::new([InstFmtArg::literal(imm)]),
Kind::MoveFrom { dst, src, .. } => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::literal(src)]),
Kind::MoveTo { dst, src, .. } => array::IntoIter::new([InstFmtArg::Register(src), InstFmtArg::literal(dst)]),
Kind::MoveFrom { dst, src, .. } => {
array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::literal(src)])
},
Kind::MoveTo { dst, src, .. } => {
array::IntoIter::new([InstFmtArg::Register(src), InstFmtArg::literal(dst)])
},
Kind::Branch { offset, .. } => array::IntoIter::new([InstFmtArg::literal(offset)]),
Kind::Load { dst, src, offset } => array::IntoIter::new([InstFmtArg::literal(dst), InstFmtArg::register_offset(src, offset)]),
Kind::Store { dst, src, offset } => array::IntoIter::new([InstFmtArg::literal(dst), InstFmtArg::register_offset(src, offset)]),
Kind::Load { dst, src, offset } => {
array::IntoIter::new([InstFmtArg::literal(dst), InstFmtArg::register_offset(src, offset)])
},
Kind::Store { dst, src, offset } => {
array::IntoIter::new([InstFmtArg::literal(dst), InstFmtArg::register_offset(src, offset)])
},
}
}
}
@ -286,7 +311,9 @@ impl ModifiesReg for Inst {
fn modifies_reg(&self, reg: Register) -> bool {
match self.kind {
Kind::MoveFrom { dst, .. } => dst == reg,
Kind::CopN { .. } | Kind::MoveTo { .. } | Kind::Branch { .. } | Kind::Load { .. } | Kind::Store { .. } => false,
Kind::CopN { .. } | Kind::MoveTo { .. } | Kind::Branch { .. } | Kind::Load { .. } | Kind::Store { .. } => {
false
},
}
}
}

View File

@ -149,15 +149,21 @@ impl<'a> Parsable<'a> for Inst {
_ => return Err(ParseError::InvalidArguments),
},
"bnez" => match *args {
[LineArg::Register(arg), ref target] => (arg, target_arg_to_offset(target)?, Kind::NotEqual(Register::Zr)),
[LineArg::Register(arg), ref target] => {
(arg, target_arg_to_offset(target)?, Kind::NotEqual(Register::Zr))
},
_ => return Err(ParseError::InvalidArguments),
},
"beq" => match *args {
[LineArg::Register(arg), LineArg::Register(reg), ref target] => (arg, target_arg_to_offset(target)?, Kind::Equal(reg)),
[LineArg::Register(arg), LineArg::Register(reg), ref target] => {
(arg, target_arg_to_offset(target)?, Kind::Equal(reg))
},
_ => return Err(ParseError::InvalidArguments),
},
"bne" => match *args {
[LineArg::Register(arg), LineArg::Register(reg), ref target] => (arg, target_arg_to_offset(target)?, Kind::NotEqual(reg)),
[LineArg::Register(arg), LineArg::Register(reg), ref target] => {
(arg, target_arg_to_offset(target)?, Kind::NotEqual(reg))
},
_ => return Err(ParseError::InvalidArguments),
},
"blez" => match *args {
@ -181,7 +187,9 @@ impl<'a> Parsable<'a> for Inst {
_ => return Err(ParseError::InvalidArguments),
},
"bgezal" => match *args {
[LineArg::Register(arg), ref target] => (arg, target_arg_to_offset(target)?, Kind::GreaterOrEqualZeroLink),
[LineArg::Register(arg), ref target] => {
(arg, target_arg_to_offset(target)?, Kind::GreaterOrEqualZeroLink)
},
_ => return Err(ParseError::InvalidArguments),
},
@ -220,18 +228,28 @@ impl<'a> InstDisplay<'a> for Inst {
}
#[auto_enums::auto_enum(Iterator)]
#[rustfmt::skip]
fn args<Ctx: DisplayCtx>(&'a self, ctx: &Ctx) -> Self::Args {
use InstFmtArg::Register as register;
let &Self { arg, offset, kind } = self;
let target = Self::target_of(offset, ctx.cur_pos());
match (arg, kind) {
(Register::Zr, Kind::Equal (Register::Zr)) => array::IntoIter::new([ InstFmtArg::Target(target)]),
(_ , Kind::Equal (Register::Zr)) => array::IntoIter::new([register(arg), InstFmtArg::Target(target)]),
(_ , Kind::Equal (reg) ) => array::IntoIter::new([register(arg), register(reg), InstFmtArg::Target(target)]),
(_ , Kind::NotEqual(Register::Zr)) => array::IntoIter::new([register(arg), InstFmtArg::Target(target)]),
(_ , Kind::NotEqual(reg) ) => array::IntoIter::new([register(arg), register(reg), InstFmtArg::Target(target)]),
(Register::Zr, Kind::Equal(Register::Zr)) => array::IntoIter::new([InstFmtArg::Target(target)]),
(_, Kind::Equal(Register::Zr)) => {
array::IntoIter::new([InstFmtArg::Register(arg), InstFmtArg::Target(target)])
},
(_, Kind::Equal(reg)) => array::IntoIter::new([
InstFmtArg::Register(arg),
InstFmtArg::Register(reg),
InstFmtArg::Target(target),
]),
(_, Kind::NotEqual(Register::Zr)) => {
array::IntoIter::new([InstFmtArg::Register(arg), InstFmtArg::Target(target)])
},
(_, Kind::NotEqual(reg)) => array::IntoIter::new([
InstFmtArg::Register(arg),
InstFmtArg::Register(reg),
InstFmtArg::Target(target),
]),
(
_,
Kind::LessOrEqualZero |
@ -240,7 +258,7 @@ impl<'a> InstDisplay<'a> for Inst {
Kind::GreaterOrEqualZero |
Kind::LessThanZeroLink |
Kind::GreaterOrEqualZeroLink,
) => array::IntoIter::new([register(arg), InstFmtArg::Target(target)]),
) => array::IntoIter::new([InstFmtArg::Register(arg), InstFmtArg::Target(target)]),
}
}
}

View File

@ -74,7 +74,9 @@ impl Encode for Inst {
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
let (target, kind) = match mnemonic {
"jr" => match *args {
[LineArg::Register(target)] => (target, Kind::Jump),

View File

@ -131,18 +131,27 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
let kind = Kind::from_mnemonic(mnemonic).ok_or(ParseError::UnknownMnemonic)?;
let (value, addr, offset) = match *args {
[LineArg::Register(value), LineArg::Register(addr)] => (value, addr, 0),
[LineArg::Register(value), LineArg::RegisterOffset { register: addr, offset }] => {
(value, addr, offset.try_into().map_err(|_| ParseError::LiteralOutOfRange)?)
},
[LineArg::Register(value), LineArg::RegisterOffset { register: addr, offset }] => (
value,
addr,
offset.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
),
_ => return Err(ParseError::InvalidArguments),
};
Ok(Self { value, addr, offset, kind })
Ok(Self {
value,
addr,
offset,
kind,
})
}
}
@ -155,7 +164,9 @@ impl<'a> InstDisplay<'a> for Inst {
}
fn args<Ctx: DisplayCtx>(&'a self, _ctx: &Ctx) -> Self::Args {
let &Self { value, addr, offset, .. } = self;
let &Self {
value, addr, offset, ..
} = self;
array::IntoIter::new([InstFmtArg::Register(value), InstFmtArg::register_offset(addr, offset)])
}

View File

@ -47,7 +47,9 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
if mnemonic != "lui" {
return Err(ParseError::UnknownMnemonic);
}

View File

@ -109,20 +109,21 @@ impl Decode for Inst {
_ => return None,
};
let reg = Register::new;
Some(match f {
// 00x0
0x0 => Self::MoveFrom { dst: Register::new(d)?, src: MultReg::Hi },
0x2 => Self::MoveFrom { dst: Register::new(d)?, src: MultReg::Lo },
0x0 => Self::MoveFrom { dst: reg(d)?, src: MultReg::Hi },
0x2 => Self::MoveFrom { dst: reg(d)?, src: MultReg::Lo },
// 00x1
0x1 => Self::MoveTo { src: Register::new(s)?, dst: MultReg::Hi },
0x3 => Self::MoveTo { src: Register::new(s)?, dst: MultReg::Lo },
0x1 => Self::MoveTo { src: reg(s)?, dst: MultReg::Hi },
0x3 => Self::MoveTo { src: reg(s)?, dst: MultReg::Lo },
// 10xx
0x8 => Self::Mult { kind: MultKind::Mult, mode: MultMode:: Signed, lhs: Register::new(s)?, rhs: Register::new(t)? },
0x9 => Self::Mult { kind: MultKind::Mult, mode: MultMode::Unsigned, lhs: Register::new(s)?, rhs: Register::new(t)? },
0xa => Self::Mult { kind: MultKind::Div , mode: MultMode:: Signed, lhs: Register::new(s)?, rhs: Register::new(t)? },
0xb => Self::Mult { kind: MultKind::Div , mode: MultMode::Unsigned, lhs: Register::new(s)?, rhs: Register::new(t)? },
0x8 => Self::Mult { kind: MultKind::Mult, mode: MultMode:: Signed, lhs: reg(s)?, rhs: reg(t)? },
0x9 => Self::Mult { kind: MultKind::Mult, mode: MultMode::Unsigned, lhs: reg(s)?, rhs: reg(t)? },
0xa => Self::Mult { kind: MultKind::Div , mode: MultMode:: Signed, lhs: reg(s)?, rhs: reg(t)? },
0xb => Self::Mult { kind: MultKind::Div , mode: MultMode::Unsigned, lhs: reg(s)?, rhs: reg(t)? },
_ => return None,
})
@ -155,7 +156,9 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
let inst = match mnemonic {
"mflo" | "mfhi" | "mtlo" | "mthi" => {
let reg = match *args {
@ -170,8 +173,14 @@ impl<'a> Parsable<'a> for Inst {
};
match &mnemonic[1..=1] {
"f" => Inst::MoveFrom { dst: reg, src: mult_reg },
"t" => Inst::MoveTo { dst: mult_reg, src: reg },
"f" => Inst::MoveFrom {
dst: reg,
src: mult_reg,
},
"t" => Inst::MoveTo {
dst: mult_reg,
src: reg,
},
_ => unreachable!(),
}
},
@ -219,7 +228,9 @@ impl<'a> InstDisplay<'a> for Inst {
fn args<Ctx: DisplayCtx>(&'a self, _ctx: &Ctx) -> Self::Args {
match *self {
Self::Mult { lhs, rhs, .. } => array::IntoIter::new([InstFmtArg::Register(lhs), InstFmtArg::Register(rhs)]),
Self::MoveFrom { dst: arg, .. } | Self::MoveTo { src: arg, .. } => array::IntoIter::new([InstFmtArg::Register(arg)]),
Self::MoveFrom { dst: arg, .. } | Self::MoveTo { src: arg, .. } => {
array::IntoIter::new([InstFmtArg::Register(arg)])
},
}
}
}

View File

@ -106,7 +106,9 @@ impl TryEncode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
let kind = match mnemonic {
"sll" => Kind::LeftLogical,
"srl" => Kind::RightLogical,
@ -115,14 +117,13 @@ impl<'a> Parsable<'a> for Inst {
};
match *args {
[LineArg::Register(lhs @ dst), LineArg::Literal(rhs)] | [LineArg::Register(dst), LineArg::Register(lhs), LineArg::Literal(rhs)] => {
Ok(Self {
dst,
lhs,
rhs: rhs.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
kind,
})
},
[LineArg::Register(lhs @ dst), LineArg::Literal(rhs)] |
[LineArg::Register(dst), LineArg::Register(lhs), LineArg::Literal(rhs)] => Ok(Self {
dst,
lhs,
rhs: rhs.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
kind,
}),
_ => Err(ParseError::InvalidArguments),
}
}
@ -144,7 +145,11 @@ impl<'a> InstDisplay<'a> for Inst {
// If `$dst` and `$lhs` are the same, only print one of them
match dst == lhs {
true => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::literal(rhs)]),
false => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(lhs), InstFmtArg::literal(rhs)]),
false => array::IntoIter::new([
InstFmtArg::Register(dst),
InstFmtArg::Register(lhs),
InstFmtArg::literal(rhs),
]),
}
}
}

View File

@ -92,7 +92,9 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
let kind = match mnemonic {
"sllv" => Kind::LeftLogical,
"srlv" => Kind::RightLogical,
@ -100,12 +102,13 @@ impl<'a> Parsable<'a> for Inst {
_ => return Err(ParseError::UnknownMnemonic),
};
match *args {
[LineArg::Register(lhs @ dst), LineArg::Register(rhs)] | [LineArg::Register(dst), LineArg::Register(lhs), LineArg::Register(rhs)] => {
Ok(Self { dst, lhs, rhs, kind })
},
_ => Err(ParseError::InvalidArguments),
}
let inst = match *args {
[LineArg::Register(lhs @ dst), LineArg::Register(rhs)] |
[LineArg::Register(dst), LineArg::Register(lhs), LineArg::Register(rhs)] => Self { dst, lhs, rhs, kind },
_ => return Err(ParseError::InvalidArguments),
};
Ok(inst)
}
}
@ -125,7 +128,11 @@ impl<'a> InstDisplay<'a> for Inst {
// If `$dst` and `$lhs` are the same, only print one of them
match dst == lhs {
true => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(rhs)]),
false => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(lhs), InstFmtArg::Register(rhs)]),
false => array::IntoIter::new([
InstFmtArg::Register(dst),
InstFmtArg::Register(lhs),
InstFmtArg::Register(rhs),
]),
}
}
}

View File

@ -119,18 +119,27 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
let kind = Kind::from_mnemonic(mnemonic).ok_or(ParseError::UnknownMnemonic)?;
let (value, addr, offset) = match *args {
[LineArg::Register(value), LineArg::Register(addr)] => (value, addr, 0),
[LineArg::Register(value), LineArg::RegisterOffset { register: addr, offset }] => {
(value, addr, offset.try_into().map_err(|_| ParseError::LiteralOutOfRange)?)
},
[LineArg::Register(value), LineArg::RegisterOffset { register: addr, offset }] => (
value,
addr,
offset.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
),
_ => return Err(ParseError::InvalidArguments),
};
Ok(Self { value, addr, offset, kind })
Ok(Self {
value,
addr,
offset,
kind,
})
}
}
@ -143,7 +152,9 @@ impl<'a> InstDisplay<'a> for Inst {
}
fn args<Ctx: DisplayCtx>(&'a self, _ctx: &Ctx) -> Self::Args {
let &Self { value, addr, offset, .. } = self;
let &Self {
value, addr, offset, ..
} = self;
array::IntoIter::new([InstFmtArg::Register(value), InstFmtArg::register_offset(addr, offset)])
}

View File

@ -87,7 +87,9 @@ impl TryEncode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
let kind = match mnemonic {
"sys" => Kind::Sys,
"break" => Kind::Break,

View File

@ -57,7 +57,9 @@ pub enum DecodeWithDataError {
impl<'a> Directive<'a> {
/// Decodes a directive with some data
pub fn decode_with_data(pos: Pos, bytes: &'a [u8], ty: &DataType, data_pos: Pos) -> Result<Self, DecodeWithDataError> {
pub fn decode_with_data(
pos: Pos, bytes: &'a [u8], ty: &DataType, data_pos: Pos,
) -> Result<Self, DecodeWithDataError> {
// Make sure that this function is only called when the data contains `pos`
assert!((data_pos..data_pos + ty.size()).contains(&pos));
@ -84,7 +86,9 @@ impl<'a> Directive<'a> {
// Then make sure there's nulls padding the string
let nulls_len = 4 - len % 4;
let nulls = bytes.get(len..len + nulls_len).ok_or(DecodeWithDataError::StrNullTerminator)?;
let nulls = bytes
.get(len..len + nulls_len)
.ok_or(DecodeWithDataError::StrNullTerminator)?;
if !nulls.iter().all(|&ch| ch == 0) {
return Err(DecodeWithDataError::StrNullTerminator);
}
@ -173,7 +177,9 @@ impl<'a> Parsable<'a> for Directive<'a> {
_ => return Err(ParseError::InvalidArguments),
},
".ascii" => match *args {
[LineArg::String(ref s)] => Self::Ascii(AsciiStr::from_ascii(s).map_err(|_| ParseError::NonAsciiString)?),
[LineArg::String(ref s)] => {
Self::Ascii(AsciiStr::from_ascii(s).map_err(|_| ParseError::NonAsciiString)?)
},
_ => return Err(ParseError::InvalidArguments),
},
_ => return Err(ParseError::UnknownMnemonic),

View File

@ -80,7 +80,9 @@ impl<'a> InstFmtArg<'a> {
pub fn write<Ctx: DisplayCtx>(&self, f: &mut fmt::Formatter, ctx: &Ctx) -> Result<(), fmt::Error> {
match *self {
// Register offsets with 0 offset are formatted like normal registers
InstFmtArg::Register(register) | InstFmtArg::RegisterOffset { register, offset: 0 } => write!(f, "{register}"),
InstFmtArg::Register(register) | InstFmtArg::RegisterOffset { register, offset: 0 } => {
write!(f, "{register}")
},
InstFmtArg::RegisterOffset { register, offset } => write!(f, "{:#}({register})", SignedHex(offset)),
// Note: Literals do not go through label lookup
InstFmtArg::Literal(value) => write!(f, "{:#}", SignedHex(value)),

View File

@ -31,7 +31,10 @@ pub trait ParseCtx {
match *arg {
LineArg::Literal(pos) => pos.try_into().map(Pos).map_err(|_| ParseError::LiteralOutOfRange),
LineArg::Label(ref label) => self.label_pos(label).ok_or(ParseError::UnknownLabel),
LineArg::LabelOffset { ref label, offset } => self.label_pos(label).map(|pos| pos + offset).ok_or(ParseError::UnknownLabel),
LineArg::LabelOffset { ref label, offset } => self
.label_pos(label)
.map(|pos| pos + offset)
.ok_or(ParseError::UnknownLabel),
_ => Err(ParseError::InvalidArguments),
}
}
@ -39,9 +42,18 @@ pub trait ParseCtx {
/// Retrieves a position and offset from an argument
fn arg_pos_offset(&self, arg: &LineArg) -> Result<(Pos, i64), ParseError> {
match *arg {
LineArg::Literal(pos) => pos.try_into().map(|pos| (Pos(pos), 0)).map_err(|_| ParseError::LiteralOutOfRange),
LineArg::Label(ref label) => self.label_pos(label).map(|pos| (pos, 0)).ok_or(ParseError::UnknownLabel),
LineArg::LabelOffset { ref label, offset } => self.label_pos(label).map(|pos| (pos, offset)).ok_or(ParseError::UnknownLabel),
LineArg::Literal(pos) => pos
.try_into()
.map(|pos| (Pos(pos), 0))
.map_err(|_| ParseError::LiteralOutOfRange),
LineArg::Label(ref label) => self
.label_pos(label)
.map(|pos| (pos, 0))
.ok_or(ParseError::UnknownLabel),
LineArg::LabelOffset { ref label, offset } => self
.label_pos(label)
.map(|pos| (pos, offset))
.ok_or(ParseError::UnknownLabel),
_ => Err(ParseError::InvalidArguments),
}
}

View File

@ -41,7 +41,10 @@ impl<R: io::BufRead> InstParser<R> {
// If it starts with a comment or it's empty, return an empty line
if line.starts_with('#') || line.is_empty() {
return Ok(Line { label: None, inst: None });
return Ok(Line {
label: None,
inst: None,
});
}
// Name character validator
@ -146,7 +149,10 @@ impl<R: io::BufRead> InstParser<R> {
// Find the first non-escaped '"'
// Note: The `+2` can never panic.
let string = match args[1..].find(find_first_non_escaped_quotes).map(|idx| args.split_at(idx + 2)) {
let string = match args[1..]
.find(find_first_non_escaped_quotes)
.map(|idx| args.split_at(idx + 2))
{
Some((string, rest)) => {
args = rest.trim_start();
string

View File

@ -39,7 +39,9 @@ impl Decodable for Inst {
basic::Inst::Lui(lui) => match insts.next()? {
basic::Inst::Load(load) if load.value == lui.dst && load.addr == load.value => Self {
value: load.value,
target: Pos((u32::join(0, lui.value).as_signed() + load.offset.sign_extended::<i32>()).as_unsigned()),
target: Pos(
(u32::join(0, lui.value).as_signed() + load.offset.sign_extended::<i32>()).as_unsigned(),
),
kind: load.kind,
},
_ => return None,

View File

@ -3,7 +3,9 @@
// Imports
use super::{Decodable, Encodable};
use crate::{
inst::{basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register},
inst::{
basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register,
},
Pos,
};
use int_conv::{Join, SignExtended, Signed, Split};
@ -66,7 +68,9 @@ impl Decodable for Inst {
dst: lui.dst,
kind: match alu.kind {
// lui << 16 + rhs
AddUnsigned(rhs) => Kind::Address(Pos((u32::join(0, lui.value).as_signed() + rhs.sign_extended::<i32>()).as_unsigned())),
AddUnsigned(rhs) => Kind::Address(Pos((u32::join(0, lui.value).as_signed() +
rhs.sign_extended::<i32>())
.as_unsigned())),
Or(rhs) => Kind::Word(u32::join(rhs, lui.value)),
_ => return None,
},
@ -105,7 +109,10 @@ impl Encodable for Inst {
};
std::array::IntoIter::new([
basic::Inst::Lui(basic::lui::Inst { dst: self.dst, value: hi }),
basic::Inst::Lui(basic::lui::Inst {
dst: self.dst,
value: hi,
}),
basic::Inst::Alu(basic::alu::Inst::Imm(basic::alu::imm::Inst {
dst: self.dst,
lhs: self.dst,
@ -117,7 +124,10 @@ impl Encodable for Inst {
let (lo, hi) = value.lo_hi();
std::array::IntoIter::new([
basic::Inst::Lui(basic::lui::Inst { dst: self.dst, value: hi }),
basic::Inst::Lui(basic::lui::Inst {
dst: self.dst,
value: hi,
}),
basic::Inst::Alu(basic::alu::Inst::Imm(basic::alu::imm::Inst {
dst: self.dst,
lhs: self.dst,
@ -125,17 +135,21 @@ impl Encodable for Inst {
})),
])
},
Kind::HalfWordUnsigned(value) => std::iter::once(basic::Inst::Alu(basic::alu::Inst::Imm(basic::alu::imm::Inst {
dst: self.dst,
lhs: Register::Zr,
kind: basic::alu::imm::Kind::Or(value),
}))),
Kind::HalfWordUnsigned(value) => {
std::iter::once(basic::Inst::Alu(basic::alu::Inst::Imm(basic::alu::imm::Inst {
dst: self.dst,
lhs: Register::Zr,
kind: basic::alu::imm::Kind::Or(value),
})))
},
Kind::HalfWordSigned(value) => std::iter::once(basic::Inst::Alu(basic::alu::Inst::Imm(basic::alu::imm::Inst {
dst: self.dst,
lhs: Register::Zr,
kind: basic::alu::imm::Kind::AddUnsigned(value),
}))),
Kind::HalfWordSigned(value) => {
std::iter::once(basic::Inst::Alu(basic::alu::Inst::Imm(basic::alu::imm::Inst {
dst: self.dst,
lhs: Register::Zr,
kind: basic::alu::imm::Kind::AddUnsigned(value),
})))
},
}
}
}

View File

@ -2,7 +2,9 @@
// Imports
use super::{Decodable, Encodable};
use crate::inst::{basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register};
use crate::inst::{
basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register,
};
use std::{array, convert::TryInto};
/// Move register instruction
@ -49,7 +51,9 @@ impl Encodable for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
if mnemonic != "move" {
return Err(ParseError::UnknownMnemonic);
}

View File

@ -2,7 +2,9 @@
// Imports
use super::{Decodable, Encodable};
use crate::inst::{basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register};
use crate::inst::{
basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register,
};
use std::{
array,
convert::{TryFrom, TryInto},
@ -48,7 +50,9 @@ impl Encodable for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
if mnemonic != "nop" {
return Err(ParseError::UnknownMnemonic);
}

View File

@ -38,7 +38,9 @@ impl Decodable for Inst {
basic::Inst::Lui(lui) if lui.dst == Register::At => match insts.next()? {
basic::Inst::Store(store) if store.addr == Register::At => Self {
value: store.value,
target: Pos((u32::join(0, lui.value).as_signed() + store.offset.sign_extended::<i32>()).as_unsigned()),
target: Pos(
(u32::join(0, lui.value).as_signed() + store.offset.sign_extended::<i32>()).as_unsigned(),
),
kind: store.kind,
},
_ => return None,

View File

@ -89,7 +89,8 @@ impl ExeReader {
pub fn deserialize<R: io::Read + io::Seek>(file: &mut R) -> Result<Self, DeserializeError> {
// Read header
let mut header_bytes = [0u8; <<Header as Bytes>::ByteArray as ByteArray>::SIZE];
file.read_exact(&mut header_bytes).map_err(DeserializeError::ReadHeader)?;
file.read_exact(&mut header_bytes)
.map_err(DeserializeError::ReadHeader)?;
let header = Header::from_bytes(&header_bytes).map_err(DeserializeError::ParseHeader)?;
// Get the instruction range
@ -100,7 +101,8 @@ impl ExeReader {
};
// Read all of the bytes
let mut bytes = vec![0u8; usize::try_from(header.size).expect("Len didn't fit into `usize`")].into_boxed_slice();
let mut bytes =
vec![0u8; usize::try_from(header.size).expect("Len didn't fit into `usize`")].into_boxed_slice();
file.read_exact(bytes.as_mut()).map_err(DeserializeError::ReadData)?;
// Read the known data and func table
@ -112,7 +114,8 @@ impl ExeReader {
// Then parse all heuristic tables
let heuristics_data = Data::search_instructions(insts_range.clone(), insts.clone());
let heuristics_func_table = FuncTable::search_instructions(insts_range, insts, &known_func_table, &known_data_table);
let heuristics_func_table =
FuncTable::search_instructions(insts_range, insts, &known_func_table, &known_data_table);
known_data_table.extend(heuristics_data);
let func_table = known_func_table.merge_with(heuristics_func_table);

View File

@ -49,7 +49,11 @@ impl<'a, R: io::Read + io::Seek> GameFile<'a, R> {
'a: 'b,
{
// Read the root directory
let root_dir = self.filesystem.root_dir().read_dir(self.cdrom).map_err(ReadDrvError::ReadRoot)?;
let root_dir = self
.filesystem
.root_dir()
.read_dir(self.cdrom)
.map_err(ReadDrvError::ReadRoot)?;
// Get the file
let entry = root_dir.find(name).ok_or(ReadDrvError::FindFile)?;

View File

@ -53,7 +53,9 @@ impl TimFile {
pub fn deserialize<R: io::Read + io::Seek>(reader: &mut R) -> Result<Self, DeserializeError> {
// Read the whole header
let mut header_bytes = [0u8; Self::HEADER_SIZE];
reader.read_exact(&mut header_bytes).map_err(DeserializeError::ReadHeader)?;
reader
.read_exact(&mut header_bytes)
.map_err(DeserializeError::ReadHeader)?;
let header_bytes = array_split!(&header_bytes,
magic : 0x1,

View File

@ -41,7 +41,9 @@ impl Clut {
pub fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, DeserializeError> {
// Read the whole header
let mut header_bytes = [0u8; Self::HEADER_SIZE];
reader.read_exact(&mut header_bytes).map_err(DeserializeError::ReadHeader)?;
reader
.read_exact(&mut header_bytes)
.map_err(DeserializeError::ReadHeader)?;
let header_bytes = array_split!(&header_bytes,
length: [0x4],
@ -65,10 +67,18 @@ impl Clut {
let mut colors = Vec::with_capacity(colors_len);
for _ in 0..colors_len {
let color = reader.read_u16::<LittleEndian>().map_err(DeserializeError::ReadColors)?;
let color = reader
.read_u16::<LittleEndian>()
.map_err(DeserializeError::ReadColors)?;
colors.push(color);
}
Ok(Self { x, y, width, height, colors })
Ok(Self {
x,
y,
width,
height,
colors,
})
}
}

View File

@ -61,9 +61,12 @@ impl Bytes for DecDateTime {
Ok(Self {
year: self::parse_decimal_string(bytes.year, [b'0', b'0', b'0', b'0'], [b'9', b'9', b'9', b'9'])
.ok_or_else(|| FromBytesError::Year(*bytes.year))?,
month: self::parse_decimal_string(bytes.month, [b'0', b'0'], [b'1', b'2']).ok_or_else(|| FromBytesError::Month(*bytes.month))?,
day: self::parse_decimal_string(bytes.day, [b'0', b'0'], [b'3', b'1']).ok_or_else(|| FromBytesError::Day(*bytes.day))?,
hour: self::parse_decimal_string(bytes.hour, [b'0', b'0'], [b'2', b'3']).ok_or_else(|| FromBytesError::Hour(*bytes.hour))?,
month: self::parse_decimal_string(bytes.month, [b'0', b'0'], [b'1', b'2'])
.ok_or_else(|| FromBytesError::Month(*bytes.month))?,
day: self::parse_decimal_string(bytes.day, [b'0', b'0'], [b'3', b'1'])
.ok_or_else(|| FromBytesError::Day(*bytes.day))?,
hour: self::parse_decimal_string(bytes.hour, [b'0', b'0'], [b'2', b'3'])
.ok_or_else(|| FromBytesError::Hour(*bytes.hour))?,
minutes: self::parse_decimal_string(bytes.minutes, [b'0', b'0'], [b'5', b'9'])
.ok_or_else(|| FromBytesError::Minute(*bytes.minutes))?,
seconds: self::parse_decimal_string(bytes.seconds, [b'0', b'0'], [b'5', b'9'])
@ -122,7 +125,8 @@ impl fmt::Debug for DecDateTime {
write!(
f,
"\"{year}-{month}-{day}T{hour}:{minutes}:{seconds}:{hundredths_sec}{time_zone_hours:+}:{time_zone_minutes}\""
"\"{year}-{month}-{day}T{hour}:{minutes}:{seconds}:{hundredths_sec}{time_zone_hours:+}:\
{time_zone_minutes}\""
)
}
}

View File

@ -60,7 +60,9 @@ impl DirEntry {
}
/// Reads a file from this entry
pub fn read_file<'a, R: io::Read + io::Seek>(&self, cdrom: &'a mut CdRomReader<R>) -> Result<FileReader<'a, R>, ReadFileError> {
pub fn read_file<'a, R: io::Read + io::Seek>(
&self, cdrom: &'a mut CdRomReader<R>,
) -> Result<FileReader<'a, R>, ReadFileError> {
// If this isn't a file, return Err
if !self.is_file() {
return Err(ReadFileError::NotAFile);
@ -121,7 +123,9 @@ impl DirEntry {
pub fn from_reader<R: io::Read>(reader: &mut R) -> Result<Self, FromReaderError> {
// Get the header
let mut header_bytes = [0; 0x21];
reader.read_exact(&mut header_bytes).map_err(FromReaderError::ReadHeader)?;
reader
.read_exact(&mut header_bytes)
.map_err(FromReaderError::ReadHeader)?;
let header_bytes = array_split!(&header_bytes,
record_size : 0x1,
@ -157,7 +161,9 @@ impl DirEntry {
// Then skip the remaining bytes
let mut remaining = vec![0; usize::from(header_bytes.record_size - 0x21 - header_bytes.name_len)];
reader.read_exact(&mut remaining).map_err(FromReaderError::ReadRemaining)?;
reader
.read_exact(&mut remaining)
.map_err(FromReaderError::ReadRemaining)?;
Ok(Self {
name,
@ -203,7 +209,9 @@ impl DirEntry {
writer.write_all(&header_bytes).map_err(ToWriterError::WriteHeader)?;
// Then write the name
writer.write_all(self.name.as_bytes()).map_err(ToWriterError::WriteName)?;
writer
.write_all(self.name.as_bytes())
.map_err(ToWriterError::WriteName)?;
Ok(())
}

View File

@ -69,7 +69,8 @@ impl<'a, R: io::Read> FileReader<'a, R> {
impl<'a, R: io::Read> io::Read for FileReader<'a, R> {
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
// If buffer would go past the end of the file, cut it.
let remaining_file_bytes = usize::try_from(self.remaining()).expect("Unable to get remaining file bytes as `usize`");
let remaining_file_bytes =
usize::try_from(self.remaining()).expect("Unable to get remaining file bytes as `usize`");
if buf.len() > remaining_file_bytes {
buf = &mut buf[..remaining_file_bytes];
}
@ -119,7 +120,9 @@ impl<'a, R: io::Seek> io::Seek for FileReader<'a, R> {
// If we don't end up in the same sector, flush our sector and seek to the next sector
if next_pos / 2048 != self.cur_pos / 2048 {
self.cached = None;
self.cdrom.seek_sector(self.sector_pos + next_pos / 2048).map_err(|err| err.err)?;
self.cdrom
.seek_sector(self.sector_pos + next_pos / 2048)
.map_err(|err| err.err)?;
}
// And set our position

View File

@ -103,18 +103,28 @@ impl FilesystemReader {
let mut sectors = cdrom.read_sectors();
let primary_volume_descriptor = loop {
match sectors.next() {
Some(Ok(sector)) => match VolumeDescriptor::from_bytes(sector.data.as_form1().ok_or(NewError::PrimaryFormatWrongForm)?) {
Ok(VolumeDescriptor::Primary(primary)) => break primary,
Ok(VolumeDescriptor::SetTerminator) => return Err(NewError::MissingPrimaryVolumeBeforeSetTerminator),
Ok(volume_descriptor) => log::debug!("Skipping {:?} volume descriptor before primary", volume_descriptor.kind()),
Err(err) => return Err(NewError::InvalidVolumeDescriptor(err)),
Some(Ok(sector)) => {
match VolumeDescriptor::from_bytes(sector.data.as_form1().ok_or(NewError::PrimaryFormatWrongForm)?)
{
Ok(VolumeDescriptor::Primary(primary)) => break primary,
Ok(VolumeDescriptor::SetTerminator) => {
return Err(NewError::MissingPrimaryVolumeBeforeSetTerminator)
},
Ok(volume_descriptor) => log::debug!(
"Skipping {:?} volume descriptor before primary",
volume_descriptor.kind()
),
Err(err) => return Err(NewError::InvalidVolumeDescriptor(err)),
}
},
Some(Err(err)) => return Err(NewError::InvalidSectorBeforeSetTerminator(err)),
None => return Err(NewError::EofBeforeSetTerminator),
}
};
Ok(Self { primary_volume_descriptor })
Ok(Self {
primary_volume_descriptor,
})
}
/// Returns the primary volume descriptor

View File

@ -72,9 +72,10 @@ pub struct AlphabetA;
impl OnlyValidCharsAlphabet for AlphabetA {
fn valid_chars() -> &'static [u8] {
&[
b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
b'X', b'Y', b'Z', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'_', b'!', b'"', b'%', b'&', b'\'', b'(', b')', b'*',
b'+', b',', b'-', b'.', b'/', b':', b';', b'<', b'=', b'>', b'?',
b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R',
b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9',
b'_', b'!', b'"', b'%', b'&', b'\'', b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', b':', b';', b'<',
b'=', b'>', b'?',
]
}
@ -92,8 +93,9 @@ pub struct AlphabetD;
impl OnlyValidCharsAlphabet for AlphabetD {
fn valid_chars() -> &'static [u8] {
&[
b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
b'X', b'Y', b'Z', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'_',
b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R',
b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9',
b'_',
]
}
@ -129,12 +131,18 @@ impl Alphabet for FileAlphabet {
// Separate into `<name>.<extension>;<version>`
let (name, extension, version) = {
// Separate into `<name>.<rest>` and ignore the `.` in `<rest>`
let dot_idx = bytes.iter().position(|&b| b == b'.').ok_or(ValidateFileAlphabetError::MissingExtension)?;
let dot_idx = bytes
.iter()
.position(|&b| b == b'.')
.ok_or(ValidateFileAlphabetError::MissingExtension)?;
let (name, rest) = bytes.split_at(dot_idx);
let rest = &rest[1..];
// Then split at `<extension>;<version>` and ignore the `;`
let version_idx = rest.iter().position(|&b| b == b';').ok_or(ValidateFileAlphabetError::MissingVersion)?;
let version_idx = rest
.iter()
.position(|&b| b == b';')
.ok_or(ValidateFileAlphabetError::MissingVersion)?;
let (extension, version) = rest.split_at(version_idx);
let version = &version[1..];

View File

@ -131,13 +131,20 @@ impl Bytes for PrimaryVolumeDescriptor {
path_table_opt_location: LittleEndian::read_u32(bytes.path_table_lsb_opt_location),
root_dir_entry: DirEntry::from_reader(&mut std::io::Cursor::new(bytes.root_dir_entry))
.map_err(FromBytesError::RootDirEntry)?,
volume_set_id: StrArrD::from_bytes(bytes.volume_set_id).map_err(FromBytesError::VolumeSetId)?,
publisher_id: StrArrA::from_bytes(bytes.publisher_id).map_err(FromBytesError::PublisherId)?,
data_preparer_id: StrArrA::from_bytes(bytes.data_preparer_id).map_err(FromBytesError::DataPreparerId)?,
application_id: StrArrA::from_bytes(bytes.application_id).map_err(FromBytesError::ApplicationId)?,
copyright_file_id: StrArrD::from_bytes(bytes.copyright_file_id).map_err(FromBytesError::CopyrightFileId)?,
abstract_file_id: StrArrD::from_bytes(bytes.abstract_file_id).map_err(FromBytesError::AbstractFileId)?,
bibliographic_file_id: StrArrD::from_bytes(bytes.bibliographic_file_id).map_err(FromBytesError::BibliographicFileId)?,
volume_set_id: StrArrD::from_bytes(bytes.volume_set_id)
.map_err(FromBytesError::VolumeSetId)?,
publisher_id: StrArrA::from_bytes(bytes.publisher_id)
.map_err(FromBytesError::PublisherId)?,
data_preparer_id: StrArrA::from_bytes(bytes.data_preparer_id)
.map_err(FromBytesError::DataPreparerId)?,
application_id: StrArrA::from_bytes(bytes.application_id)
.map_err(FromBytesError::ApplicationId)?,
copyright_file_id: StrArrD::from_bytes(bytes.copyright_file_id)
.map_err(FromBytesError::CopyrightFileId)?,
abstract_file_id: StrArrD::from_bytes(bytes.abstract_file_id)
.map_err(FromBytesError::AbstractFileId)?,
bibliographic_file_id: StrArrD::from_bytes(bytes.bibliographic_file_id)
.map_err(FromBytesError::BibliographicFileId)?,
volume_creation_date_time: DecDateTime::from_bytes(bytes.volume_creation_date_time)
.map_err(FromBytesError::VolumeCreationDateTime)?,
volume_modification_date_time: DecDateTime::from_bytes(bytes.volume_modification_date_time)
@ -206,10 +213,18 @@ impl Bytes for PrimaryVolumeDescriptor {
self.copyright_file_id.to_bytes(bytes.copyright_file_id);
self.abstract_file_id.to_bytes(bytes.abstract_file_id);
self.bibliographic_file_id.to_bytes(bytes.bibliographic_file_id);
self.volume_creation_date_time.to_bytes(bytes.volume_creation_date_time).into_ok();
self.volume_modification_date_time.to_bytes(bytes.volume_modification_date_time).into_ok();
self.volume_expiration_date_time.to_bytes(bytes.volume_expiration_date_time).into_ok();
self.volume_effective_date_time.to_bytes(bytes.volume_effective_date_time).into_ok();
self.volume_creation_date_time
.to_bytes(bytes.volume_creation_date_time)
.into_ok();
self.volume_modification_date_time
.to_bytes(bytes.volume_modification_date_time)
.into_ok();
self.volume_expiration_date_time
.to_bytes(bytes.volume_expiration_date_time)
.into_ok();
self.volume_effective_date_time
.to_bytes(bytes.volume_effective_date_time)
.into_ok();
Ok(())
}

View File

@ -42,7 +42,9 @@ impl<R: io::Read + io::Seek> PakFileReader<R> {
/// Returns the next entry
pub fn next_entry(&mut self) -> Result<Option<PakEntryReader<R>>, NextEntryError> {
// Seek to our current position
self.reader.seek(SeekFrom::Start(self.cur_pos)).map_err(NextEntryError::SeekNextEntry)?;
self.reader
.seek(SeekFrom::Start(self.cur_pos))
.map_err(NextEntryError::SeekNextEntry)?;
// Try to read an entry
let entry = match PakEntryReader::from_reader(&mut self.reader).map_err(NextEntryError::ReadEntry)? {

View File

@ -35,7 +35,9 @@ impl<'a, R: io::Read> PakEntryReader<'a, R> {
// Read the header
// Note: We do a two-part read so we can quit early if we find `0xffffffff`
let mut header_bytes = [0u8; 0x8];
reader.read_exact(&mut header_bytes[..0x4]).map_err(FromReaderError::ReadHeader)?;
reader
.read_exact(&mut header_bytes[..0x4])
.map_err(FromReaderError::ReadHeader)?;
// If we found `0xffffffff`, this is the final header, return
if header_bytes[..0x4] == [0xff; 4] {
@ -43,7 +45,9 @@ impl<'a, R: io::Read> PakEntryReader<'a, R> {
}
// Then read the rest and parse the header
reader.read_exact(&mut header_bytes[0x4..]).map_err(FromReaderError::ReadHeader)?;
reader
.read_exact(&mut header_bytes[0x4..])
.map_err(FromReaderError::ReadHeader)?;
let header = Header::from_bytes(&header_bytes).map_err(FromReaderError::ParseHeader)?;
Ok(Some(Self { header, reader }))

View File

@ -58,7 +58,9 @@ impl Animation2d {
pub fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, DeserializeError> {
// Read the header
let mut header_bytes = [0; Self::HEADER_SIZE];
reader.read_exact(&mut header_bytes).map_err(DeserializeError::ReadHeader)?;
reader
.read_exact(&mut header_bytes)
.map_err(DeserializeError::ReadHeader)?;
let header_bytes = array_split!(&header_bytes,
file_name : [0xc],
@ -72,13 +74,18 @@ impl Animation2d {
unknown6 : [0x4],
);
let file_name = header_bytes.file_name.read_string().map_err(DeserializeError::ParseName)?;
let file_name = header_bytes
.file_name
.read_string()
.map_err(DeserializeError::ParseName)?;
let frames_len = LittleEndian::read_u32(header_bytes.frames_len);
let mut frames = vec![];
for _ in 0..frames_len {
let mut frame_bytes = [0; 0x14];
reader.read_exact(&mut frame_bytes).map_err(DeserializeError::ReadFrame)?;
reader
.read_exact(&mut frame_bytes)
.map_err(DeserializeError::ReadFrame)?;
let frame = Frame::from_bytes(&frame_bytes).into_ok();
frames.push(frame);

View File

@ -36,7 +36,9 @@ impl Model3dSet {
pub fn from_reader<R: io::Read + io::Seek>(reader: &mut R) -> Result<Self, FromReaderError> {
// Read the header
let mut header_bytes = [0; Self::HEADER_SIZE];
reader.read_exact(&mut header_bytes).map_err(FromReaderError::ReadHeader)?;
reader
.read_exact(&mut header_bytes)
.map_err(FromReaderError::ReadHeader)?;
let header_bytes = array_split!(&header_bytes,
file_name : [0x10],
@ -44,12 +46,18 @@ impl Model3dSet {
unknown0 : [0x20],
);
let file_name = header_bytes.file_name.read_string().map_err(FromReaderError::ParseName)?;
let models_len = usize::try_from(LittleEndian::read_u32(header_bytes.models_len)).expect("Model length didn't fit into `usize`");
let file_name = header_bytes
.file_name
.read_string()
.map_err(FromReaderError::ParseName)?;
let models_len = usize::try_from(LittleEndian::read_u32(header_bytes.models_len))
.expect("Model length didn't fit into `usize`");
// Read the unknown 1
let mut unknown1_bytes = vec![0; models_len * 3 * 4];
reader.read_exact(&mut unknown1_bytes).map_err(FromReaderError::ReadUnknown1)?;
reader
.read_exact(&mut unknown1_bytes)
.map_err(FromReaderError::ReadUnknown1)?;
// Read the models
let mut models = vec![];

View File

@ -33,7 +33,9 @@ impl TmdModel {
pub fn from_reader<R: io::Read + io::Seek>(reader: &mut R) -> Result<Self, FromReaderError> {
// Read the header
let mut header_bytes = [0; Self::HEADER_SIZE];
reader.read_exact(&mut header_bytes).map_err(FromReaderError::ReadHeader)?;
reader
.read_exact(&mut header_bytes)
.map_err(FromReaderError::ReadHeader)?;
let header_bytes = array_split!(&header_bytes,
magic : [0x4],
flags : [0x4],
@ -51,7 +53,8 @@ impl TmdModel {
todo!("Flags other than `0x0` ({:#x}) are not supported", flags);
}
let objs_len = usize::try_from(LittleEndian::read_u32(header_bytes.objs_len)).expect("Unable to get object number as `usize`");
let objs_len = usize::try_from(LittleEndian::read_u32(header_bytes.objs_len))
.expect("Unable to get object number as `usize`");
// TODO: Support more than 1 object
if objs_len != 1 {

View File

@ -33,14 +33,19 @@ use std::{
fn main() -> Result<(), anyhow::Error> {
// Initialize the logger
simplelog::TermLogger::init(log::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr)
.expect("Unable to initialize logger");
simplelog::TermLogger::init(
log::LevelFilter::Info,
simplelog::Config::default(),
simplelog::TerminalMode::Stderr,
)
.expect("Unable to initialize logger");
// Get all data from cli
let cli = cli::CliData::new();
// Get the header
let header_file = fs::File::open(&cli.header_path).with_context(|| format!("Unable to open header file {}", cli.header_path.display()))?;
let header_file = fs::File::open(&cli.header_path)
.with_context(|| format!("Unable to open header file {}", cli.header_path.display()))?;
let header: Header = serde_yaml::from_reader(header_file).context("Unable to read header file")?;
// Open the input and output file
@ -70,7 +75,12 @@ fn main() -> Result<(), anyhow::Error> {
.range(..=cur_pos)
.filter_map(|(_, label)| label.as_global())
.next_back()
.ok_or_else(|| (n, anyhow::anyhow!("Cannot define a local label before any global labels")))?;
.ok_or_else(|| {
(
n,
anyhow::anyhow!("Cannot define a local label before any global labels"),
)
})?;
// Then insert it
let mut name = label.name;
@ -79,7 +89,9 @@ fn main() -> Result<(), anyhow::Error> {
Label::Local { name: LabelName(name) }
},
// It's global
false => Label::Global { name: LabelName(label.name) },
false => Label::Global {
name: LabelName(label.name),
},
};
@ -102,7 +114,12 @@ fn main() -> Result<(), anyhow::Error> {
.range(..=cur_pos)
.filter_map(|(_, label)| label.as_global())
.next_back()
.ok_or_else(|| (n, anyhow::anyhow!("Cannot define a local label before any global labels")))?;
.ok_or_else(|| {
(
n,
anyhow::anyhow!("Cannot define a local label before any global labels"),
)
})?;
// Then insert it
name.insert_str(0, prev_label_name);
@ -129,8 +146,10 @@ fn main() -> Result<(), anyhow::Error> {
};
// Read all foreign data as labels.
let foreign_data_file = std::fs::File::open("resources/foreign_data.yaml").context("Unable to open foreign data file")?;
let foreign_data: Vec<Data> = serde_yaml::from_reader(foreign_data_file).context("Unable to read foreign data file")?;
let foreign_data_file =
std::fs::File::open("resources/foreign_data.yaml").context("Unable to open foreign data file")?;
let foreign_data: Vec<Data> =
serde_yaml::from_reader(foreign_data_file).context("Unable to read foreign data file")?;
for data in foreign_data {
let (pos, name) = data.into_label();
labels_by_name.insert(name, pos);
@ -149,8 +168,8 @@ fn main() -> Result<(), anyhow::Error> {
labels_by_name: &labels_by_name,
};
let inst =
Inst::parse(&inst.mnemonic, &inst.args, &ctx).with_context(|| format!("Unable to compile instruction at {} in line {}", pos, n + 1))?;
let inst = Inst::parse(&inst.mnemonic, &inst.args, &ctx)
.with_context(|| format!("Unable to compile instruction at {} in line {}", pos, n + 1))?;
inst.write(&mut output_file).context("Unable to write to file")?;
}
@ -172,10 +191,14 @@ fn main() -> Result<(), anyhow::Error> {
initial_sp_offset: header.initial_sp_offset,
marker: header.marker,
};
output_file.seek(SeekFrom::Start(0)).context("Unable to seek stream to beginning")?;
output_file
.seek(SeekFrom::Start(0))
.context("Unable to seek stream to beginning")?;
let mut header_bytes = [0; 0x800];
header.to_bytes(&mut header_bytes).into_ok();
output_file.write_all(&header_bytes).context("Unable to write header to output file")?;
output_file
.write_all(&header_bytes)
.context("Unable to write header to output file")?;
Ok(())
}

View File

@ -25,8 +25,12 @@ use std::{collections::BTreeMap, fmt, path::PathBuf};
fn main() -> Result<(), anyhow::Error> {
// Initialize the logger
simplelog::TermLogger::init(log::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr)
.expect("Unable to initialize logger");
simplelog::TermLogger::init(
log::LevelFilter::Info,
simplelog::Config::default(),
simplelog::TerminalMode::Stderr,
)
.expect("Unable to initialize logger");
// Get all data from cli
let cli = cli::CliData::new();
@ -208,7 +212,9 @@ fn main() -> Result<(), anyhow::Error> {
/// Returns a display-able for an instruction inside a possible function
#[must_use]
pub fn inst_display<'a>(inst: &'a Inst, exe: &'a ExeReader, func: Option<&'a Func>, pos: Pos) -> impl fmt::Display + 'a {
pub fn inst_display<'a>(
inst: &'a Inst, exe: &'a ExeReader, func: Option<&'a Func>, pos: Pos,
) -> impl fmt::Display + 'a {
// Overload the target of as many as possible using `inst_target`.
dcb_util::DisplayWrapper::new(move |f| {
// Build the context and get the mnemonic + args
@ -284,7 +290,13 @@ impl<'a> DisplayCtx for Ctx<'a> {
if let Some(func) = self.exe.func_table().get_containing(pos) {
// And then one of it's labels
if let Some(label) = func.labels.get(&pos) {
return Some((LabelDisplay::OtherFuncLabel { func: &func.name, label }, 0));
return Some((
LabelDisplay::OtherFuncLabel {
func: &func.name,
label,
},
0,
));
}
// Else just any position in it

View File

@ -22,11 +22,19 @@ impl CliData {
.version("0.1")
.author("Filipe [...] <[...]@gmail.com>")
.about("Coverts an ISO 9660 filesystem file to a `.bin` file in the CdRom/XA format")
.arg(ClapArg::with_name("INPUT_FILE").help("The input file to use").required(true).index(1))
.arg(
ClapArg::with_name("INPUT_FILE")
.help("The input file to use")
.required(true)
.index(1),
)
.arg(
ClapArg::with_name("OUTPUT")
.help("The file to output to")
.long_help("The file to output to. If not specified, a file with the input's name appended by `.bin` will be used")
.long_help(
"The file to output to. If not specified, a file with the input's name appended by `.bin` \
will be used",
)
.short("o")
.long("output")
.takes_value(true)
@ -56,6 +64,9 @@ impl CliData {
};
// Return the data
Self { input_file, output_file }
Self {
input_file,
output_file,
}
}
}

View File

@ -18,11 +18,18 @@ use std::{
fn main() -> Result<(), anyhow::Error> {
// Initialize the logger
simplelog::TermLogger::init(log::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr)
.expect("Unable to initialize logger");
simplelog::TermLogger::init(
log::LevelFilter::Info,
simplelog::Config::default(),
simplelog::TerminalMode::Stderr,
)
.expect("Unable to initialize logger");
// Get all data from cli
let cli::CliData { input_file, output_file } = cli::CliData::new();
let cli::CliData {
input_file,
output_file,
} = cli::CliData::new();
// Try to pack it into a `CdRom/XA`
self::pack_cdrom_xa(&input_file, &output_file).context("Unable to pack file")?;

View File

@ -22,11 +22,19 @@ impl CliData {
.version("0.1")
.author("Filipe [...] <[...]@gmail.com>")
.about("Packs a folder into a `.drv` file")
.arg(ClapArg::with_name("INPUT_DIR").help("The input directory to use").required(true).index(1))
.arg(
ClapArg::with_name("INPUT_DIR")
.help("The input directory to use")
.required(true)
.index(1),
)
.arg(
ClapArg::with_name("OUTPUT")
.help("The file to output to")
.long_help("The file to output to. If not specified, a file with the directory's name appended by `.drv` will be used")
.long_help(
"The file to output to. If not specified, a file with the directory's name appended by `.drv` \
will be used",
)
.short("o")
.long("output")
.takes_value(true)

View File

@ -107,7 +107,10 @@ impl IntoIterator for DirLister {
.duration_since(SystemTime::UNIX_EPOCH)
.map_err(NextError::EntryDateSinceEpoch)?
.as_secs();
let date = chrono::NaiveDateTime::from_timestamp(i64::try_from(secs_since_epoch).map_err(|_err| NextError::EntryDateI64Secs)?, 0);
let date = chrono::NaiveDateTime::from_timestamp(
i64::try_from(secs_since_epoch).map_err(|_err| NextError::EntryDateI64Secs)?,
0,
);
// Check if it's a directory or file
let kind = match entry.metadata.is_dir() {

View File

@ -15,8 +15,12 @@ use std::{fs, path::Path};
fn main() -> Result<(), anyhow::Error> {
// Initialize the logger
simplelog::TermLogger::init(log::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr)
.expect("Unable to initialize logger");
simplelog::TermLogger::init(
log::LevelFilter::Info,
simplelog::Config::default(),
simplelog::TerminalMode::Stderr,
)
.expect("Unable to initialize logger");
// Get all data from cli
let cli::CliData { input_dir, output_file } = cli::CliData::new();
@ -33,13 +37,19 @@ fn pack_filesystem(input_dir: &Path, output_file: &Path) -> Result<(), anyhow::E
let mut output_file = fs::File::create(output_file).context("Unable to create output file")?;
// Create the filesystem writer
let root_entries = dir_lister::DirLister::new(input_dir).context("Unable to create new dir lister for root directory")?;
let root_entries =
dir_lister::DirLister::new(input_dir).context("Unable to create new dir lister for root directory")?;
DrvFsWriter::write_fs(&mut output_file, root_entries).context("Unable to write filesystem")?;
// Then pad the file to a sector `2048` if it isn't already
let len = output_file.metadata().context("Unable to get output file metadata")?.len();
let len = output_file
.metadata()
.context("Unable to get output file metadata")?
.len();
if len % 2048 != 0 {
output_file.set_len(2048 * ((len + 2047) / 2048)).context("Unable to set file length")?;
output_file
.set_len(2048 * ((len + 2047) / 2048))
.context("Unable to set file length")?;
}
Ok(())

View File

@ -13,8 +13,12 @@ use std::{fs, path::PathBuf};
fn main() -> Result<(), anyhow::Error> {
// Initialize the logger
simplelog::TermLogger::init(log::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr)
.expect("Unable to initialize logger");
simplelog::TermLogger::init(
log::LevelFilter::Info,
simplelog::Config::default(),
simplelog::TerminalMode::Stderr,
)
.expect("Unable to initialize logger");
// Get all data from cli
let cli_data = CliData::new();

View File

@ -22,11 +22,19 @@ impl CliData {
.version("0.1")
.author("Filipe [...] <[...]@gmail.com>")
.about("Coverts a `.bin` in the CdRom/XA format to a ISO 9660 filesystem file")
.arg(ClapArg::with_name("INPUT_FILE").help("The input file to use").required(true).index(1))
.arg(
ClapArg::with_name("INPUT_FILE")
.help("The input file to use")
.required(true)
.index(1),
)
.arg(
ClapArg::with_name("OUTPUT")
.help("The file to output to")
.long_help("The file to output to. If not specified, a file with the input's name changed by `.iso` will be used")
.long_help(
"The file to output to. If not specified, a file with the input's name changed by `.iso` will \
be used",
)
.short("o")
.long("output")
.takes_value(true)
@ -50,6 +58,9 @@ impl CliData {
};
// Return the data
Self { input_file, output_file }
Self {
input_file,
output_file,
}
}
}

View File

@ -11,11 +11,18 @@ use std::{fs, io::Write, path::Path};
fn main() -> Result<(), anyhow::Error> {
// Initialize the logger
simplelog::TermLogger::init(log::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr)
.expect("Unable to initialize logger");
simplelog::TermLogger::init(
log::LevelFilter::Info,
simplelog::Config::default(),
simplelog::TerminalMode::Stderr,
)
.expect("Unable to initialize logger");
// Get all data from cli
let cli::CliData { input_file, output_file } = cli::CliData::new();
let cli::CliData {
input_file,
output_file,
} = cli::CliData::new();
// Try to extract it into a `iso`
self::extract_cdrom_xa(&input_file, &output_file).context("Unable to extract file")?;
@ -36,7 +43,9 @@ fn extract_cdrom_xa(input_file: &Path, output_file: &Path) -> Result<(), anyhow:
for sector in input_file.read_sectors() {
let sector = sector.context("Unable to read sector")?;
output_file.write_all(sector.data.as_ref()).context("Unable to write data")?;
output_file
.write_all(sector.data.as_ref())
.context("Unable to write data")?;
}
Ok(())

View File

@ -42,8 +42,8 @@ impl CliData {
ClapArg::with_name(OUTPUT_DIR_STR)
.help("The directory to output to")
.long_help(
"The directory to output to. If not specified, the parent of the input file is used. If it doesn't exist, the current \
directory is used",
"The directory to output to. If not specified, the parent of the input file is used. If it \
doesn't exist, the current directory is used",
)
.short("o")
.long("output-dir")
@ -53,7 +53,8 @@ impl CliData {
ClapArg::with_name(QUIET_STR)
.help("Suppresses listing of extracted files")
.long_help(
"Suppresses printing on `stdout` of this program. If any errors or warnings occur, they will still be printed to stderr",
"Suppresses printing on `stdout` of this program. If any errors or warnings occur, they will \
still be printed to stderr",
)
.short("q")
.long("quiet"),
@ -61,7 +62,9 @@ impl CliData {
.arg(
ClapArg::with_name(WARN_ON_OVERRIDE_STR)
.help("Warns when overriding files that already exist.")
.long_help("Warns if this program would override existing files. By default no warnings are produced.")
.long_help(
"Warns if this program would override existing files. By default no warnings are produced.",
)
.long("warn-on-override"),
)
.get_matches();

View File

@ -14,8 +14,12 @@ use std::{
fn main() -> Result<(), anyhow::Error> {
// Initialize the logger
simplelog::TermLogger::init(log::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr)
.expect("Unable to initialize logger");
simplelog::TermLogger::init(
log::LevelFilter::Info,
simplelog::Config::default(),
simplelog::TerminalMode::Stderr,
)
.expect("Unable to initialize logger");
// Get all data from cli
let cli_data = CliData::new();
@ -37,7 +41,8 @@ fn main() -> Result<(), anyhow::Error> {
let mut input_file = io::BufReader::new(input_file);
// Create output directory if it doesn't exist
dcb_util::try_create_folder(&output_dir).with_context(|| format!("Unable to create directory {}", output_dir.display()))?;
dcb_util::try_create_folder(&output_dir)
.with_context(|| format!("Unable to create directory {}", output_dir.display()))?;
// Then extract the tree
if let Err(err) = self::extract_tree(&mut input_file, &DrvFsReader::root(), &output_dir, &cli_data) {
@ -59,7 +64,9 @@ fn main() -> Result<(), anyhow::Error> {
}
/// Extracts a `.drv` file from a reader and starting directory
fn extract_tree<R: io::Read + io::Seek>(reader: &mut R, dir: &DirReader, path: &Path, cli_data: &CliData) -> Result<(), anyhow::Error> {
fn extract_tree<R: io::Read + io::Seek>(
reader: &mut R, dir: &DirReader, path: &Path, cli_data: &CliData,
) -> Result<(), anyhow::Error> {
// Get all entries
// Note: We need to collect to free the reader so it can seek to the next files.
let entries: Vec<_> = dir
@ -89,7 +96,11 @@ fn extract_tree<R: io::Read + io::Seek>(reader: &mut R, dir: &DirReader, path: &
DirEntryReaderKind::File(file) => {
// Log the file and it's size
if !cli_data.quiet {
println!("{} ({}B)", path.display(), size_format::SizeFormatterSI::new(u64::from(file.size())));
println!(
"{} ({}B)",
path.display(),
size_format::SizeFormatterSI::new(u64::from(file.size()))
);
}
// If the output file already exists, log a warning
@ -98,15 +109,23 @@ fn extract_tree<R: io::Read + io::Seek>(reader: &mut R, dir: &DirReader, path: &
}
// Get the file's reader.
let mut file_reader = file.reader(reader).with_context(|| format!("Unable to read file {}", path.display()))?;
let mut file_reader = file
.reader(reader)
.with_context(|| format!("Unable to read file {}", path.display()))?;
// Then create the output file and copy.
let mut output_file = fs::File::create(&path).with_context(|| format!("Unable to create file {}", path.display()))?;
std::io::copy(&mut file_reader, &mut output_file).with_context(|| format!("Unable to write file {}", path.display()))?;
let mut output_file =
fs::File::create(&path).with_context(|| format!("Unable to create file {}", path.display()))?;
std::io::copy(&mut file_reader, &mut output_file)
.with_context(|| format!("Unable to write file {}", path.display()))?;
// And set the file's modification time
if let Err(err) = filetime::set_file_handle_times(&output_file, None, Some(time)) {
log::warn!("Unable to write date for file {}: {}", path.display(), dcb_util::fmt_err_wrapper(&err));
log::warn!(
"Unable to write date for file {}: {}",
path.display(),
dcb_util::fmt_err_wrapper(&err)
);
}
},
@ -118,8 +137,10 @@ fn extract_tree<R: io::Read + io::Seek>(reader: &mut R, dir: &DirReader, path: &
}
// Create the directory and recurse over it
dcb_util::try_create_folder(&path).with_context(|| format!("Unable to create directory {}", path.display()))?;
self::extract_tree(reader, dir, &path, &cli_data).with_context(|| format!("Unable to extract directory {}", path.display()))?;
dcb_util::try_create_folder(&path)
.with_context(|| format!("Unable to create directory {}", path.display()))?;
self::extract_tree(reader, dir, &path, &cli_data)
.with_context(|| format!("Unable to extract directory {}", path.display()))?;
// Then set it's date
// Note: We must do this *after* extracting the tree, else the time

View File

@ -36,8 +36,8 @@ impl CliData {
ClapArg::with_name(OUTPUT_DIR_STR)
.help("The directory to output to")
.long_help(
"The directory to output to. If not specified, the parent of the input file is used. If it doesn't exist, the current \
directory is used",
"The directory to output to. If not specified, the parent of the input file is used. If it \
doesn't exist, the current directory is used",
)
.short("o")
.long("output-dir")

View File

@ -16,8 +16,12 @@ use std::{fs, io, path::PathBuf};
fn main() -> Result<(), anyhow::Error> {
// Initialize the logger
simplelog::TermLogger::init(log::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr)
.expect("Unable to initialize logger");
simplelog::TermLogger::init(
log::LevelFilter::Info,
simplelog::Config::default(),
simplelog::TerminalMode::Stderr,
)
.expect("Unable to initialize logger");
// Get all data from cli
let cli_data = CliData::new();
@ -32,7 +36,8 @@ fn main() -> Result<(), anyhow::Error> {
};
// Create output directory if it doesn't exist
dcb_util::try_create_folder(&output_dir).with_context(|| format!("Unable to create directory {}", output_dir.display()))?;
dcb_util::try_create_folder(&output_dir)
.with_context(|| format!("Unable to create directory {}", output_dir.display()))?;
// Open the file.
let input_file = fs::File::open(&cli_data.input_file).context("Unable to open input file")?;
@ -51,7 +56,9 @@ fn main() -> Result<(), anyhow::Error> {
let date_time_to_string = |date_time: DecDateTime| {
let mut bytes = [0; 0x11];
date_time.to_bytes(&mut bytes).into_ok();
std::str::from_utf8(&bytes).expect("Date time was invalid utf8").to_owned()
std::str::from_utf8(&bytes)
.expect("Date time was invalid utf8")
.to_owned()
};
let volume = fs_reader.primary_volume_descriptor();

View File

@ -44,8 +44,8 @@ impl CliData {
ClapArg::with_name(OUTPUT_DIR_STR)
.help("The directory to output to")
.long_help(
"The directory to output to. If not specified, the parent of the input file is used. If it doesn't exist, the current \
directory is used",
"The directory to output to. If not specified, the parent of the input file is used. If it \
doesn't exist, the current directory is used",
)
.short("o")
.long("output-dir")
@ -55,7 +55,8 @@ impl CliData {
ClapArg::with_name(QUIET_STR)
.help("Suppresses listing of extracted files")
.long_help(
"Suppresses printing on `stdout` of this program. If any errors or warnings occur, they will still be printed to stderr",
"Suppresses printing on `stdout` of this program. If any errors or warnings occur, they will \
still be printed to stderr",
)
.short("q")
.long("quiet"),
@ -63,7 +64,9 @@ impl CliData {
.arg(
ClapArg::with_name(WARN_ON_OVERRIDE_STR)
.help("Warns when overriding files that already exist.")
.long_help("Warns if this program would override existing files. By default no warnings are produced.")
.long_help(
"Warns if this program would override existing files. By default no warnings are produced.",
)
.long("warn-on-override"),
)
.arg(

View File

@ -15,8 +15,12 @@ use std::{
fn main() -> Result<(), anyhow::Error> {
// Initialize the logger
simplelog::TermLogger::init(log::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr)
.expect("Unable to initialize logger");
simplelog::TermLogger::init(
log::LevelFilter::Info,
simplelog::Config::default(),
simplelog::TerminalMode::Stderr,
)
.expect("Unable to initialize logger");
// Get all data from cli
let cli_data = CliData::new();
@ -50,7 +54,8 @@ fn extract_file(input_file_path: &Path, output_dir: &Path, cli_data: &CliData) -
// Try to create the output directory if we're not just listing
if !cli_data.only_list {
dcb_util::try_create_folder(output_dir).with_context(|| format!("Unable to create directory {}", output_dir.display()))?;
dcb_util::try_create_folder(output_dir)
.with_context(|| format!("Unable to create directory {}", output_dir.display()))?;
}
// Then read all entries
@ -97,8 +102,10 @@ fn extract_file(input_file_path: &Path, output_dir: &Path, cli_data: &CliData) -
log::warn!("Overriding file {}", path.display());
}
let mut output_file = fs::File::create(&path).with_context(|| format!("Unable to create file {}", path.display()))?;
io::copy(&mut contents, &mut output_file).with_context(|| format!("Unable to write file {}", path.display()))?;
let mut output_file =
fs::File::create(&path).with_context(|| format!("Unable to create file {}", path.display()))?;
io::copy(&mut contents, &mut output_file)
.with_context(|| format!("Unable to write file {}", path.display()))?;
}
Ok(())

View File

@ -11,7 +11,12 @@ type BoxedLogger = Box<dyn SharedLogger>;
pub fn init() {
// All loggers to try and initialize
let loggers = [
Some(TermLogger::new(LevelFilter::Info, Config::default(), TerminalMode::Stderr)).map(|logger| BoxedLogger::from(logger)),
Some(TermLogger::new(
LevelFilter::Info,
Config::default(),
TerminalMode::Stderr,
))
.map(|logger| BoxedLogger::from(logger)),
std::fs::File::create("latest.log")
.ok()
.map(|file| WriteLogger::new(LevelFilter::Debug, Config::default(), file))

View File

@ -33,7 +33,8 @@ fn extract_file(input_file: &Path, output_dir: &Path) -> Result<(), anyhow::Erro
let model_set = Model3dSet::from_reader(&mut input_file).context("Unable to parse file")?;
dcb_util::try_create_folder(output_dir).with_context(|| format!("Unable to create directory {}", output_dir.display()))?;
dcb_util::try_create_folder(output_dir)
.with_context(|| format!("Unable to create directory {}", output_dir.display()))?;
for (idx, (pos, size, ..)) in model_set.models.iter().enumerate() {
// Get the filename
let path = output_dir.join(format!("{}.TMD", idx));
@ -50,8 +51,10 @@ fn extract_file(input_file: &Path, output_dir: &Path) -> Result<(), anyhow::Erro
if path.exists() {
log::warn!("Overriding file {}", path.display());
}
let mut output_file = std::fs::File::create(&path).with_context(|| format!("Unable to create file {}", path.display()))?;
std::io::copy(&mut input_file, &mut output_file).with_context(|| format!("Unable to write file {}", path.display()))?;
let mut output_file =
std::fs::File::create(&path).with_context(|| format!("Unable to create file {}", path.display()))?;
std::io::copy(&mut input_file, &mut output_file)
.with_context(|| format!("Unable to write file {}", path.display()))?;
}
Ok(())

View File

@ -131,7 +131,10 @@ impl<const N: usize> AsciiStrArr<N> {
*uninit = ascii;
}
Ok(Self { chars, len: ascii.len() })
Ok(Self {
chars,
len: ascii.len(),
})
}
/// Creates a string from bytes
@ -312,7 +315,10 @@ impl<const N: usize> TryFrom<&[u8; N]> for AsciiStrArr<N> {
*ascii = AsciiChar::from_ascii(byte).map_err(|_err| NotAsciiError { pos })?;
}
Ok(Self { chars, len: byte_str.len() })
Ok(Self {
chars,
len: byte_str.len(),
})
}
}

View File

@ -76,7 +76,9 @@ where
(None, Some((key, right))) => Some((key, ParIterValue::Right(right))),
// If we got both with equal keys, return them both
(Some((left_key, left)), Some((right_key, right))) if left_key == right_key => Some((left_key, ParIterValue::Both(left, right))),
(Some((left_key, left)), Some((right_key, right))) if left_key == right_key => {
Some((left_key, ParIterValue::Both(left, right)))
},
// If we got both, but without equal keys, emit the first and store the other.
// Note: In all of these branches, `self.value` is empty, as we call both `self.next_{left, right}` functions.

View File

@ -8,8 +8,8 @@ pub use error::{FromBytesError, ToBytesError};
// Imports
use crate::card::property::{
ArrowColor, CrossMoveEffect, Effect, EffectCondition, Level, MaybeArrowColor, MaybeCrossMoveEffect, MaybeEffect, MaybeEffectCondition, Move,
Speciality,
ArrowColor, CrossMoveEffect, Effect, EffectCondition, Level, MaybeArrowColor, MaybeCrossMoveEffect, MaybeEffect,
MaybeEffectCondition, Move, Speciality,
};
use byteorder::{ByteOrder, LittleEndian};
use dcb_bytes::Bytes;
@ -124,7 +124,8 @@ impl Bytes for Digimon {
Ok(Self {
name: NullAsciiString::read_string(bytes.name).map_err(FromBytesError::Name)?,
speciality: Speciality::from_bytes(&((bytes.speciality_level & 0xF0) >> 4u8)).map_err(FromBytesError::Speciality)?,
speciality: Speciality::from_bytes(&((bytes.speciality_level & 0xF0) >> 4u8))
.map_err(FromBytesError::Speciality)?,
level: Level::from_bytes(&(bytes.speciality_level & 0x0F)).map_err(FromBytesError::Level)?,
@ -149,9 +150,15 @@ impl Bytes for Digimon {
],
effects: [
MaybeEffect::from_bytes(bytes.effect_first).map_err(FromBytesError::EffectFirst)?.into(),
MaybeEffect::from_bytes(bytes.effect_second).map_err(FromBytesError::EffectSecond)?.into(),
MaybeEffect::from_bytes(bytes.effect_third).map_err(FromBytesError::EffectThird)?.into(),
MaybeEffect::from_bytes(bytes.effect_first)
.map_err(FromBytesError::EffectFirst)?
.into(),
MaybeEffect::from_bytes(bytes.effect_second)
.map_err(FromBytesError::EffectSecond)?
.into(),
MaybeEffect::from_bytes(bytes.effect_third)
.map_err(FromBytesError::EffectThird)?
.into(),
],
cross_move_effect: MaybeCrossMoveEffect::from_bytes(bytes.cross_move_effect)
@ -163,10 +170,22 @@ impl Bytes for Digimon {
.into(),
effect_description: [
bytes.effect_description_0.read_string().map_err(FromBytesError::EffectDescription1)?,
bytes.effect_description_1.read_string().map_err(FromBytesError::EffectDescription2)?,
bytes.effect_description_2.read_string().map_err(FromBytesError::EffectDescription3)?,
bytes.effect_description_3.read_string().map_err(FromBytesError::EffectDescription4)?,
bytes
.effect_description_0
.read_string()
.map_err(FromBytesError::EffectDescription1)?,
bytes
.effect_description_1
.read_string()
.map_err(FromBytesError::EffectDescription2)?,
bytes
.effect_description_2
.read_string()
.map_err(FromBytesError::EffectDescription3)?,
bytes
.effect_description_3
.read_string()
.map_err(FromBytesError::EffectDescription4)?,
],
// Unknown

View File

@ -72,10 +72,22 @@ impl Bytes for Digivolve {
// Effect
effect_description: [
bytes.effect_description_0.read_string().map_err(FromBytesError::EffectDescription1)?,
bytes.effect_description_1.read_string().map_err(FromBytesError::EffectDescription2)?,
bytes.effect_description_2.read_string().map_err(FromBytesError::EffectDescription3)?,
bytes.effect_description_3.read_string().map_err(FromBytesError::EffectDescription4)?,
bytes
.effect_description_0
.read_string()
.map_err(FromBytesError::EffectDescription1)?,
bytes
.effect_description_1
.read_string()
.map_err(FromBytesError::EffectDescription2)?,
bytes
.effect_description_2
.read_string()
.map_err(FromBytesError::EffectDescription3)?,
bytes
.effect_description_3
.read_string()
.map_err(FromBytesError::EffectDescription4)?,
],
// Unknown

View File

@ -1,7 +1,9 @@
#![doc(include = "item.md")]
// Imports
use crate::card::property::{self, ArrowColor, Effect, EffectCondition, MaybeArrowColor, MaybeEffect, MaybeEffectCondition};
use crate::card::property::{
self, ArrowColor, Effect, EffectCondition, MaybeArrowColor, MaybeEffect, MaybeEffectCondition,
};
use byteorder::{ByteOrder, LittleEndian};
use dcb_bytes::Bytes;
use dcb_util::{
@ -146,9 +148,15 @@ impl Bytes for Item {
],
effects: [
MaybeEffect::from_bytes(bytes.effect_first).map_err(FromBytesError::EffectFirst)?.into(),
MaybeEffect::from_bytes(bytes.effect_second).map_err(FromBytesError::EffectSecond)?.into(),
MaybeEffect::from_bytes(bytes.effect_third).map_err(FromBytesError::EffectThird)?.into(),
MaybeEffect::from_bytes(bytes.effect_first)
.map_err(FromBytesError::EffectFirst)?
.into(),
MaybeEffect::from_bytes(bytes.effect_second)
.map_err(FromBytesError::EffectSecond)?
.into(),
MaybeEffect::from_bytes(bytes.effect_third)
.map_err(FromBytesError::EffectThird)?
.into(),
],
effect_arrow_color: MaybeArrowColor::from_bytes(bytes.effect_arrow_color)
@ -156,10 +164,22 @@ impl Bytes for Item {
.into(),
effect_description: [
bytes.effect_description_0.read_string().map_err(FromBytesError::EffectDescription1)?,
bytes.effect_description_1.read_string().map_err(FromBytesError::EffectDescription2)?,
bytes.effect_description_2.read_string().map_err(FromBytesError::EffectDescription3)?,
bytes.effect_description_3.read_string().map_err(FromBytesError::EffectDescription4)?,
bytes
.effect_description_0
.read_string()
.map_err(FromBytesError::EffectDescription1)?,
bytes
.effect_description_1
.read_string()
.map_err(FromBytesError::EffectDescription2)?,
bytes
.effect_description_2
.read_string()
.map_err(FromBytesError::EffectDescription3)?,
bytes
.effect_description_3
.read_string()
.map_err(FromBytesError::EffectDescription4)?,
],
// Unknown

View File

@ -253,7 +253,8 @@ impl Bytes for Effect {
// Attack type
// Lower byte of `y`
let get_attack_type = || AttackType::from_bytes(&y.to_le_bytes()[0]).map_err(FromBytesError::UseAttackAttackType);
let get_attack_type =
|| AttackType::from_bytes(&y.to_le_bytes()[0]).map_err(FromBytesError::UseAttackAttackType);
// The operation argument
let get_op = || EffectOperation::from_bytes(bytes.op).map_err(FromBytesError::Operation);

View File

@ -118,7 +118,9 @@ impl Bytes for EffectCondition {
self.property_cmp.to_bytes(bytes.property_cmp).into_ok();
// Arguments
MaybeDigimonProperty::ref_cast(&self.arg_property).to_bytes(bytes.arg_property).into_ok();
MaybeDigimonProperty::ref_cast(&self.arg_property)
.to_bytes(bytes.arg_property)
.into_ok();
LittleEndian::write_u16(bytes.arg_num, self.arg_num);
self.operation.to_bytes(bytes.operation).into_ok();

View File

@ -42,7 +42,10 @@ fn valid_bytes() {
for (mov, bytes) in valid_moves {
// Check that we can create the move from bytes
assert_eq!(&Move::from_bytes(bytes).expect("Unable to convert move from bytes"), mov);
assert_eq!(
&Move::from_bytes(bytes).expect("Unable to convert move from bytes"),
mov
);
// Make sure the validation succeeds
let validation = mov.validate();

View File

@ -49,7 +49,9 @@ impl Table {
pub fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, DeserializeError> {
// Read header
let mut header_bytes = <Header as Bytes>::ByteArray::default();
reader.read_exact(&mut header_bytes).map_err(DeserializeError::ReadHeader)?;
reader
.read_exact(&mut header_bytes)
.map_err(DeserializeError::ReadHeader)?;
let header = Header::from_bytes(&header_bytes).map_err(DeserializeError::ParseHeader)?;
// Then check the number of each card
@ -75,7 +77,8 @@ impl Table {
.map_err(|err| DeserializeError::ReadCardHeader { id: card_id, err })?;
// Read the header
let card_header = CardHeader::from_bytes(&card_header_bytes).map_err(|err| DeserializeError::ParseCardHeader { id: card_id, err })?;
let card_header = CardHeader::from_bytes(&card_header_bytes)
.map_err(|err| DeserializeError::ParseCardHeader { id: card_id, err })?;
log::trace!("Found #{}: {}", card_id, card_header.ty);
@ -87,33 +90,41 @@ impl Table {
match card_header.ty {
CardType::Digimon => {
let mut digimon_bytes = [0; std::mem::size_of::<<Digimon as Bytes>::ByteArray>()];
reader.read_exact(&mut digimon_bytes).map_err(|err| DeserializeError::ReadCard {
id: card_id,
card_type: card_header.ty,
err,
})?;
let digimon = Digimon::from_bytes(&digimon_bytes).map_err(|err| DeserializeError::ParseDigimonCard { id: card_id, err })?;
reader
.read_exact(&mut digimon_bytes)
.map_err(|err| DeserializeError::ReadCard {
id: card_id,
card_type: card_header.ty,
err,
})?;
let digimon = Digimon::from_bytes(&digimon_bytes)
.map_err(|err| DeserializeError::ParseDigimonCard { id: card_id, err })?;
digimons.push(digimon);
},
CardType::Item => {
let mut item_bytes = [0; std::mem::size_of::<<Item as Bytes>::ByteArray>()];
reader.read_exact(&mut item_bytes).map_err(|err| DeserializeError::ReadCard {
id: card_id,
card_type: card_header.ty,
err,
})?;
let item = Item::from_bytes(&item_bytes).map_err(|err| DeserializeError::ParseItemCard { id: card_id, err })?;
reader
.read_exact(&mut item_bytes)
.map_err(|err| DeserializeError::ReadCard {
id: card_id,
card_type: card_header.ty,
err,
})?;
let item = Item::from_bytes(&item_bytes)
.map_err(|err| DeserializeError::ParseItemCard { id: card_id, err })?;
items.push(item);
},
CardType::Digivolve => {
let mut digivolve_bytes = [0; std::mem::size_of::<<Digivolve as Bytes>::ByteArray>()];
reader.read_exact(&mut digivolve_bytes).map_err(|err| DeserializeError::ReadCard {
id: card_id,
card_type: card_header.ty,
err,
})?;
let digivolve =
Digivolve::from_bytes(&digivolve_bytes).map_err(|err| DeserializeError::ParseDigivolveCard { id: card_id, err })?;
reader
.read_exact(&mut digivolve_bytes)
.map_err(|err| DeserializeError::ReadCard {
id: card_id,
card_type: card_header.ty,
err,
})?;
let digivolve = Digivolve::from_bytes(&digivolve_bytes)
.map_err(|err| DeserializeError::ParseDigivolveCard { id: card_id, err })?;
digivolves.push(digivolve);
},
}
@ -124,12 +135,20 @@ impl Table {
.read_exact(&mut null_terminator)
.map_err(|err| DeserializeError::ReadCardFooter { id: card_id, err })?;
if null_terminator[0] != 0 {
log::warn!("Card with id {}'s null terminator was {} instead of 0", card_id, null_terminator[0]);
log::warn!(
"Card with id {}'s null terminator was {} instead of 0",
card_id,
null_terminator[0]
);
}
}
// Return the table
Ok(Self { digimons, items, digivolves })
Ok(Self {
digimons,
items,
digivolves,
})
}
/// Serializes this card table to a file

View File

@ -111,9 +111,15 @@ impl Bytes for Deck {
owner: bytes.owner.read_string().map_err(FromBytesError::Owner)?,
cards: cards.map(CardId),
city: MaybeCity::from_bytes(bytes.city).map_err(FromBytesError::City)?.into(),
armor_evo: MaybeArmorEvo::from_bytes(bytes.armor_evo).map_err(FromBytesError::ArmorEvo)?.into(),
battle_music: MaybeMusic::from_bytes(bytes.battle_music).map_err(FromBytesError::BattleMusic)?.into(),
polygon_music: MaybeMusic::from_bytes(bytes.polygon_music).map_err(FromBytesError::PolygonMusic)?.into(),
armor_evo: MaybeArmorEvo::from_bytes(bytes.armor_evo)
.map_err(FromBytesError::ArmorEvo)?
.into(),
battle_music: MaybeMusic::from_bytes(bytes.battle_music)
.map_err(FromBytesError::BattleMusic)?
.into(),
polygon_music: MaybeMusic::from_bytes(bytes.polygon_music)
.map_err(FromBytesError::PolygonMusic)?
.into(),
experience: *bytes.experience,
unknown_64: *bytes.unknown_64,
unknown_6a: *bytes.unknown_6a,
@ -151,11 +157,17 @@ impl Bytes for Deck {
MaybeCity::ref_cast(&self.city).to_bytes(bytes.city).into_ok();
// Armor evo
MaybeArmorEvo::ref_cast(&self.armor_evo).to_bytes(bytes.armor_evo).into_ok();
MaybeArmorEvo::ref_cast(&self.armor_evo)
.to_bytes(bytes.armor_evo)
.into_ok();
// Music
MaybeMusic::ref_cast(&self.battle_music).to_bytes(bytes.battle_music).into_ok();
MaybeMusic::ref_cast(&self.polygon_music).to_bytes(bytes.polygon_music).into_ok();
MaybeMusic::ref_cast(&self.battle_music)
.to_bytes(bytes.battle_music)
.into_ok();
MaybeMusic::ref_cast(&self.polygon_music)
.to_bytes(bytes.polygon_music)
.into_ok();
// Unknown
*bytes.unknown_64 = self.unknown_64;

View File

@ -16,7 +16,11 @@ pub enum DeserializeError {
ReadHeader(#[source] std::io::Error),
/// The magic of the table was wrong
#[error("Found wrong table header magic (expected {:#}, found {:#x})", Table::HEADER_MAGIC, magic)]
#[error(
"Found wrong table header magic (expected {:#}, found {:#x})",
Table::HEADER_MAGIC,
magic
)]
HeaderMagic {
/// Magic we found
magic: u32,

View File

@ -15,12 +15,12 @@ enum_discrim_align_threshold = 100
fn_args_layout = "Compressed"
merge_derives = false
imports_granularity="Crate"
max_width = 150
max_width = 120
use_small_heuristics = "Default"
indent_style = "Block"
wrap_comments = false
format_code_in_doc_comments = false
comment_width = 150
comment_width = 120
normalize_comments = false
normalize_doc_attributes = false
license_template_path = ""