<commit_before>use std::error;

#[derive(Debug)]
pub struct RootEntry {
    pub filename:  [u8; 8],
    pub extension: [u8; 3],
    attrs: u8,
    pub reserved: u16,
    pub creation_time: u16,
    pub creation_date: u16,
    pub last_access_date: u16,
    _ignore: u16,
    pub last_write_time: u16,
    pub last_write_date: u16,
    pub first_logical_cluster: u16,
    pub file_size: u32, // in bytes
}

#[allow(dead_code)]
impl RootEntry {
    pub fn filename(&self) -> Result<String, Box<error::Error>> {
        let mut my_fn = self.filename.to_vec();
        let mut name = my_fn
            .drain(..)
            .take_while(|&c| c != ' ' as u8)
            .collect::<Vec<u8>>();
        name.push('.' as u8);
        name.extend(self.extension.iter());

        match String::from_utf8(name) {
            Ok(s) => Ok(s),
            Err(err) => Err(From::from(err)),
        }
    }

    pub fn is_read_only(&self)    -> bool {
        self.attrs & 0x01 == 0x01
    }
    pub fn is_hidden(&self)       -> bool {
        self.attrs & 0x02 == 0x02
    }
    pub fn is_system(&self)       -> bool {
        self.attrs & 0x04 == 0x04
    }
    pub fn is_volume_label(&self) -> bool {
        self.attrs & 0x08 == 0x08
    }
    pub fn is_subdir(&self)       -> bool {
        self.attrs & 0x10 == 0x10
    }
    pub fn is_archive(&self)      -> bool {
        self.attrs & 0x20 == 0x20
    }

    pub fn is_free(&self) -> bool {
        self.filename[0] == 0 || self.filename[0] == 0xe5
    }

    pub fn rest_are_free(&self) -> bool {
        self.filename[0] == 0
    }

    pub fn filename_full(&self) -> String {
        let filename = String::from_utf8(
            Vec::from(&self.filename[..])
        );
        let extension = String::from_utf8(
            Vec::from(&self.extension[..])
        );

        if filename.is_ok() && extension.is_ok() {
            format!(
                "{}.{}",
                filename.unwrap(),
                extension.unwrap()
            )
        } else {
            "BAD FILENAME".to_string()
        }
    }
}<commit_msg>Improve RootEntry pretty-printing<commit_after>use std::error;
use std::fmt;
use std::fmt::Debug;

pub struct RootEntry {
    pub filename:  [u8; 8],
    pub extension: [u8; 3],
    attrs: u8,
    reserved: u16,
    pub creation_time: u16,
    pub creation_date: u16,
    pub last_access_date: u16,
    _ignore: u16,
    pub last_write_time: u16,
    pub last_write_date: u16,
    pub first_logical_cluster: u16,
    pub file_size: u32, // in bytes
}

#[allow(dead_code)]
impl RootEntry {
    pub fn filename(&self) -> Result<String, Box<error::Error>> {
        let mut my_fn = self.filename.to_vec();
        let mut name = my_fn
            .drain(..)
            .take_while(|&c| c != ' ' as u8)
            .collect::<Vec<u8>>();
        name.push('.' as u8);
        name.extend(self.extension.iter());

        match String::from_utf8(name) {
            Ok(s) => Ok(s),
            Err(err) => Err(From::from(err)),
        }
    }

    pub fn is_read_only(&self)    -> bool {
        self.attrs & 0x01 == 0x01
    }
    pub fn is_hidden(&self)       -> bool {
        self.attrs & 0x02 == 0x02
    }
    pub fn is_system(&self)       -> bool {
        self.attrs & 0x04 == 0x04
    }
    pub fn is_volume_label(&self) -> bool {
        self.attrs & 0x08 == 0x08
    }
    pub fn is_subdir(&self)       -> bool {
        self.attrs & 0x10 == 0x10
    }
    pub fn is_archive(&self)      -> bool {
        self.attrs & 0x20 == 0x20
    }

    pub fn is_free(&self) -> bool {
        self.filename[0] == 0 || self.filename[0] == 0xe5
    }

    pub fn rest_are_free(&self) -> bool {
        self.filename[0] == 0
    }

    pub fn filename_full(&self) -> String {
        let filename = String::from_utf8(
            Vec::from(&self.filename[..])
        );
        let extension = String::from_utf8(
            Vec::from(&self.extension[..])
        );

        if filename.is_ok() && extension.is_ok() {
            format!(
                "{}.{}",
                filename.unwrap(),
                extension.unwrap()
            )
        } else {
            "BAD FILENAME".to_string()
        }
    }
}

impl Debug for RootEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("RootEntry")
            .field(
                "filename",
                &self.filename().unwrap_or("bad filename".to_string())
            )
            .field("attrs",                 &self.attrs)
            .field("creation_time",         &self.creation_time)
            .field("creation_date",         &self.creation_date)
            .field("last_access_date",      &self.last_access_date)
            .field("last_write_time",       &self.last_write_time)
            .field("last_write_date",       &self.last_write_date)
            .field("first_logical_cluster", &self.first_logical_cluster)
            .field("file_size",             &format!("{:#x}", self.file_size))
            .finish()
    }
}
{'fraction_non_alphanumeric': 0.14640938929779193, 'fraction_numerical': 0.028645315297394072, 'mean_word_length': 1.7266811279826464, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3704009', 'n_tokens_mistral': 1760, 'n_tokens_neox': 1666, 'n_words': 343}