cff 0.5.0

A zero-allocation CFF parser.
// Copyright 2018 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! CFF type 2 charstring deques.

#![allow(dead_code)]

use core::fmt::{Debug, Error, Formatter};

use tarrasque::{ExtractError, ExtractResult};

use crate::error::{OVERFLOW, UNDERFLOW};
use super::{Number};

/// The size of the charstring number deque.
const SIZE: usize = 64;

/// A type 2 charstring number double-ended queue.
#[derive(Copy, Clone)]
pub struct NumberDeque {
    buffer: [Number; SIZE],
    top: usize,
    bottom: usize,
}

impl NumberDeque {
    /// Constructs a new number deque.
    #[inline]
    pub fn new() -> Self {
        Self { buffer: [Number::Integer(0); SIZE], top: 0, bottom: 0 }
    }

    /// Returns the number of numbers in this deque.
    #[inline]
    pub fn len(&self) -> usize {
        self.top.wrapping_sub(self.bottom)
    }

    /// Returns whether there are no numbers in this deque.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.top == self.bottom
    }

    /// Pushes the supplied number onto the top of this deque.
    #[inline]
    pub fn push_top<'s>(&mut self, value: Number) -> ExtractResult<'s, ()> {
        if self.len() != self.buffer.len() {
            self.buffer[self.top & (self.buffer.len() - 1)] = value;
            self.top = self.top.wrapping_add(1);
            Ok(())
        } else {
            Err(ExtractError::Code(OVERFLOW))
        }
    }

    /// Pushes the supplied number onto the bottom of this deque.
    #[inline]
    pub fn push_bottom<'s>(
        &mut self, value: Number
    ) -> ExtractResult<'s, ()> {
        if self.len() != self.buffer.len() {
            self.bottom = self.bottom.wrapping_sub(1);
            self.buffer[self.bottom & (self.buffer.len() - 1)] = value;
            Ok(())
        } else {
            Err(ExtractError::Code(OVERFLOW))
        }
    }

    /// Removes and returns the number at the top of this deque.
    #[inline]
    pub fn pop_top<'s, T>(
        &mut self
    ) -> ExtractResult<'s, T> where Number: Into<T> {
        if !self.is_empty() {
            self.top -= 1;
            Ok(self.buffer[self.top & (self.buffer.len() - 1)].into())
        } else {
            Err(ExtractError::Code(UNDERFLOW))
        }
    }

    /// Removes and returns the number at the top of this deque.
    #[inline]
    pub fn pop_bottom<'s, T>(
        &mut self
    ) -> ExtractResult<'s, T> where Number: Into<T> {
        if !self.is_empty() {
            let value = self.buffer[self.bottom & (self.buffer.len() - 1)];
            self.bottom = self.bottom.wrapping_add(1);
            Ok(value.into())
        } else {
            Err(ExtractError::Code(UNDERFLOW))
        }
    }
}

impl Debug for NumberDeque {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let bottom = self.bottom & (self.buffer.len() - 1);
        let top = self.top & (self.buffer.len() - 1);
        f.debug_list().entries((bottom..top).map(|i| self.buffer[i])).finish()
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_number_deque_top() {
        let mut deque = NumberDeque::new();

        for number in 0..SIZE as i16 {
            deque.push_top(Number::Integer(number)).unwrap();
        }

        let result = deque.push_top(Number::Integer(64));
        assert_eq!(result, Err(ExtractError::Code(OVERFLOW)));

        for number in (0..SIZE as i16).rev() {
            assert_eq!(deque.pop_top(), Ok(Number::Integer(number)));
        }

        let result = deque.pop_top::<i16>();
        assert_eq!(result, Err(ExtractError::Code(UNDERFLOW)));
    }

    #[test]
    fn test_number_deque_bottom() {
        let mut deque = NumberDeque::new();

        for number in 0..SIZE as i16 {
            deque.push_bottom(Number::Integer(number)).unwrap();
        }

        let result = deque.push_bottom(Number::Integer(64));
        assert_eq!(result, Err(ExtractError::Code(OVERFLOW)));

        for number in (0..SIZE as i16).rev() {
            assert_eq!(deque.pop_bottom(), Ok(Number::Integer(number)));
        }

        let result = deque.pop_bottom::<i16>();
        assert_eq!(result, Err(ExtractError::Code(UNDERFLOW)));
    }
}