<commit_before>//! compile-time representations of offsets

use super::write::{FontWrite, TableWriter};

/// The width in bytes of an Offset16
pub const WIDTH_16: usize = 2;
/// The width in bytes of an Offset24
#[allow(dead_code)] // will be used one day :')
pub const WIDTH_24: usize = 3;
/// The width in bytes of an Offset32
pub const WIDTH_32: usize = 4;

/// An offset subtable.
///
/// The generic const `N` is the width of the offset, in bytes.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OffsetMarker<T, const N: usize = WIDTH_16> {
    obj: Option<T>,
}

/// An offset subtable which may be null.
///
/// The generic const `N` is the width of the offset, in bytes.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NullableOffsetMarker<T, const N: usize = WIDTH_16> {
    obj: Option<T>,
}

impl<const N: usize, T> OffsetMarker<T, N> {
    /// `true` if the offset is non-null
    pub fn is_some(&self) -> bool {
        self.obj.is_some()
    }

    /// `true` if the offset is null
    pub fn is_none(&self) -> bool {
        self.obj.is_none()
    }

    //TODO: how do we handle malformed inputs? do we error earlier than this?
    /// Get the object. Fonts in the wild may be malformed, so this still returns
    /// an option?
    pub fn get(&self) -> Option<&T> {
        self.obj.as_ref()
    }

    pub fn get_mut(&mut self) -> Option<&mut T> {
        self.obj.as_mut()
    }

    pub fn set(&mut self, obj: T) {
        self.obj = Some(obj);
    }

    pub fn clear(&mut self) {
        self.obj = None;
    }
}

impl<const N: usize, T> OffsetMarker<T, N> {
    /// Create a new marker.
    pub fn new(obj: T) -> Self {
        OffsetMarker { obj: Some(obj) }
    }

    /// Creates a new marker with an object that may be null.
    //TODO: figure out how we're actually handling null offsets. Some offsets
    //are allowed to be null, but even offsets that aren't *may* be null,
    //and we should handle this.
    pub fn new_maybe_null(obj: Option<T>) -> Self {
        OffsetMarker { obj }
    }
}

impl<const N: usize, T> NullableOffsetMarker<T, N> {
    /// `true` if the offset is non-null
    pub fn is_some(&self) -> bool {
        self.obj.is_some()
    }

    /// `true` if the offset is null
    pub fn is_none(&self) -> bool {
        self.obj.is_none()
    }

    //TODO: how do we handle malformed inputs? do we error earlier than this?
    /// Get the object, if it exists.
    pub fn get(&self) -> Option<&T> {
        self.obj.as_ref()
    }

    pub fn get_mut(&mut self) -> Option<&mut T> {
        self.obj.as_mut()
    }

    pub fn set(&mut self, obj: T) {
        self.obj = Some(obj);
    }

    pub fn clear(&mut self) {
        self.obj = None;
    }
}

impl<const N: usize, T> NullableOffsetMarker<T, N> {
    pub fn new(obj: Option<T>) -> Self {
        NullableOffsetMarker { obj }
    }
}

impl<const N: usize, T: FontWrite> FontWrite for OffsetMarker<T, N> {
    fn write_into(&self, writer: &mut TableWriter) {
        match self.obj.as_ref() {
            Some(obj) => writer.write_offset(obj, N),
            None => {
                eprintln!("warning: unexpected null OffsetMarker");
                writer.write_slice([0u8; N].as_slice());
            }
        }
    }
}

impl<const N: usize, T: FontWrite> FontWrite for NullableOffsetMarker<T, N> {
    fn write_into(&self, writer: &mut TableWriter) {
        match self.obj.as_ref() {
            Some(obj) => writer.write_offset(obj, N),
            None => writer.write_slice([0u8; N].as_slice()),
        }
    }
}

impl<T: Default, const N: usize> Default for OffsetMarker<T, N> {
    fn default() -> Self {
        Self {
            obj: Some(T::default()),
        }
    }
}

impl<T, const N: usize> Default for NullableOffsetMarker<T, N> {
    fn default() -> Self {
        Self { obj: None }
    }
}
// In case I still want to use these?

//impl<T: std::fmt::Debug, const N: usize> std::fmt::Debug for OffsetMarker<T, N> {
//fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//write!(f, "OffsetMarker({}, {:?})", N * 8, self.obj.as_ref(),)
//}
//}

//impl<const N: usize, T: std::fmt::Debug> std::fmt::Debug for NullableOffsetMarker<T, N> {
//fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//write!(
//f,
//"NullableOffsetMarker({}, {:?})",
//N * 8,<commit_msg>Add blanket From<T> and From<Option<T>> for offset markers<commit_after>//! compile-time representations of offsets

use super::write::{FontWrite, TableWriter};

/// The width in bytes of an Offset16
pub const WIDTH_16: usize = 2;
/// The width in bytes of an Offset24
#[allow(dead_code)] // will be used one day :')
pub const WIDTH_24: usize = 3;
/// The width in bytes of an Offset32
pub const WIDTH_32: usize = 4;

