use core::fmt;
use core::num::NonZeroU64;
use core::ops::{Add, AddAssign};
use binrw::BinRead;
use derive_more::{Binary, Display, From, LowerHex, Octal, UpperHex};
use crate::error::{NtfsError, Result};
use crate::ntfs::Ntfs;
#[derive(Clone, Copy, Debug, Eq, From, Ord, PartialEq, PartialOrd)]
pub struct NtfsPosition(Option<NonZeroU64>);
impl NtfsPosition {
const NONE_STR: &'static str = "<NONE>";
pub(crate) const fn new(position: u64) -> Self {
Self(NonZeroU64::new(position))
}
pub(crate) const fn none() -> Self {
Self(None)
}
pub const fn value(&self) -> Option<NonZeroU64> {
self.0
}
}
impl Add<u16> for NtfsPosition {
type Output = Self;
fn add(self, other: u16) -> Self {
self + other as u64
}
}
impl Add<u64> for NtfsPosition {
type Output = Self;
fn add(self, other: u64) -> Self {
let new_value = self
.0
.and_then(|position| NonZeroU64::new(position.get().wrapping_add(other)));
Self(new_value)
}
}
impl Add<usize> for NtfsPosition {
type Output = Self;
fn add(self, other: usize) -> Self {
self + other as u64
}
}
impl AddAssign<u16> for NtfsPosition {
fn add_assign(&mut self, other: u16) {
*self = *self + other;
}
}
impl AddAssign<u64> for NtfsPosition {
fn add_assign(&mut self, other: u64) {
*self = *self + other;
}
}
impl AddAssign<usize> for NtfsPosition {
fn add_assign(&mut self, other: usize) {
*self = *self + other;
}
}
impl fmt::Binary for NtfsPosition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Some(position) => fmt::Binary::fmt(&position, f),
None => fmt::Display::fmt(Self::NONE_STR, f),
}
}
}
impl fmt::Display for NtfsPosition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Some(position) => fmt::Display::fmt(&position, f),
None => fmt::Display::fmt(Self::NONE_STR, f),
}
}
}
impl fmt::LowerHex for NtfsPosition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Some(position) => fmt::LowerHex::fmt(&position, f),
None => fmt::Display::fmt(Self::NONE_STR, f),
}
}
}
impl fmt::Octal for NtfsPosition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Some(position) => fmt::Octal::fmt(&position, f),
None => fmt::Display::fmt(Self::NONE_STR, f),
}
}
}
impl fmt::UpperHex for NtfsPosition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Some(position) => fmt::UpperHex::fmt(&position, f),
None => fmt::Display::fmt(Self::NONE_STR, f),
}
}
}
impl From<NonZeroU64> for NtfsPosition {
fn from(value: NonZeroU64) -> Self {
Self(Some(value))
}
}
#[derive(
Binary,
BinRead,
Clone,
Copy,
Debug,
Display,
Eq,
From,
LowerHex,
Octal,
Ord,
PartialEq,
PartialOrd,
UpperHex,
)]
pub struct Lcn(u64);
impl Lcn {
pub fn checked_add(&self, vcn: Vcn) -> Option<Lcn> {
if vcn.0 >= 0 {
self.0.checked_add(vcn.0 as u64).map(Into::into)
} else {
self.0
.checked_sub(vcn.0.wrapping_neg() as u64)
.map(Into::into)
}
}
pub fn position(&self, ntfs: &Ntfs) -> Result<NtfsPosition> {
let value = self
.0
.checked_mul(ntfs.cluster_size() as u64)
.ok_or(NtfsError::LcnTooBig { lcn: *self })?;
Ok(NtfsPosition::new(value))
}
pub fn value(&self) -> u64 {
self.0
}
}
#[derive(
Binary,
BinRead,
Clone,
Copy,
Debug,
Display,
Eq,
From,
LowerHex,
Octal,
Ord,
PartialEq,
PartialOrd,
UpperHex,
)]
pub struct Vcn(i64);
impl Vcn {
pub fn offset(&self, ntfs: &Ntfs) -> Result<i64> {
self.0
.checked_mul(ntfs.cluster_size() as i64)
.ok_or(NtfsError::VcnTooBig { vcn: *self })
}
pub fn value(&self) -> i64 {
self.0
}
}