replace errors with eyre
This commit is contained in:
		
							parent
							
								
									f71048b185
								
							
						
					
					
						commit
						4e5898c0c0
					
				@ -9,6 +9,7 @@ mmap = ["memmap"]
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
bytes = "1.1.0"
 | 
					bytes = "1.1.0"
 | 
				
			||||||
 | 
					eyre = "0.6.5"
 | 
				
			||||||
log = "0.4.14"
 | 
					log = "0.4.14"
 | 
				
			||||||
lz4_flex = { version = "0.8.2", default-features = false, features = ["std", "checked-decode", "frame"] }
 | 
					lz4_flex = { version = "0.8.2", default-features = false, features = ["std", "checked-decode", "frame"] }
 | 
				
			||||||
memmap = { version = "0.7.0", optional = true }
 | 
					memmap = { version = "0.7.0", optional = true }
 | 
				
			||||||
@ -21,5 +22,6 @@ smallvec = "1.6.1"
 | 
				
			|||||||
thiserror = "1.0.28"
 | 
					thiserror = "1.0.28"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dev-dependencies]
 | 
					[dev-dependencies]
 | 
				
			||||||
 | 
					color-eyre = "0.5.11"
 | 
				
			||||||
env_logger = "0.9.0"
 | 
					env_logger = "0.9.0"
 | 
				
			||||||
eyre = "0.6.5"
 | 
					eyre = "0.6.5"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,29 +1,32 @@
 | 
				
			|||||||
use std::{convert::TryFrom, env::args, fs::File, io};
 | 
					use std::{convert::TryFrom, env::args, fs::File, io};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use eyre::Context;
 | 
				
			||||||
use log::{error, info, trace};
 | 
					use log::{error, info, trace};
 | 
				
			||||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
 | 
					use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
 | 
				
			||||||
use regex::Regex;
 | 
					use regex::Regex;
 | 
				
			||||||
use ros_message::{MessagePath, Msg};
 | 
					use ros_message::{MessagePath, Msg};
 | 
				
			||||||
