Skip to content

Commit

Permalink
index: encode using binrw (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcelCoding authored Oct 14, 2024
1 parent 577e1e6 commit d0bbbba
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 49 deletions.
70 changes: 60 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion libixx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
bincode = "1.3"
binrw = "0.14"

[dev-dependencies]
serde_json = "1.0"
6 changes: 5 additions & 1 deletion libixx/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::string::FromUtf8Error;

use thiserror::Error;

#[derive(Error, Debug)]
Expand All @@ -8,5 +10,7 @@ pub enum IxxError {
RecursiveReference,

#[error("(de)serialization failed")]
Bincode(#[from] bincode::Error),
Binrw(#[from] binrw::Error),
#[error("invalid utf8")]
FromUtf8Error(#[from] FromUtf8Error),
}
97 changes: 60 additions & 37 deletions libixx/src/index.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,64 @@
use std::io::{Read, Write};
use std::io::{Cursor, Read, Seek, Write};

use serde::{Deserialize, Serialize};
use binrw::{binrw, BinRead, BinWrite, Endian, NullString};

use crate::IxxError;

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Index(Vec<Vec<Label>>);
#[binrw(magic = b"ixx01", little)]
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Index {
#[bw(calc = entries.len() as u32)]
count: u32,
#[br(count = count)]
entries: Vec<Entry>,
}

#[binrw]
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Entry {
#[bw(calc = labels.len() as u16)]
count: u16,
#[br(count = count)]
labels: Vec<Label>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[binrw]
#[derive(Debug, Clone, PartialEq)]
struct Reference {
option_idx: u16,
label_idx: u8,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[binrw]
#[derive(Debug, Clone, PartialEq)]
enum Label {
InPlace(String),
InPlace(NullString),
Reference(Reference),
}

impl Index {
pub fn read(buf: &[u8]) -> Result<Self, IxxError> {
Ok(bincode::deserialize(buf)?)
Self::read_from(&mut Cursor::new(buf))
}

pub fn read_from<R: Read>(read: &mut R) -> Result<Self, IxxError> {
Ok(bincode::deserialize_from(read)?)
pub fn read_from<R: Read + Seek>(read: &mut R) -> Result<Self, IxxError> {
Ok(BinRead::read_options(read, Endian::Little, ())?)
}

pub fn write(&self) -> Result<Vec<u8>, IxxError> {
Ok(bincode::serialize(self)?)
}

pub fn write_into<W: Write>(&self, write: &mut W) -> Result<(), IxxError> {
Ok(bincode::serialize_into(write, self)?)
pub fn write_into<W: Write + Seek>(&self, write: &mut W) -> Result<(), IxxError> {
Ok(BinWrite::write_options(self, write, Endian::Little, ())?)
}

pub fn push(&mut self, option: &str) {
let labels = option
.split('.')
.map(|segment| {
for (option_idx, option) in self.0.iter().enumerate() {
let segment = segment.into();

for (option_idx, Entry { labels: option }) in self.entries.iter().enumerate() {
for (label_idx, label) in option.iter().enumerate() {
if let Label::InPlace(inplace) = label {
if inplace != segment {
if inplace != &segment {
continue;
}

Expand All @@ -55,21 +70,21 @@ impl Index {
}
}

Label::InPlace(segment.to_string())
Label::InPlace(segment)
})
.collect();

self.0.push(labels);
self.entries.push(Entry { labels });
}

fn resolve_reference(&self, reference: &Reference) -> Result<&str, IxxError> {
fn resolve_reference(&self, reference: &Reference) -> Result<&NullString, IxxError> {
let option_idx = reference.option_idx as usize;

if self.0.len() <= option_idx {
if self.entries.len() <= option_idx {
return Err(IxxError::ReferenceOutOfBounds);
}

let entry = &self.0[option_idx];
let entry = &self.entries[option_idx].labels;

let label_idx = reference.label_idx as usize;

Expand All @@ -88,11 +103,13 @@ impl Index {
pub fn get_idx_by_name(&self, option: &str) -> Result<Option<usize>, IxxError> {
let mut labels = Vec::new();
for segment in option.split('.') {
let segment = segment.into();

'outer: {
for (option_idx, option) in self.0.iter().enumerate() {
for (option_idx, Entry { labels: option }) in self.entries.iter().enumerate() {
for (label_idx, label) in option.iter().enumerate() {
if let Label::InPlace(inplace) = label {
if inplace != segment {
if inplace != &segment {
continue;
}

Expand All @@ -111,10 +128,10 @@ impl Index {

Ok(
self
.0
.entries
.iter()
.enumerate()
.find(|(idx, option)| do_labels_match(*idx, option, &labels))
.find(|(idx, Entry { labels: option })| do_labels_match(*idx, option, &labels))
.map(|(idx, _)| idx),
)
}
Expand All @@ -131,13 +148,16 @@ impl Index {

let mut results = Vec::new();

for (idx, option) in self.0.iter().enumerate() {
for (idx, Entry { labels: option }) in self.entries.iter().enumerate() {
let mut option_name = String::new();
for label in option {
match label {
Label::InPlace(data) => option_name.push_str(data),
Label::Reference(reference) => option_name.push_str(self.resolve_reference(reference)?),
}
option_name.push_str(&String::try_from(
match label {
Label::InPlace(data) => data,
Label::Reference(reference) => self.resolve_reference(reference)?,
}
.clone(),
)?);
option_name.push('.')
}
// remove last dot...
Expand Down Expand Up @@ -168,13 +188,16 @@ impl Index {
pub fn all(&self, max: usize) -> Result<Vec<String>, IxxError> {
let mut options = Vec::new();

for option in &self.0[..max] {
for Entry { labels: option } in &self.entries[..max] {
let mut option_name = String::new();
for label in option {
match label {
Label::InPlace(data) => option_name.push_str(data),
Label::Reference(reference) => option_name.push_str(self.resolve_reference(reference)?),
}
option_name.push_str(&String::try_from(
match label {
Label::InPlace(data) => data,
Label::Reference(reference) => self.resolve_reference(reference)?,
}
.clone(),
)?);
option_name.push('.')
}
// remove last dot...
Expand Down

0 comments on commit d0bbbba

Please sign in to comment.