/// Metadata about an inode, including unix-style permissions and
/// whether this inode is a directory.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
#[doc(hidden)]
pub struct InodeMetadata(pub u16);
const DIR_BIT: u16 = 0x200;

use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
impl InodeMetadata {
    /// Read the file metadata from the file name encoded in the
    /// repository.
    pub fn from_basename(p: &[u8]) -> Self {
        debug_assert!(p.len() == 2);
        InodeMetadata(BigEndian::read_u16(p))
    }

    /// Create a new file metadata with the given Unix permissions,
    /// and "is directory" bit.
    pub fn new(perm: usize, is_dir: bool) -> Self {
        let mut m = InodeMetadata(0);
        m.set_permissions(perm as u16);
        if is_dir {
            m.set_dir()
        } else {
            m.unset_dir()
        }
        m
    }

    /// Permissions of this inode (as in Unix).
    pub fn permissions(&self) -> u16 {
        u16::from_le(self.0) & 0x1ff
    }

    /// Set the permissions to the supplied parameters.
    pub fn set_permissions(&mut self, perm: u16) {
        let bits = u16::from_le(self.0);
        let perm = (bits & !0x1ff) | perm;
        self.0 = perm.to_le()
    }

    /// Tell whether this `InodeMetadata` is a directory.
    pub fn is_dir(&self) -> bool {
        u16::from_le(self.0) & DIR_BIT != 0
    }

    /// Tell whether this `InodeMetadata` is a file.
    pub fn is_file(&self) -> bool {
        u16::from_le(self.0) & DIR_BIT == 0
    }

    /// Set the metadata to be a directory.
    pub fn set_dir(&mut self) {
        let bits = u16::from_le(self.0);
        self.0 = (bits | DIR_BIT).to_le()
    }

    /// Set the metadata to be a file.
    pub fn unset_dir(&mut self) {
        let bits = u16::from_le(self.0);
        self.0 = (bits & !DIR_BIT).to_le()
    }

    pub fn write<W: std::io::Write>(&self, mut w: W) -> std::io::Result<()> {
        w.write_u16::<BigEndian>(self.0)
    }
}