use rsbag::{
 | 
					use rsbag::{
 | 
				
			||||||
 | 
					    chunk::ChunkHeader,
 | 
				
			||||||
    index::{BagIndex, ConnInfo},
 | 
					    index::{BagIndex, ConnInfo},
 | 
				
			||||||
    reader::{BagReader, MmapReader},
 | 
					    reader::{BagReader, MmapReader},
 | 
				
			||||||
 | 
					    Result,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn parse_msgdef(message_name: &str, msgdef: &str) -> rsbag::Result<Msg> {
 | 
					fn parse_msgdef(message_name: &str, msgdef: &str) -> Result<Msg> {
 | 
				
			||||||
    trace!("message definition: {}", msgdef);
 | 
					    trace!("message definition: {}", msgdef);
 | 
				
			||||||
    let path = MessagePath::try_from(message_name).map_err(rsbag::Error::other)?;
 | 
					    let path = MessagePath::try_from(message_name)?;
 | 
				
			||||||
    let msgtype = Msg::new(path, msgdef).map_err(rsbag::Error::other)?;
 | 
					    let msgtype = Msg::new(path, msgdef)?;
 | 
				
			||||||
    Ok(msgtype)
 | 
					    Ok(msgtype)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn parse_message_definitions(conn: &ConnInfo) -> rsbag::Result<Vec<Msg>> {
 | 
					fn parse_message_definitions(conn: &ConnInfo) -> Result<Vec<Msg>> {
 | 
				
			||||||
    let msgdefs = conn.message_definition()?;
 | 
					    let msgdefs = &conn.message_definition;
 | 
				
			||||||
    let boundary_re = Regex::new(r"\r?\n==+\r?\nMSG: ([^\r\n]+)\r?\n").unwrap();
 | 
					    let boundary_re = Regex::new(r"\r?\n==+\r?\nMSG: ([^\r\n]+)\r?\n")?;
 | 
				
			||||||
    let mut name = conn.datatype()?;
 | 
					    let mut name = conn.datatype.clone();
 | 
				
			||||||
    let mut begin = 0usize;
 | 
					    let mut begin = 0usize;
 | 
				
			||||||
    let mut msgs = Vec::new();
 | 
					    let mut msgs = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for cap in boundary_re.captures_iter(&msgdefs) {
 | 
					    for cap in boundary_re.captures_iter(msgdefs) {
 | 
				
			||||||
        let boundary_range = cap.get(0).unwrap();
 | 
					        let boundary_range = cap.get(0).unwrap();
 | 
				
			||||||
        let end = boundary_range.start();
 | 
					        let end = boundary_range.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -43,37 +46,32 @@ fn parse_message_definitions(conn: &ConnInfo) -> rsbag::Result<Vec<Msg>> {
 | 
				
			|||||||
    Ok(msgs)
 | 
					    Ok(msgs)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn read_chunk<R: BagReader>(bag_reader: &mut R, pos: u64) -> rsbag::Result<Vec<u8>> {
 | 
					fn read_chunk<R: BagReader>(bag_reader: &mut R, pos: u64) -> Result<Vec<u8>> {
 | 
				
			||||||
    let chunk_header = bag_reader.read_chunk_header(pos)?;
 | 
					    let chunk_header = ChunkHeader::read(bag_reader, pos)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let compressed_data = bag_reader.read_data().unwrap();
 | 
					    let compressed_data = bag_reader.read_data()?;
 | 
				
			||||||
    let mut data = Vec::with_capacity(chunk_header.uncompressed_size as usize);
 | 
					    let mut data = Vec::with_capacity(chunk_header.uncompressed_size as usize);
 | 
				
			||||||
    let mut decompresor = chunk_header.compression.decompress(compressed_data);
 | 
					    let mut decompresor = chunk_header.compression.decompress(compressed_data);
 | 
				
			||||||
    io::copy(&mut decompresor, &mut data).unwrap();
 | 
					    io::copy(&mut decompresor, &mut data)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(data)
 | 
					    Ok(data)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() -> Result<()> {
 | 
				
			||||||
 | 
					    color_eyre::install()?;
 | 
				
			||||||
    env_logger::init();
 | 
					    env_logger::init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let args: Vec<_> = args().collect();
 | 
					    let args: Vec<_> = args().collect();
 | 
				
			||||||
    if args.len() != 2 {
 | 
					    if args.len() != 2 {
 | 
				
			||||||
        eprintln!("Usage: {} <bag path>", args[0]);
 | 
					        eprintln!("Usage: {} <bag path>", args[0]);
 | 
				
			||||||
        return;
 | 
					        return Ok(());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let bag_path = &args[1];
 | 
					    let bag_path = &args[1];
 | 
				
			||||||
    let bag_file = File::open(bag_path).expect("Could not open bag file");
 | 
					    let bag_file = File::open(bag_path).expect("Could not open bag file");
 | 
				
			||||||
    let mut bag_reader = MmapReader::new(bag_file).unwrap();
 | 
					    let mut bag_reader = MmapReader::new(bag_file)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let index = match BagIndex::read_all(&mut bag_reader) {
 | 
					    let index = BagIndex::read_all(&mut bag_reader).wrap_err("bag parse error")?;
 | 
				
			||||||
        Ok(index) => index,
 | 
					 | 
				
			||||||
        Err(err) => {
 | 
					 | 
				
			||||||
            error!("bag parse error: {}", err);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for conn in &index.connections {
 | 
					    for conn in &index.connections {
 | 
				
			||||||
        match parse_message_definitions(conn) {
 | 
					        match parse_message_definitions(conn) {
 | 
				
			||||||
@ -93,42 +91,45 @@ fn main() {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // let mut total_size = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // let total_size = index
 | 
					 | 
				
			||||||
    //     .chunks
 | 
					 | 
				
			||||||
    //     .par_iter()
 | 
					 | 
				
			||||||
    //     .try_fold(
 | 
					 | 
				
			||||||
    //         || 0u64,
 | 
					 | 
				
			||||||
    //         |total_size, chunk| -> rsbag::Result<_> {
 | 
					 | 
				
			||||||
    //             let chunk_header = bag_reader.clone().read_chunk_header(chunk.pos)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //             // let data = read_chunk(&mut bag_reader.clone(), chunk.pos)?;
 | 
					 | 
				
			||||||
    //             // chunks.push(data);
 | 
					 | 
				
			||||||
    //             Ok(total_size + chunk_header.uncompressed_size as u64)
 | 
					 | 
				
			||||||
    //         },
 | 
					 | 
				
			||||||
    //     )
 | 
					 | 
				
			||||||
    //     .reduce(
 | 
					 | 
				
			||||||
    //         // || Ok(Vec::new()),
 | 
					 | 
				
			||||||
    //         || Ok(0),
 | 
					 | 
				
			||||||
    //         |a, b| a.and_then(|a| b.map(|b| a + b)),
 | 
					 | 
				
			||||||
    //     ).unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let total_size = index
 | 
					    let total_size = index
 | 
				
			||||||
        .chunks
 | 
					        .chunks
 | 
				
			||||||
        .par_iter()
 | 
					        .par_iter()
 | 
				
			||||||
        .try_fold(
 | 
					        .try_fold(
 | 
				
			||||||
            || 0u64,
 | 
					            || 0u64,
 | 
				
			||||||
            |total_size, chunk| -> rsbag::Result<_> {
 | 
					            |total_size, chunk| -> rsbag::Result<_> {
 | 
				
			||||||
                let data = read_chunk(&mut bag_reader.clone(), chunk.pos)?;
 | 
					                let mut reader = bag_reader.clone();
 | 
				
			||||||
                Ok(total_size + data.len() as u64)
 | 
					                let chunk_header = ChunkHeader::read(&mut reader, chunk.pos)?;
 | 
				
			||||||
 | 
					                reader.skip_data()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // let data = read_chunk(&mut bag_reader.clone(), chunk.pos)?;
 | 
				
			||||||
 | 
					                // chunks.push(data);
 | 
				
			||||||
 | 
					                Ok(total_size + chunk_header.uncompressed_size as u64)
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .reduce(
 | 
					        .reduce(
 | 
				
			||||||
            // || Ok(Vec::new()),
 | 
					            // || Ok(Vec::new()),
 | 
				
			||||||
            || Ok(0),
 | 
					            || Ok(0),
 | 
				
			||||||
            |a, b| a.and_then(|a| b.map(|b| a + b)),
 | 
					            |a, b| a.and_then(|a| b.map(|b| a + b)),
 | 
				
			||||||
        ).unwrap();
 | 
					        )
 | 
				
			||||||
 | 
					        .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // let total_size = index
 | 
				
			||||||
 | 
					    //     .chunks
 | 
				
			||||||
 | 
					    //     .par_iter()
 | 
				
			||||||
 | 
					    //     .try_fold(
 | 
				
			||||||
 | 
					    //         || 0u64,
 | 
				
			||||||
 | 
					    //         |total_size, chunk| -> Result<_> {
 | 
				
			||||||
 | 
					    //             let data = read_chunk(&mut bag_reader.clone(), chunk.pos)?;
 | 
				
			||||||
 | 
					    //             Ok(total_size + data.len() as u64)
 | 
				
			||||||
 | 
					    //         },
 | 
				
			||||||
 | 
					    //     )
 | 
				
			||||||
 | 
					    //     .reduce(
 | 
				
			||||||
 | 
					    //         // || Ok(Vec::new()),
 | 
				
			||||||
 | 
					    //         || Ok(0),
 | 
				
			||||||
 | 
					    //         |a, b| a.and_then(|a| b.map(|b| a + b)),
 | 
				
			||||||
 | 
					    //     )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info!("total uncompressed size: {}", total_size);
 | 
					    info!("total uncompressed size: {}", total_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										24
									
								
								src/chunk.rs
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								src/chunk.rs
									
									
									
									
									
								
							@ -1,6 +1,16 @@
 | 
				
			|||||||
use std::{io, str::FromStr};
 | 
					use std::{
 | 
				
			||||||
 | 
					    io::{self, SeekFrom},
 | 
				
			||||||
 | 
					    str::FromStr,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{parse::Header, Error, Result};
 | 
					use eyre::bail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    error,
 | 
				
			||||||
 | 
					    parse::{Header, Op},
 | 
				
			||||||
 | 
					    reader::BagReader,
 | 
				
			||||||
 | 
					    Error, Result,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Copy, Debug)]
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
pub enum Compression {
 | 
					pub enum Compression {
 | 
				
			||||||
@ -17,7 +27,7 @@ impl FromStr for Compression {
 | 
				
			|||||||
            "none" => Compression::None,
 | 
					            "none" => Compression::None,
 | 
				
			||||||
            "bz2" => Compression::Bz2,
 | 
					            "bz2" => Compression::Bz2,
 | 
				
			||||||
            "lz4" => Compression::Lz4,
 | 
					            "lz4" => Compression::Lz4,
 | 
				
			||||||
            _ => return Err(Error::UnsupportedCompression(s.to_string())),
 | 
					            _ => bail!(error::UnsupportedCompression(s.to_string())),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -39,8 +49,14 @@ pub struct ChunkHeader {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ChunkHeader {
 | 
					impl ChunkHeader {
 | 
				
			||||||
 | 
					    pub fn read<R: BagReader>(reader: &mut R, pos: u64) -> Result<ChunkHeader> {
 | 
				
			||||||
 | 
					        reader.seek(SeekFrom::Start(pos))?;
 | 
				
			||||||
 | 
					        let header = reader.read_header_op(Op::Chunk)?;
 | 
				
			||||||
 | 
					        ChunkHeader::from_header(header)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn from_header(header: Header) -> Result<Self> {
 | 
					    pub fn from_header(header: Header) -> Result<Self> {
 | 
				
			||||||
        Ok(Self {
 | 
					        Ok(ChunkHeader {
 | 
				
			||||||
            compression: header.read_string(b"compression")?.parse()?,
 | 
					            compression: header.read_string(b"compression")?.parse()?,
 | 
				
			||||||
            uncompressed_size: header.read_u32(b"size")?,
 | 
					            uncompressed_size: header.read_u32(b"size")?,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										54
									
								
								src/error.rs
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								src/error.rs
									
									
									
									
									
								
							@ -1,51 +1,21 @@
 | 
				
			|||||||
use num_enum::TryFromPrimitiveError;
 | 
					 | 
				
			||||||
use thiserror::Error;
 | 
					use thiserror::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::parse::{self, Op};
 | 
					use crate::parse::{self};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Error)]
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
pub enum Error {
 | 
					 | 
				
			||||||
    #[error("i/o error: {0}")]
 | 
					 | 
				
			||||||
    Io(#[from] std::io::Error),
 | 
					 | 
				
			||||||
    #[error("{0}")]
 | 
					 | 
				
			||||||
    Parse(parse::Error<parse::InputOwned>),
 | 
					 | 
				
			||||||
    #[error("unsupported version: {0}")]
 | 
					 | 
				
			||||||
    UnsupportedVersion(parse::Version),
 | 
					 | 
				
			||||||
    #[error("unsupported encryptor: {0}")]
 | 
					 | 
				
			||||||
    UnsupportedEncryptor(String),
 | 
					 | 
				
			||||||
    #[error("unsupported compression: {0}")]
 | 
					 | 
				
			||||||
    UnsupportedCompression(String),
 | 
					 | 
				
			||||||
    #[error("unexpected EOF")]
 | 
					 | 
				
			||||||
    Eof,
 | 
					 | 
				
			||||||
    #[error("invalid header op: {0}")]
 | 
					 | 
				
			||||||
    InvalidOp(#[from] TryFromPrimitiveError<Op>),
 | 
					 | 
				
			||||||
    #[error("missing field: {0:?}")]
 | 
					 | 
				
			||||||
    MissingField(String),
 | 
					 | 
				
			||||||
#[error("bag is unindexed")]
 | 
					#[error("bag is unindexed")]
 | 
				
			||||||
	Unindexed,
 | 
					pub struct Unindexed;
 | 
				
			||||||
    #[error("{0}")]
 | 
					 | 
				
			||||||
    Other(String),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> From<parse::Error<parse::Input<'a>>> for Error {
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
    fn from(err: parse::Error<parse::Input>) -> Self {
 | 
					#[error("unsupported encryptor: {0}")]
 | 
				
			||||||
        Error::Parse(err.into_owned())
 | 
					pub struct UnsupportedEncryptor(pub String);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> From<nom::Err<parse::Error<parse::Input<'a>>>> for Error {
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
    fn from(err: nom::Err<parse::Error<parse::Input<'a>>>) -> Self {
 | 
					#[error("unsupported bag version: {0}")]
 | 
				
			||||||
        match err {
 | 
					pub struct UnsupportedVersion(pub parse::Version);
 | 
				
			||||||
            nom::Err::Error(e) | nom::Err::Failure(e) => e.into(),
 | 
					 | 
				
			||||||
            nom::Err::Incomplete(_) => panic!("incomplete error"),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Error {
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
    pub fn other<S: ToString>(message: S) -> Self {
 | 
					#[error("unsupported compression: {0}")]
 | 
				
			||||||
        Error::Other(message.to_string())
 | 
					pub struct UnsupportedCompression(pub String);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub type Result<T, E = Error> = core::result::Result<T, E>;
 | 
					pub use eyre::{Report as Error, Result};
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										79
									
								
								src/index.rs
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								src/index.rs
									
									
									
									
									
								
							@ -1,40 +1,41 @@
 | 
				
			|||||||
use std::io::SeekFrom;
 | 
					use std::io::SeekFrom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use eyre::bail;
 | 
				
			||||||
use log::trace;
 | 
					use log::trace;
 | 
				
			||||||
 | 
					use nom::{number::streaming::le_u32, sequence::tuple, Parser};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    parse::{Header, Op},
 | 
					    error,
 | 
				
			||||||
 | 
					    parse::{self, Header, Op},
 | 
				
			||||||
    reader::BagReader,
 | 
					    reader::BagReader,
 | 
				
			||||||
    Error, Result,
 | 
					    Result,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct ConnInfo {
 | 
					pub struct ConnInfo {
 | 
				
			||||||
    pub id: u32,
 | 
					    pub id: u32,
 | 
				
			||||||
    pub topic: String,
 | 
					    pub topic: String,
 | 
				
			||||||
    pub conn_header: Header,
 | 
					    pub message_definition: String,
 | 
				
			||||||
 | 
					    pub datatype: String,
 | 
				
			||||||
 | 
					    pub md5sum: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ConnInfo {
 | 
					impl ConnInfo {
 | 
				
			||||||
 | 
					    pub fn read<R: BagReader>(reader: &mut R) -> Result<Self> {
 | 
				
			||||||
 | 
					        let record_header = reader.read_header_op(Op::Connection)?;
 | 
				
			||||||
 | 
					        let conn_header = reader.read_header()?;
 | 
				
			||||||
 | 
					        Self::from_headers(record_header, conn_header)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn from_headers(record_header: Header, conn_header: Header) -> Result<Self> {
 | 
					    pub fn from_headers(record_header: Header, conn_header: Header) -> Result<Self> {
 | 
				
			||||||
        Ok(ConnInfo {
 | 
					        Ok(ConnInfo {
 | 
				
			||||||
            id: record_header.read_u32(b"conn")?,
 | 
					            id: record_header.read_u32(b"conn")?,
 | 
				
			||||||
            topic: record_header.read_string(b"topic")?,
 | 
					            topic: record_header.read_string(b"topic")?,
 | 
				
			||||||
            conn_header,
 | 
					            message_definition: conn_header.read_string(b"message_definition")?,
 | 
				
			||||||
 | 
					            datatype: conn_header.read_string(b"type")?,
 | 
				
			||||||
 | 
					            md5sum: conn_header.read_string(b"md5sum")?,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn message_definition(&self) -> Result<String> {
 | 
					 | 
				
			||||||
        self.conn_header.read_string(b"message_definition")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn datatype(&self) -> Result<String> {
 | 
					 | 
				
			||||||
        self.conn_header.read_string(b"type")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn md5sum(&self) -> Result<String> {
 | 
					 | 
				
			||||||
        self.conn_header.read_string(b"md5sum")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
@ -42,23 +43,51 @@ pub struct ChunkInfo {
 | 
				
			|||||||
    pub pos: u64,
 | 
					    pub pos: u64,
 | 
				
			||||||
    pub start_time: u64, // TODO: unpack time
 | 
					    pub start_time: u64, // TODO: unpack time
 | 
				
			||||||
    pub end_time: u64,
 | 
					    pub end_time: u64,
 | 
				
			||||||
    pub conn_count: u32,
 | 
					    pub connections: Vec<ChunkConnection>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ChunkInfo {
 | 
					impl ChunkInfo {
 | 
				
			||||||
    pub fn from_header(header: Header) -> Result<Self> {
 | 
					    pub fn read<R: BagReader>(reader: &mut R) -> Result<Self> {
 | 
				
			||||||
 | 
					        let header = reader.read_header_op(Op::ChunkInfo)?;
 | 
				
			||||||
        if header.read_u32(b"ver")? != 1 {
 | 
					        if header.read_u32(b"ver")? != 1 {
 | 
				
			||||||
            return Err(Error::other("unsupported ChunkInfo version"));
 | 
					            bail!("unsupported ChunkInfo version");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        reader.read_data_length()?; // Data length not needed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let conn_count = header.read_u32(b"count")?;
 | 
				
			||||||
 | 
					        let mut connections = Vec::with_capacity(conn_count as usize);
 | 
				
			||||||
 | 
					        for _ in 0..conn_count {
 | 
				
			||||||
 | 
					            let conn = ChunkConnection::read(reader)?;
 | 
				
			||||||
 | 
					            connections.push(conn);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(ChunkInfo {
 | 
					        Ok(ChunkInfo {
 | 
				
			||||||
            pos: header.read_u64(b"chunk_pos")?,
 | 
					            pos: header.read_u64(b"chunk_pos")?,
 | 
				
			||||||
            start_time: header.read_u64(b"start_time")?,
 | 
					            start_time: header.read_u64(b"start_time")?,
 | 
				
			||||||
            end_time: header.read_u64(b"end_time")?,
 | 
					            end_time: header.read_u64(b"end_time")?,
 | 
				
			||||||
            conn_count: header.read_u32(b"count")?,
 | 
					            connections,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct ChunkConnection {
 | 
				
			||||||
 | 
					    pub conn_id: u32,
 | 
				
			||||||
 | 
					    pub count: u32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ChunkConnection {
 | 
				
			||||||
 | 
					    pub fn parse(input: parse::Input) -> parse::IResult<Self> {
 | 
				
			||||||
 | 
					        tuple((le_u32, le_u32))
 | 
				
			||||||
 | 
					            .map(|(conn_id, count)| ChunkConnection { conn_id, count })
 | 
				
			||||||
 | 
					            .parse(input)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn read<R: BagReader>(reader: &mut R) -> Result<Self> {
 | 
				
			||||||
 | 
					        reader.read_parser(Self::parse)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct BagIndex {
 | 
					pub struct BagIndex {
 | 
				
			||||||
    pub connections: Vec<ConnInfo>,
 | 
					    pub connections: Vec<ConnInfo>,
 | 
				
			||||||
@ -76,11 +105,11 @@ impl BagIndex {
 | 
				
			|||||||
        trace!("index pos: {}", index_pos);
 | 
					        trace!("index pos: {}", index_pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if index_pos == 0 {
 | 
					        if index_pos == 0 {
 | 
				
			||||||
            return Err(Error::Unindexed);
 | 
					            bail!(error::Unindexed);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Ok(encryptor) = file_header.read_string(b"encryptor") {
 | 
					        if let Ok(encryptor) = file_header.read_string(b"encryptor") {
 | 
				
			||||||
            return Err(Error::UnsupportedEncryptor(encryptor));
 | 
					            bail!(error::UnsupportedEncryptor(encryptor));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        reader.seek(SeekFrom::Start(index_pos))?;
 | 
					        reader.seek(SeekFrom::Start(index_pos))?;
 | 
				
			||||||
@ -91,7 +120,7 @@ impl BagIndex {
 | 
				
			|||||||
        let mut connections = Vec::with_capacity(conn_count as usize);
 | 
					        let mut connections = Vec::with_capacity(conn_count as usize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for _ in 0..conn_count {
 | 
					        for _ in 0..conn_count {
 | 
				
			||||||
            let conn = reader.read_conn_info()?;
 | 
					            let conn = ConnInfo::read(reader)?;
 | 
				
			||||||
            trace!("connection: id={}, topic={}", conn.id, conn.topic);
 | 
					            trace!("connection: id={}, topic={}", conn.id, conn.topic);
 | 
				
			||||||
            connections.push(conn);
 | 
					            connections.push(conn);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -102,7 +131,7 @@ impl BagIndex {
 | 
				
			|||||||
        let mut chunks = Vec::with_capacity(chunk_count as usize);
 | 
					        let mut chunks = Vec::with_capacity(chunk_count as usize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for _ in 0..chunk_count {
 | 
					        for _ in 0..chunk_count {
 | 
				
			||||||
            let chunk = reader.read_chunk_info()?;
 | 
					            let chunk = ChunkInfo::read(reader)?;
 | 
				
			||||||
            chunks.push(chunk);
 | 
					            chunks.push(chunk);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -118,7 +147,7 @@ impl BagIndex {
 | 
				
			|||||||
        if (version.major, version.minor) == (2, 0) {
 | 
					        if (version.major, version.minor) == (2, 0) {
 | 
				
			||||||
            Self::read_v2(reader)
 | 
					            Self::read_v2(reader)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            Err(Error::UnsupportedVersion(version))
 | 
					            bail!(error::UnsupportedVersion(version));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,9 @@
 | 
				
			|||||||
mod error;
 | 
					mod error;
 | 
				
			||||||
mod fields;
 | 
					pub mod header;
 | 
				
			||||||
mod header;
 | 
					 | 
				
			||||||
mod version;
 | 
					mod version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use error::{Error, ErrorKind};
 | 
					pub use error::{Error, ErrorKind};
 | 
				
			||||||
pub use fields::Op;
 | 
					pub use header::{Header, Op};
 | 
				
			||||||
pub use header::Header;
 | 
					 | 
				
			||||||
pub use version::Version;
 | 
					pub use version::Version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub type Input<'a> = &'a [u8];
 | 
					pub type Input<'a> = &'a [u8];
 | 
				
			||||||
 | 
				
			|||||||
@ -149,6 +149,12 @@ impl<I: ToOwned + ?Sized> Error<&I> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> From<Error<&'a [u8]>> for Error<Vec<u8>> {
 | 
				
			||||||
 | 
					    fn from(e: Error<&'a [u8]>) -> Self {
 | 
				
			||||||
 | 
					        e.into_owned()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// adapted from https://fasterthanli.me/series/making-our-own-ping/part-9
 | 
					// adapted from https://fasterthanli.me/series/making-our-own-ping/part-9
 | 
				
			||||||
impl<I: ErrorInputDisplay> fmt::Display for Error<I> {
 | 
					impl<I: ErrorInputDisplay> fmt::Display for Error<I> {
 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
					    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
				
			||||||
 | 
				
			|||||||
@ -11,8 +11,16 @@ use nom::{
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
use smallvec::SmallVec;
 | 
					use smallvec::SmallVec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::{fields, IResult, Input, Op};
 | 
					use super::{IResult, Input};
 | 
				
			||||||
use crate::{Error, Result};
 | 
					use crate::Result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod error;
 | 
				
			||||||
 | 
					mod fields;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use self::{
 | 
				
			||||||
 | 
					    error::{FieldDataError, MissingFieldError},
 | 
				
			||||||
 | 
					    fields::Op,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub struct HeaderField {
 | 
					pub struct HeaderField {
 | 
				
			||||||
@ -70,15 +78,15 @@ impl Header {
 | 
				
			|||||||
        .parse(input)
 | 
					        .parse(input)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn find_field(&self, name: &[u8]) -> Result<&[u8]> {
 | 
					    fn find_field(&self, name: &[u8]) -> Result<&[u8]> {
 | 
				
			||||||
        self.0
 | 
					        self.0
 | 
				
			||||||
            .iter()
 | 
					            .iter()
 | 
				
			||||||
            .find(|field| field.name() == name)
 | 
					            .find(|field| field.name() == name)
 | 
				
			||||||
            .map(|field| field.value())
 | 
					            .map(|field| field.value())
 | 
				
			||||||
            .ok_or_else(|| Error::MissingField(String::from_utf8_lossy(name).into_owned()))
 | 
					            .ok_or_else(|| MissingFieldError(String::from_utf8_lossy(name).into_owned()).into())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn read_op(&self) -> Result<Op> {
 | 
					    pub fn read_op(&self) -> Result<fields::Op> {
 | 
				
			||||||
        self.find_field(b"op").and_then(fields::Op::parse)
 | 
					        self.find_field(b"op").and_then(fields::Op::parse)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										26
									
								
								src/parse/header/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/parse/header/error.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					use thiserror::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::parse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					#[error("missing field {0:?}")]
 | 
				
			||||||
 | 
					pub struct MissingFieldError(pub String);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					#[error("bad field data: {0}")]
 | 
				
			||||||
 | 
					pub struct FieldDataError(#[source] pub parse::Error<parse::InputOwned>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> From<parse::Error<parse::Input<'a>>> for FieldDataError {
 | 
				
			||||||
 | 
					    fn from(err: parse::Error<parse::Input<'a>>) -> Self {
 | 
				
			||||||
 | 
					        FieldDataError(err.into_owned())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> From<nom::Err<parse::Error<parse::Input<'a>>>> for FieldDataError {
 | 
				
			||||||
 | 
					    fn from(err: nom::Err<parse::Error<parse::Input<'a>>>) -> Self {
 | 
				
			||||||
 | 
					        match err {
 | 
				
			||||||
 | 
					            nom::Err::Error(e) | nom::Err::Failure(e) => e.into(),
 | 
				
			||||||
 | 
					            nom::Err::Incomplete(_) => unreachable!("incomplete error"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,8 +5,7 @@ use nom::{
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
use num_enum::TryFromPrimitive;
 | 
					use num_enum::TryFromPrimitive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::Input;
 | 
					use super::{FieldDataError, Input, Result};
 | 
				
			||||||
use crate::{Error, Result};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Copy, Debug, TryFromPrimitive, PartialEq)]
 | 
					#[derive(Clone, Copy, Debug, TryFromPrimitive, PartialEq)]
 | 
				
			||||||
#[repr(u8)]
 | 
					#[repr(u8)]
 | 
				
			||||||
@ -21,21 +20,27 @@ pub enum Op {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
impl Op {
 | 
					impl Op {
 | 
				
			||||||
    pub fn parse(input: Input) -> Result<Self> {
 | 
					    pub fn parse(input: Input) -> Result<Self> {
 | 
				
			||||||
        let (_, op) = all_consuming(le_u8).parse(input)?;
 | 
					        let (_, op) = all_consuming(le_u8)
 | 
				
			||||||
 | 
					            .parse(input)
 | 
				
			||||||
 | 
					            .map_err(FieldDataError::from)?;
 | 
				
			||||||
        Op::try_from_primitive(op).map_err(Into::into)
 | 
					        Op::try_from_primitive(op).map_err(Into::into)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn parse_u32(input: Input) -> Result<u32> {
 | 
					pub fn parse_u32(input: Input) -> Result<u32> {
 | 
				
			||||||
    let (_, x) = all_consuming(le_u32).parse(input)?;
 | 
					    let (_, x) = all_consuming(le_u32)
 | 
				
			||||||
 | 
					        .parse(input)
 | 
				
			||||||
 | 
					        .map_err(FieldDataError::from)?;
 | 
				
			||||||
    Ok(x)
 | 
					    Ok(x)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn parse_u64(input: Input) -> Result<u64> {
 | 
					pub fn parse_u64(input: Input) -> Result<u64> {
 | 
				
			||||||
    let (_, x) = all_consuming(le_u64).parse(input)?;
 | 
					    let (_, x) = all_consuming(le_u64)
 | 
				
			||||||
 | 
					        .parse(input)
 | 
				
			||||||
 | 
					        .map_err(FieldDataError::from)?;
 | 
				
			||||||
    Ok(x)
 | 
					    Ok(x)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn parse_string(input: Input) -> Result<String> {
 | 
					pub fn parse_string(input: Input) -> Result<String> {
 | 
				
			||||||
    String::from_utf8(input.to_owned()).map_err(|_| Error::other("invalid utf8"))
 | 
					    Ok(String::from_utf8(input.to_owned())?)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -3,18 +3,17 @@ use std::io::SeekFrom;
 | 
				
			|||||||
use nom::multi::length_data;
 | 
					use nom::multi::length_data;
 | 
				
			||||||
use nom::number::streaming::le_u32;
 | 
					use nom::number::streaming::le_u32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::chunk::ChunkHeader;
 | 
					use crate::error::Result;
 | 
				
			||||||
use crate::error::{Error, Result};
 | 
					 | 
				
			||||||
use crate::index::{ChunkInfo, ConnInfo};
 | 
					 | 
				
			||||||
use crate::parse::{self, Header, Op, Version};
 | 
					use crate::parse::{self, Header, Op, Version};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod error;
 | 
				
			||||||
mod io;
 | 
					mod io;
 | 
				
			||||||
#[cfg(feature = "mmap")]
 | 
					#[cfg(feature = "mmap")]
 | 
				
			||||||
mod mmap;
 | 
					mod mmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use io::IoReader;
 | 
					pub use self::io::IoReader;
 | 
				
			||||||
#[cfg(feature = "mmap")]
 | 
					#[cfg(feature = "mmap")]
 | 
				
			||||||
pub use mmap::MmapReader;
 | 
					pub use self::mmap::MmapReader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait BagReader {
 | 
					pub trait BagReader {
 | 
				
			||||||
    type Read: std::io::Read;
 | 
					    type Read: std::io::Read;
 | 
				
			||||||
@ -37,8 +36,9 @@ pub trait BagReader {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    fn read_header_op(&mut self, op: Op) -> Result<Header> {
 | 
					    fn read_header_op(&mut self, op: Op) -> Result<Header> {
 | 
				
			||||||
        let header = self.read_header()?;
 | 
					        let header = self.read_header()?;
 | 
				
			||||||
        if header.read_op()? != op {
 | 
					        let actual_op = header.read_op()?;
 | 
				
			||||||
            return Err(Error::other(format!("Expected {:?} op", op)));
 | 
					        if actual_op != op {
 | 
				
			||||||
 | 
					            return Err(error::UnexpectedOp(op, actual_op).into());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(header)
 | 
					        Ok(header)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -56,23 +56,4 @@ pub trait BagReader {
 | 
				
			|||||||
    fn read_data(&mut self) -> Result<&[u8]> {
 | 
					    fn read_data(&mut self) -> Result<&[u8]> {
 | 
				
			||||||
        self.read_parser(length_data(le_u32))
 | 
					        self.read_parser(length_data(le_u32))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn read_conn_info(&mut self) -> Result<ConnInfo> {
 | 
					 | 
				
			||||||
        let record_header = self.read_header_op(Op::Connection)?;
 | 
					 | 
				
			||||||
        let conn_header = self.read_header()?;
 | 
					 | 
				
			||||||
        ConnInfo::from_headers(record_header, conn_header)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn read_chunk_info(&mut self) -> Result<ChunkInfo> {
 | 
					 | 
				
			||||||
        let header = self.read_header_op(Op::ChunkInfo)?;
 | 
					 | 
				
			||||||
        // TODO: read connection message counts
 | 
					 | 
				
			||||||
        self.skip_data()?;
 | 
					 | 
				
			||||||
        ChunkInfo::from_header(header)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn read_chunk_header(&mut self, pos: u64) -> Result<ChunkHeader> {
 | 
					 | 
				
			||||||
        self.seek(SeekFrom::Start(pos))?;
 | 
					 | 
				
			||||||
        let header = self.read_header_op(Op::Chunk)?;
 | 
					 | 
				
			||||||
        ChunkHeader::from_header(header)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								src/reader/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/reader/error.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					use thiserror::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::parse::Op;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					#[error("unexpected EOF")]
 | 
				
			||||||
 | 
					pub struct UnexpectedEof;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					#[error("expected op {0:?}, got {1:?}")]
 | 
				
			||||||
 | 
					pub struct UnexpectedOp(pub Op, pub Op);
 | 
				
			||||||
@ -2,8 +2,8 @@ use std::io;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use bytes::{Buf, BytesMut};
 | 
					use bytes::{Buf, BytesMut};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::BagReader;
 | 
					use super::{error::UnexpectedEof, BagReader};
 | 
				
			||||||
use crate::{parse, Error, Result};
 | 
					use crate::{parse, Result};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const READ_SIZE: usize = 4096;
 | 
					const READ_SIZE: usize = 4096;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -31,7 +31,7 @@ impl<R: io::Read + io::Seek> IoReader<R> {
 | 
				
			|||||||
        let read = self.read.read(&mut self.buffer[old_size..])?;
 | 
					        let read = self.read.read(&mut self.buffer[old_size..])?;
 | 
				
			||||||
        self.buffer.truncate(old_size + read);
 | 
					        self.buffer.truncate(old_size + read);
 | 
				
			||||||
        if read == 0 {
 | 
					        if read == 0 {
 | 
				
			||||||
            return Err(Error::Eof);
 | 
					            return Err(UnexpectedEof.into());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -69,7 +69,7 @@ impl<R: io::Read + io::Seek> BagReader for IoReader<R> {
 | 
				
			|||||||
                    unsafe { &mut *this }.read_more(needed.max(READ_SIZE))?;
 | 
					                    unsafe { &mut *this }.read_more(needed.max(READ_SIZE))?;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                Err(nom::Err::Error(e) | nom::Err::Failure(e)) => {
 | 
					                Err(nom::Err::Error(e) | nom::Err::Failure(e)) => {
 | 
				
			||||||
                    return Err(e.into());
 | 
					                    return Err(e.into_owned().into());
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,10 @@
 | 
				
			|||||||
use std::{fs::File, io, sync::Arc};
 | 
					use std::{fs::File, io, sync::Arc};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use eyre::bail;
 | 
				
			||||||
use memmap::Mmap;
 | 
					use memmap::Mmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::BagReader;
 | 
					use super::{error::UnexpectedEof, BagReader};
 | 
				
			||||||
use crate::{parse, Error, Result};
 | 
					use crate::{parse, Result};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone)]
 | 
				
			||||||
pub struct MmapReader {
 | 
					pub struct MmapReader {
 | 
				
			||||||
@ -46,14 +47,14 @@ impl BagReader for MmapReader {
 | 
				
			|||||||
    where
 | 
					    where
 | 
				
			||||||
        P: nom::Parser<&'a [u8], O, parse::Error<&'a [u8]>>,
 | 
					        P: nom::Parser<&'a [u8], O, parse::Error<&'a [u8]>>,
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let input = self.mmap.get(self.pos..).ok_or(Error::Eof)?;
 | 
					        let input = self.mmap.get(self.pos..).ok_or(UnexpectedEof)?;
 | 
				
			||||||
        match parser.parse(input) {
 | 
					        match parser.parse(input) {
 | 
				
			||||||
            Ok((rest, output)) => {
 | 
					            Ok((rest, output)) => {
 | 
				
			||||||
                self.pos += input.len() - rest.len();
 | 
					                self.pos += input.len() - rest.len();
 | 
				
			||||||
                Ok(output)
 | 
					                Ok(output)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Err(nom::Err::Incomplete(_)) => Err(Error::Eof),
 | 
					            Err(nom::Err::Incomplete(_)) => bail!(UnexpectedEof),
 | 
				
			||||||
            Err(nom::Err::Error(e) | nom::Err::Failure(e)) => Err(e.into()),
 | 
					            Err(nom::Err::Error(e) | nom::Err::Failure(e)) => Err(e.into_owned().into()),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user