/// An offset subtable.
///
/// The generic const `N` is the width of the offset, in bytes.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OffsetMarker<T, const N: usize = WIDTH_16> {
    obj: Option<T>,
}

/// An offset subtable which may be null.
///
/// The generic const `N` is the width of the offset, in bytes.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NullableOffsetMarker<T, const N: usize = WIDTH_16> {
    obj: Option<T>,
}

impl<const N: usize, T> OffsetMarker<T, N> {
    /// `true` if the offset is non-null
    pub fn is_some(&self) -> bool {
        self.obj.is_some()
    }

    /// `true` if the offset is null
    pub fn is_none(&self) -> bool {
        self.obj.is_none()
    }

    //TODO: how do we handle malformed inputs? do we error earlier than this?
    /// Get the object. Fonts in the wild may be malformed, so this still returns
    /// an option?
    pub fn get(&self) -> Option<&T> {
        self.obj.as_ref()
    }

    pub fn get_mut(&mut self) -> Option<&mut T> {
        self.obj.as_mut()
    }

    pub fn set(&mut self, obj: T) {
        self.obj = Some(obj);
    }

    pub fn clear(&mut self) {
        self.obj = None;
    }
}

impl<const N: usize, T> OffsetMarker<T, N> {
    /// Create a new marker.
    pub fn new(obj: T) -> Self {
        OffsetMarker { obj: Some(obj) }
    }

    /// Creates a new marker with an object that may be null.
    //TODO: figure out how we're actually handling null offsets. Some offsets
    //are allowed to be null, but even offsets that aren't *may* be null,
    //and we should handle this.
    pub fn new_maybe_null(obj: Option<T>) -> Self {
        OffsetMarker { obj }
    }
}

impl<const N: usize, T> NullableOffsetMarker<T, N> {
    /// `true` if the offset is non-null
    pub fn is_some(&self) -> bool {
        self.obj.is_some()
    }

    /// `true` if the offset is null
    pub fn is_none(&self) -> bool {
        self.obj.is_none()
    }

    //TODO: how do we handle malformed inputs? do we error earlier than this?
    /// Get the object, if it exists.
    pub fn get(&self) -> Option<&T> {
        self.obj.as_ref()
    }

    pub fn get_mut(&mut self) -> Option<&mut T> {
        self.obj.as_mut()
    }

    pub fn set(&mut self, obj: T) {
        self.obj = Some(obj);
    }

    pub fn clear(&mut self) {
        self.obj = None;
    }
}

impl<const N: usize, T> NullableOffsetMarker<T, N> {
    pub fn new(obj: Option<T>) -> Self {
        NullableOffsetMarker { obj }
    }
}

impl<const N: usize, T: FontWrite> FontWrite for OffsetMarker<T, N> {
    fn write_into(&self, writer: &mut TableWriter) {
        match self.obj.as_ref() {
            Some(obj) => writer.write_offset(obj, N),
            None => {
                eprintln!("warning: unexpected null OffsetMarker");
                writer.write_slice([0u8; N].as_slice());
            }
        }
    }
}

impl<const N: usize, T: FontWrite> FontWrite for NullableOffsetMarker<T, N> {
    fn write_into(&self, writer: &mut TableWriter) {
        match self.obj.as_ref() {
            Some(obj) => writer.write_offset(obj, N),
            None => writer.write_slice([0u8; N].as_slice()),
        }
    }
}

impl<T: Default, const N: usize> Default for OffsetMarker<T, N> {
    fn default() -> Self {
        Self {
            obj: Some(T::default()),
        }
    }
}

impl<T, const N: usize> Default for NullableOffsetMarker<T, N> {
    fn default() -> Self {
        Self { obj: None }
    }
}

impl<T, const N: usize> From<T> for OffsetMarker<T, N> {
    fn from(src: T) -> Self {
        OffsetMarker::new(src)
    }
}

impl<T, const N: usize> From<T> for NullableOffsetMarker<T, N> {
    fn from(src: T) -> Self {
        NullableOffsetMarker::new(Some(src))
    }
}

impl<T, const N: usize> From<Option<T>> for NullableOffsetMarker<T, N> {
    fn from(src: Option<T>) -> Self {
        NullableOffsetMarker::new(src)
    }
}

// In case I still want to use these?

//impl<T: std::fmt::Debug, const N: usize> std::fmt::Debug for OffsetMarker<T, N> {
//fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//write!(f, "OffsetMarker({}, {:?})", N * 8, self.obj.as_ref(),)
//}
//}

//impl<const N: usize, T: std::fmt::Debug> std::fmt::Debug for NullableOffsetMarker<T, N> {
//fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//write!(
//f,
//"NullableOffsetMarker({}, {:?})",
//N * 8,
{'fraction_non_alphanumeric': 0.15445284258954978, 'fraction_numerical': 0.005477051155657794, 'mean_word_length': 2.4258911819887428, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 118, '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': '3486281', 'n_tokens_mistral': 3184, 'n_tokens_neox': 3127, 'n_words': 983}