<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ops::Range;
use std::u32;
use vk;

#[derive(Debug, Clone)]
pub struct DepthStencil {
    pub depth_write: bool,
    pub depth_compare: Compare,
    pub depth_bounds_test: DepthBounds,
    pub stencil_front: Stencil,
    pub stencil_back: Stencil,
}

impl DepthStencil {
    /// Creates a `DepthStencil` with a `Less` depth test, `depth_write` set to true, and stencil
    /// testing disabled.
    #[inline]
    pub fn simple_depth_test() -> DepthStencil {
        DepthStencil {
            depth_write: true,
            depth_compare: Compare::Less,
            depth_bounds_test: DepthBounds::Disabled,
            stencil_front: Default::default(),
            stencil_back: Default::default(),
        }
    }
}

impl Default for DepthStencil {
    #[inline]
    fn default() -> DepthStencil {
        DepthStencil {
            depth_write: false,
            depth_compare: Compare::Always,
            depth_bounds_test: DepthBounds::Disabled,
            stencil_front: Default::default(),
            stencil_back: Default::default(),
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Stencil {
    /// The comparison to perform between the existing stencil value in the stencil buffer, and
    /// the reference value (given by `reference`).
    pub compare: Compare,

    /// The operation to perform when both the depth test and the stencil test passed.
    pub pass_op: StencilOp,

    /// The operation to perform when the stencil test failed.
    pub fail_op: StencilOp,

    /// The operation to perform when the stencil test passed but the depth test failed.
    pub depth_fail_op: StencilOp,

    /// Selects the bits of the unsigned integer stencil values participating in the stencil test.
    ///
    /// Ignored if `compare` is `Never` or `Always`.
    ///
    /// If `None`, then this value is dynamic and will need to be set when drawing. Doesn't apply
    /// if `compare` is `Never` or `Always`.
    ///
    /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in
    /// `stencil_back` (but the content can be different). If this value is `None` in
    /// `stencil_front`, then it must also be `None` in `stencil_back`. This rule doesn't apply
    /// if `compare` is `Never` or `Always`.
    pub compare_mask: Option<u32>,

    /// Selects the bits of the unsigned integer stencil values updated by the stencil test in the
    /// stencil framebuffer attachment.
    ///
    /// If `None`, then this value is dynamic and will need to be set when drawing.
    ///
    /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in
    /// `stencil_back` (but the content can be different). If this value is `None` in
    /// `stencil_front`, then it must also be `None` in `stencil_back`.
    pub write_mask: Option<u32>,

    /// Reference value that is used in the unsigned stencil comparison.
    ///
    /// If `None`, then this value is dynamic and will need to be set when drawing.
    ///
    /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in
    /// `stencil_back` (but the content can be different). If this value is `None` in
    /// `stencil_front`, then it must also be `None` in `stencil_back`.
    pub reference: Option<u32>,
}

impl Stencil {
    /// Returns true if the stencil operation will always result in `Keep`.
    #[inline]
    pub fn always_keep(&self) -> bool {
        match self.compare {
            Compare::Always => self.pass_op == StencilOp::Keep &&
                               self.depth_fail_op == StencilOp::Keep,
            Compare::Never => self.fail_op == StencilOp::Keep,
            _ => self.pass_op == StencilOp::Keep && self.fail_op == StencilOp::Keep &&
                 self.depth_fail_op == StencilOp::Keep,
        }
    }
}

impl Default for Stencil {
    #[inline]
    fn default() -> Stencil {
        Stencil {
            compare: Compare::Never,
            pass_op: StencilOp::Keep,
            fail_op: StencilOp::Keep,
            depth_fail_op: StencilOp::Keep,
            compare_mask: Some(u32::MAX),
            write_mask: Some(u32::MAX),
            reference: Some(u32::MAX),
        }
    }
}

/// Operation to perform after the depth and stencil tests.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum StencilOp {
    Keep = vk::STENCIL_OP_KEEP,
    Zero = vk::STENCIL_OP_ZERO,
    Replace = vk::STENCIL_OP_REPLACE,
    IncrementAndClamp = vk::STENCIL_OP_INCREMENT_AND_CLAMP,
    DecrementAndClamp = vk::STENCIL_OP_DECREMENT_AND_CLAMP,
    Invert = vk::STENCIL_OP_INVERT,
    IncrementAndWrap = vk::STENCIL_OP_INCREMENT_AND_WRAP,
    DecrementAndWrap = vk::STENCIL_OP_DECREMENT_AND_WRAP,
}

#[derive(Debug, Clone, PartialEq)]
pub enum DepthBounds {
    Disabled,
    Fixed(Range<f32>),
    Dynamic,
}

impl DepthBounds {
    /// Returns true if equal to `DepthBounds::Dynamic`.
    #[inline]
    pub fn is_dynamic(&self) -> bool {
        match self {
            &DepthBounds::Dynamic => true,
            _ => false,
        }
    }
}

/// Specifies how two values should be compared to decide whether a test passes or fails.
///
/// Used for both depth testing and stencil testing.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum Compare {
    /// The test never passes.
    Never = vk::COMPARE_OP_NEVER,
    /// The test passes if `value < reference_value`.
    Less = vk::COMPARE_OP_LESS,
    /// The test passes if `value == reference_value`.
    Equal = vk::COMPARE_OP_EQUAL,
    /// The test passes if `value <= reference_value`.
    LessOrEqual = vk::COMPARE_OP_LESS_OR_EQUAL,
    /// The test passes if `value > reference_value`.
    Greater = vk::COMPARE_OP_GREATER,
    /// The test passes if `value != reference_value`.
    NotEqual = vk::COMPARE_OP_NOT_EQUAL,
    /// The test passes if `value >= reference_value`.
    GreaterOrEqual = vk::COMPARE_OP_GREATER_OR_EQUAL,
    /// The test always passes.
    Always = vk::COMPARE_OP_ALWAYS,
}
<commit_msg>Add docs to depth_stencil.rs<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ops::Range;
use std::u32;
use vk;

/// Configuration of the depth and stencil tests.
#[derive(Debug, Clone)]
pub struct DepthStencil {
    /// Comparison to use between the depth value of each fragment and the depth value currently
    /// in the depth buffer.
    pub depth_compare: Compare,

    /// If `true`, then the value in the depth buffer will be updated when the depth test succeeds.
    pub depth_write: bool,

    /// Allows you to ask the GPU to exclude fragments that are outside of a certain range. This is
    /// done in addition to the regular depth test.
    pub depth_bounds_test: DepthBounds,

    /// Stencil operations to use for points, lines and triangles whose front is facing the user.
    pub stencil_front: Stencil,

    /// Stencil operations to use for triangles whose back is facing the user.
    pub stencil_back: Stencil,
}

impl DepthStencil {
    /// Creates a `DepthStencil` with a `Less` depth test, `depth_write` set to true, and stencil
    /// testing disabled.
    #[inline]
    pub fn simple_depth_test() -> DepthStencil {
        DepthStencil {
            depth_write: true,
            depth_compare: Compare::Less,
            depth_bounds_test: DepthBounds::Disabled,
            stencil_front: Default::default(),
            stencil_back: Default::default(),
        }
    }
}

impl Default for DepthStencil {
    #[inline]
    fn default() -> DepthStencil {
        DepthStencil {
            depth_write: false,
            depth_compare: Compare::Always,
            depth_bounds_test: DepthBounds::Disabled,
            stencil_front: Default::default(),
            stencil_back: Default::default(),
        }
    }
}

/// Configuration of a stencil test.
#[derive(Debug, Copy, Clone)]
pub struct Stencil {
    /// The comparison to perform between the existing stencil value in the stencil buffer, and
    /// the reference value (given by `reference`).
    pub compare: Compare,

    /// The operation to perform when both the depth test and the stencil test passed.
    pub pass_op: StencilOp,

    /// The operation to perform when the stencil test failed.
    pub fail_op: StencilOp,

    /// The operation to perform when the stencil test passed but the depth test failed.
    pub depth_fail_op: StencilOp,

    /// Selects the bits of the unsigned integer stencil values participating in the stencil test.
    ///
    /// Ignored if `compare` is `Never` or `Always`.
    ///
    /// If `None`, then this value is dynamic and will need to be set when drawing. Doesn't apply
    /// if `compare` is `Never` or `Always`.
    ///
    /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in
    /// `stencil_back` (but the content can be different). If this value is `None` in
    /// `stencil_front`, then it must also be `None` in `stencil_back`. This rule doesn't apply
    /// if `compare` is `Never` or `Always`.
    pub compare_mask: Option<u32>,

    /// Selects the bits of the unsigned integer stencil values updated by the stencil test in the
    /// stencil framebuffer attachment.
    ///
    /// If `None`, then this value is dynamic and will need to be set when drawing.
    ///
    /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in
    /// `stencil_back` (but the content can be different). If this value is `None` in
    /// `stencil_front`, then it must also be `None` in `stencil_back`.
    pub write_mask: Option<u32>,

    /// Reference value that is used in the unsigned stencil comparison.
    ///
    /// If `None`, then this value is dynamic and will need to be set when drawing.
    ///
    /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in
    /// `stencil_back` (but the content can be different). If this value is `None` in
    /// `stencil_front`, then it must also be `None` in `stencil_back`.
    pub reference: Option<u32>,
}

impl Stencil {
    /// Returns true if the stencil operation will always result in `Keep`.
    #[inline]
    pub fn always_keep(&self) -> bool {
        match self.compare {
            Compare::Always => self.pass_op == StencilOp::Keep &&
                               self.depth_fail_op == StencilOp::Keep,
            Compare::Never => self.fail_op == StencilOp::Keep,
            _ => self.pass_op == StencilOp::Keep && self.fail_op == StencilOp::Keep &&
                 self.depth_fail_op == StencilOp::Keep,
        }
    }
}

impl Default for Stencil {
    #[inline]
    fn default() -> Stencil {
        Stencil {
            compare: Compare::Never,
            pass_op: StencilOp::Keep,
            fail_op: StencilOp::Keep,
            depth_fail_op: StencilOp::Keep,
            compare_mask: Some(u32::MAX),
            write_mask: Some(u32::MAX),
            reference: Some(u32::MAX),
        }
    }
}

/// Operation to perform after the depth and stencil tests.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum StencilOp {
    Keep = vk::STENCIL_OP_KEEP,
    Zero = vk::STENCIL_OP_ZERO,
    Replace = vk::STENCIL_OP_REPLACE,
    IncrementAndClamp = vk::STENCIL_OP_INCREMENT_AND_CLAMP,
    DecrementAndClamp = vk::STENCIL_OP_DECREMENT_AND_CLAMP,
    Invert = vk::STENCIL_OP_INVERT,
    IncrementAndWrap = vk::STENCIL_OP_INCREMENT_AND_WRAP,
    DecrementAndWrap = vk::STENCIL_OP_DECREMENT_AND_WRAP,
}

/// Allows you to ask the GPU to exclude fragments that are outside of a certain range.
#[derive(Debug, Clone, PartialEq)]
pub enum DepthBounds {
    /// The test is disabled. All fragments pass the depth bounds test.
    Disabled,

    /// Fragments that are within the given range do pass the test. Values are depth values
    /// between 0.0 and 1.0.
    Fixed(Range<f32>),

    /// The depth bounds test is enabled, but the range will need to specified when you submit
    /// a draw command.
    Dynamic,
}

impl DepthBounds {
    /// Returns true if equal to `DepthBounds::Dynamic`.
    #[inline]
    pub fn is_dynamic(&self) -> bool {
        match self {
            &DepthBounds::Dynamic => true,
            _ => false,
        }
    }
}

/// Specifies how two values should be compared to decide whether a test passes or fails.
///
/// Used for both depth testing and stencil testing.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum Compare {
    /// The test never passes.
    Never = vk::COMPARE_OP_NEVER,
    /// The test passes if `value < reference_value`.
    Less = vk::COMPARE_OP_LESS,
    /// The test passes if `value == reference_value`.
    Equal = vk::COMPARE_OP_EQUAL,
    /// The test passes if `value <= reference_value`.
    LessOrEqual = vk::COMPARE_OP_LESS_OR_EQUAL,
    /// The test passes if `value > reference_value`.
    Greater = vk::COMPARE_OP_GREATER,
    /// The test passes if `value != reference_value`.
    NotEqual = vk::COMPARE_OP_NOT_EQUAL,
    /// The test passes if `value >= reference_value`.
    GreaterOrEqual = vk::COMPARE_OP_GREATER_OR_EQUAL,
    /// The test always passes.
    Always = vk::COMPARE_OP_ALWAYS,
}
<|endoftext|>


<commit_before>use crate::mir::interpret::{sign_extend, truncate, InterpErrorInfo, InterpResult};
use crate::throw_ub;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_macros::HashStable;
use rustc_target::abi::{Size, TargetDataLayout};
use std::convert::{TryFrom, TryInto};
use std::fmt;

#[derive(Copy, Clone)]
/// A type for representing any integer. Only used for printing.
pub struct ConstInt {
    /// The "untyped" variant of `ConstInt`.
    int: ScalarInt,
    /// Whether the value is of a signed integer type.
    signed: bool,
    /// Whether the value is a `usize` or `isize` type.
    is_ptr_sized_integral: bool,
}

impl ConstInt {
    pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
        Self { int, signed, is_ptr_sized_integral }
    }
}

impl std::fmt::Debug for ConstInt {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let Self { int, signed, is_ptr_sized_integral } = *self;
        let size = int.size().bytes();
        let raw = int.data();
        if signed {
            let bit_size = size * 8;
            let min = 1u128 << (bit_size - 1);
            let max = min - 1;
            if raw == min {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MIN"),
                    (1, _) => write!(fmt, "i8::MIN"),
                    (2, _) => write!(fmt, "i16::MIN"),
                    (4, _) => write!(fmt, "i32::MIN"),
                    (8, _) => write!(fmt, "i64::MIN"),
                    (16, _) => write!(fmt, "i128::MIN"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MAX"),
                    (1, _) => write!(fmt, "i8::MAX"),
                    (2, _) => write!(fmt, "i16::MAX"),
                    (4, _) => write!(fmt, "i32::MAX"),
                    (8, _) => write!(fmt, "i64::MAX"),
                    (16, _) => write!(fmt, "i128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as i8)?,
                    2 => write!(fmt, "{}", raw as i16)?,
                    4 => write!(fmt, "{}", raw as i32)?,
                    8 => write!(fmt, "{}", raw as i64)?,
                    16 => write!(fmt, "{}", raw as i128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_isize")?,
                        (1, _) => write!(fmt, "_i8")?,
                        (2, _) => write!(fmt, "_i16")?,
                        (4, _) => write!(fmt, "_i32")?,
                        (8, _) => write!(fmt, "_i64")?,
                        (16, _) => write!(fmt, "_i128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        } else {
            let max = truncate(u128::MAX, Size::from_bytes(size));
            if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "usize::MAX"),
                    (1, _) => write!(fmt, "u8::MAX"),
                    (2, _) => write!(fmt, "u16::MAX"),
                    (4, _) => write!(fmt, "u32::MAX"),
                    (8, _) => write!(fmt, "u64::MAX"),
                    (16, _) => write!(fmt, "u128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as u8)?,
                    2 => write!(fmt, "{}", raw as u16)?,
                    4 => write!(fmt, "{}", raw as u32)?,
                    8 => write!(fmt, "{}", raw as u64)?,
                    16 => write!(fmt, "{}", raw as u128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_usize")?,
                        (1, _) => write!(fmt, "_u8")?,
                        (2, _) => write!(fmt, "_u16")?,
                        (4, _) => write!(fmt, "_u32")?,
                        (8, _) => write!(fmt, "_u64")?,
                        (16, _) => write!(fmt, "_u128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        }
    }
}

// FIXME: reuse in `super::int::ConstInt` and `Scalar::Bits`
/// The raw bytes of a simple value.
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
#[derive(HashStable)]
pub struct ScalarInt {
    /// The first `size` bytes of `data` are the value.
    /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
    ///
    /// This is an array in order to allow this type to be optimally embedded in enums
    /// (like Scalar).
    bytes: [u8; 16],
    size: u8,
}

impl ScalarInt {
    pub const TRUE: ScalarInt = ScalarInt { bytes: 1_u128.to_ne_bytes(), size: 1 };

    pub const FALSE: ScalarInt = ScalarInt { bytes: 0_u128.to_ne_bytes(), size: 1 };

    pub const ZST: ScalarInt = ScalarInt { bytes: 0_u128.to_ne_bytes(), size: 0 };

    fn data(self) -> u128 {
        u128::from_ne_bytes(self.bytes)
    }

    #[inline]
    pub fn size(self) -> Size {
        Size::from_bytes(self.size)
    }

    /// Make sure the `data` fits in `size`.
    /// This is guaranteed by all constructors here, but since the enum variants are public,
    /// it could still be violated (even though no code outside this file should
    /// construct `Scalar`s).
    #[inline(always)]
    fn check_data(self) {
        debug_assert_eq!(
            truncate(self.data(), self.size()),
            self.data(),
            "Scalar value {:#x} exceeds size of {} bytes",
            self.data(),
            self.size
        );
    }

    #[inline]
    pub fn zst() -> Self {
        Self::null(Size::ZERO)
    }

    #[inline]
    pub fn null(size: Size) -> Self {
        Self { bytes: [0; 16], size: size.bytes() as u8 }
    }

    pub(crate) fn ptr_sized_op<'tcx>(
        self,
        dl: &TargetDataLayout,
        f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>,
    ) -> InterpResult<'tcx, Self> {
        assert_eq!(u64::from(self.size), dl.pointer_size.bytes());
        Ok(Self {
            bytes: u128::from(f_int(u64::try_from(self.data()).unwrap())?).to_ne_bytes(),
            size: self.size,
        })
    }

    #[inline]
    pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
        let data = i.into();
        if truncate(data, size) == data {
            Some(Self { bytes: data.to_ne_bytes(), size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
        let i = i.into();
        // `into` performed sign extension, we have to truncate
        let truncated = truncate(i as u128, size);
        if sign_extend(truncated, size) as i128 == i {
            Some(Self { bytes: truncated.to_ne_bytes(), size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn assert_bits(self, target_size: Size) -> u128 {
        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
        assert_eq!(target_size.bytes(), u64::from(self.size));
        self.check_data();
        self.data()
    }

    #[inline]
    pub fn to_bits(self, target_size: Size) -> InterpResult<'static, u128> {
        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
        if target_size.bytes() != u64::from(self.size) {
            throw_ub!(ScalarSizeMismatch {
                target_size: target_size.bytes(),
                data_size: u64::from(self.size),
            });
        }
        self.check_data();
        Ok(self.data())
    }
}

macro_rules! from {
    ($($ty:ty),*) => {
        $(
            impl From<$ty> for ScalarInt {
                #[inline]
                fn from(u: $ty) -> Self {
                    Self {
                        bytes: u128::from(u).to_ne_bytes(),
                        size: std::mem::size_of::<$ty>() as u8,
                    }
                }
            }
        )*
    }
}

macro_rules! try_from {
    ($($ty:ty),*) => {
        $(
            impl TryFrom<ScalarInt> for $ty {
                type Error = InterpErrorInfo<'static>;
                #[inline]
                fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
                    int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())).map(|u| u.try_into().unwrap())
                }
            }
        )*
    }
}

from!(u8, u16, u32, u64, u128, bool);
try_from!(u8, u16, u32, u64, u128);

impl From<char> for ScalarInt {
    #[inline]
    fn from(c: char) -> Self {
        Self { bytes: (c as u128).to_ne_bytes(), size: std::mem::size_of::<char>() as u8 }
    }
}

impl TryFrom<ScalarInt> for char {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(std::mem::size_of::<char>()))
            .map(|u| char::from_u32(u.try_into().unwrap()).unwrap())
    }
}

impl From<Single> for ScalarInt {
    #[inline]
    fn from(f: Single) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { bytes: f.to_bits().to_ne_bytes(), size: 4 }
    }
}

impl TryFrom<ScalarInt> for Single {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(4)).map(Self::from_bits)
    }
}

impl From<Double> for ScalarInt {
    #[inline]
    fn from(f: Double) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { bytes: f.to_bits().to_ne_bytes(), size: 8 }
    }
}

impl TryFrom<ScalarInt> for Double {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(8)).map(Self::from_bits)
    }
}

impl fmt::Debug for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.size == 0 {
            self.check_data();
            write!(f, "<ZST>")
        } else {
            write!(f, "0x{:x}", self)
        }
    }
}

impl fmt::LowerHex for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.check_data();
        // Format as hex number wide enough to fit any value of the given `size`.
        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
        write!(f, "{:01$x}", self.data(), self.size as usize * 2)
    }
}
<commit_msg>Encode `ScalarInt::bytes` as `u128` instead of `[u8; 16]` to see if that caused the performance regression<commit_after>use crate::mir::interpret::{sign_extend, truncate, InterpErrorInfo, InterpResult};
use crate::throw_ub;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_macros::HashStable;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_target::abi::{Size, TargetDataLayout};
use std::convert::{TryFrom, TryInto};
use std::fmt;

#[derive(Copy, Clone)]
/// A type for representing any integer. Only used for printing.
pub struct ConstInt {
    /// The "untyped" variant of `ConstInt`.
    int: ScalarInt,
    /// Whether the value is of a signed integer type.
    signed: bool,
    /// Whether the value is a `usize` or `isize` type.
    is_ptr_sized_integral: bool,
}

impl ConstInt {
    pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
        Self { int, signed, is_ptr_sized_integral }
    }
}

impl std::fmt::Debug for ConstInt {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let Self { int, signed, is_ptr_sized_integral } = *self;
        let size = int.size().bytes();
        let raw = int.data();
        if signed {
            let bit_size = size * 8;
            let min = 1u128 << (bit_size - 1);
            let max = min - 1;
            if raw == min {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MIN"),
                    (1, _) => write!(fmt, "i8::MIN"),
                    (2, _) => write!(fmt, "i16::MIN"),
                    (4, _) => write!(fmt, "i32::MIN"),
                    (8, _) => write!(fmt, "i64::MIN"),
                    (16, _) => write!(fmt, "i128::MIN"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MAX"),
                    (1, _) => write!(fmt, "i8::MAX"),
                    (2, _) => write!(fmt, "i16::MAX"),
                    (4, _) => write!(fmt, "i32::MAX"),
                    (8, _) => write!(fmt, "i64::MAX"),
                    (16, _) => write!(fmt, "i128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as i8)?,
                    2 => write!(fmt, "{}", raw as i16)?,
                    4 => write!(fmt, "{}", raw as i32)?,
                    8 => write!(fmt, "{}", raw as i64)?,
                    16 => write!(fmt, "{}", raw as i128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_isize")?,
                        (1, _) => write!(fmt, "_i8")?,
                        (2, _) => write!(fmt, "_i16")?,
                        (4, _) => write!(fmt, "_i32")?,
                        (8, _) => write!(fmt, "_i64")?,
                        (16, _) => write!(fmt, "_i128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        } else {
            let max = truncate(u128::MAX, Size::from_bytes(size));
            if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "usize::MAX"),
                    (1, _) => write!(fmt, "u8::MAX"),
                    (2, _) => write!(fmt, "u16::MAX"),
                    (4, _) => write!(fmt, "u32::MAX"),
                    (8, _) => write!(fmt, "u64::MAX"),
                    (16, _) => write!(fmt, "u128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as u8)?,
                    2 => write!(fmt, "{}", raw as u16)?,
                    4 => write!(fmt, "{}", raw as u32)?,
                    8 => write!(fmt, "{}", raw as u64)?,
                    16 => write!(fmt, "{}", raw as u128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_usize")?,
                        (1, _) => write!(fmt, "_u8")?,
                        (2, _) => write!(fmt, "_u16")?,
                        (4, _) => write!(fmt, "_u32")?,
                        (8, _) => write!(fmt, "_u64")?,
                        (16, _) => write!(fmt, "_u128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        }
    }
}

// FIXME: reuse in `super::int::ConstInt` and `Scalar::Bits`
/// The raw bytes of a simple value.
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(HashStable)]
pub struct ScalarInt {
    /// The first `size` bytes of `data` are the value.
    /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
    ///
    /// This is an array in order to allow this type to be optimally embedded in enums
    /// (like Scalar).
    bytes: [u8; 16],
    size: u8,
}

impl<S: Encoder> Encodable<S> for ScalarInt {
    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_u128(self.data())?;
        s.emit_u8(self.size)
    }
}

impl<D: Decoder> Decodable<D> for ScalarInt {
    fn decode(d: &mut D) -> Result<ScalarInt, D::Error> {
        Ok(ScalarInt { bytes: d.read_u128()?.to_ne_bytes(), size: d.read_u8()? })
    }
}

impl ScalarInt {
    pub const TRUE: ScalarInt = ScalarInt { bytes: 1_u128.to_ne_bytes(), size: 1 };

    pub const FALSE: ScalarInt = ScalarInt { bytes: 0_u128.to_ne_bytes(), size: 1 };

    pub const ZST: ScalarInt = ScalarInt { bytes: 0_u128.to_ne_bytes(), size: 0 };

    fn data(self) -> u128 {
        u128::from_ne_bytes(self.bytes)
    }

    #[inline]
    pub fn size(self) -> Size {
        Size::from_bytes(self.size)
    }

    /// Make sure the `data` fits in `size`.
    /// This is guaranteed by all constructors here, but since the enum variants are public,
    /// it could still be violated (even though no code outside this file should
    /// construct `Scalar`s).
    #[inline(always)]
    fn check_data(self) {
        debug_assert_eq!(
            truncate(self.data(), self.size()),
            self.data(),
            "Scalar value {:#x} exceeds size of {} bytes",
            self.data(),
            self.size
        );
    }

    #[inline]
    pub fn zst() -> Self {
        Self::null(Size::ZERO)
    }

    #[inline]
    pub fn null(size: Size) -> Self {
        Self { bytes: [0; 16], size: size.bytes() as u8 }
    }

    pub(crate) fn ptr_sized_op<'tcx>(
        self,
        dl: &TargetDataLayout,
        f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>,
    ) -> InterpResult<'tcx, Self> {
        assert_eq!(u64::from(self.size), dl.pointer_size.bytes());
        Ok(Self {
            bytes: u128::from(f_int(u64::try_from(self.data()).unwrap())?).to_ne_bytes(),
            size: self.size,
        })
    }

    #[inline]
    pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
        let data = i.into();
        if truncate(data, size) == data {
            Some(Self { bytes: data.to_ne_bytes(), size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
        let i = i.into();
        // `into` performed sign extension, we have to truncate
        let truncated = truncate(i as u128, size);
        if sign_extend(truncated, size) as i128 == i {
            Some(Self { bytes: truncated.to_ne_bytes(), size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn assert_bits(self, target_size: Size) -> u128 {
        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
        assert_eq!(target_size.bytes(), u64::from(self.size));
        self.check_data();
        self.data()
    }

    #[inline]
    pub fn to_bits(self, target_size: Size) -> InterpResult<'static, u128> {
        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
        if target_size.bytes() != u64::from(self.size) {
            throw_ub!(ScalarSizeMismatch {
                target_size: target_size.bytes(),
                data_size: u64::from(self.size),
            });
        }
        self.check_data();
        Ok(self.data())
    }
}

macro_rules! from {
    ($($ty:ty),*) => {
        $(
            impl From<$ty> for ScalarInt {
                #[inline]
                fn from(u: $ty) -> Self {
                    Self {
                        bytes: u128::from(u).to_ne_bytes(),
                        size: std::mem::size_of::<$ty>() as u8,
                    }
                }
            }
        )*
    }
}

macro_rules! try_from {
    ($($ty:ty),*) => {
        $(
            impl TryFrom<ScalarInt> for $ty {
                type Error = InterpErrorInfo<'static>;
                #[inline]
                fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
                    int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())).map(|u| u.try_into().unwrap())
                }
            }
        )*
    }
}

from!(u8, u16, u32, u64, u128, bool);
try_from!(u8, u16, u32, u64, u128);

impl From<char> for ScalarInt {
    #[inline]
    fn from(c: char) -> Self {
        Self { bytes: (c as u128).to_ne_bytes(), size: std::mem::size_of::<char>() as u8 }
    }
}

impl TryFrom<ScalarInt> for char {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(std::mem::size_of::<char>()))
            .map(|u| char::from_u32(u.try_into().unwrap()).unwrap())
    }
}

impl From<Single> for ScalarInt {
    #[inline]
    fn from(f: Single) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { bytes: f.to_bits().to_ne_bytes(), size: 4 }
    }
}

impl TryFrom<ScalarInt> for Single {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(4)).map(Self::from_bits)
    }
}

impl From<Double> for ScalarInt {
    #[inline]
    fn from(f: Double) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { bytes: f.to_bits().to_ne_bytes(), size: 8 }
    }
}

impl TryFrom<ScalarInt> for Double {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(8)).map(Self::from_bits)
    }
}

impl fmt::Debug for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.size == 0 {
            self.check_data();
            write!(f, "<ZST>")
        } else {
            write!(f, "0x{:x}", self)
        }
    }
}

impl fmt::LowerHex for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.check_data();
        // Format as hex number wide enough to fit any value of the given `size`.
        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
        write!(f, "{:01$x}", self.data(), self.size as usize * 2)
    }
}
<|endoftext|>


<commit_before>//! incremental BLOB I/O
use std::mem;
use std::ptr;

use super::ffi;
use {Error, Result, Connection, DatabaseName};

/// Handle to an open BLOB
pub struct Blob<'conn> {
    conn: &'conn Connection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

/// Enumeration of possible methods to seek within an BLOB.
pub enum SeekFrom {
    Start(i32),
    End(i32),
    Current(i32),
}

impl Connection {
    /// Open a handle to the BLOB located in `row`, `column`, `table` in database `db`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string or if the
    /// underlying SQLite BLOB open call fails.
    pub fn blob_open<'a>(&'a self,
                         db: DatabaseName,
                         table: &str,
                         column: &str,
                         row: i64,
                         read_only: bool)
                         -> Result<Blob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = try!(db.to_cstring());
        let table = try!(super::str_to_cstring(table));
        let column = try!(super::str_to_cstring(column));
        let rc = unsafe {
            ffi::sqlite3_blob_open(c.db(),
                                   db.as_ptr(),
                                   table.as_ptr(),
                                   column.as_ptr(),
                                   row,
                                   if read_only {
                                       0
                                   } else {
                                       1
                                   },
                                   &mut blob)
        };
        c.decode_result(rc).map(|_| {
            Blob {
                conn: self,
                blob: blob,
                pos: 0,
            }
        })
    }
}

impl<'conn> Blob<'conn> {
    /// Move a BLOB handle to a new row
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB
    pub fn size(&self) -> i32 {
        unsafe { ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Read data from a BLOB incrementally
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if the underlying SQLite read call fails.
    pub fn read(&mut self, buf: &mut [u8]) -> Result<i32> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(Error {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string(),
            });
        }
        let mut n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            n = size - self.pos;
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n
        })
    }

    /// Write data into a BLOB incrementally
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if `buf` length + offset > BLOB size
    /// or if the underlying SQLite write call fails.
    pub fn write(&mut self, buf: &[u8]) -> Result<i32> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(Error {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string(),
            });
        }
        let n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            return Err(Error {
                code: ffi::SQLITE_MISUSE,
                message: format!("pos = {} + n = {} > size = {}", self.pos, n, size),
            });
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n
        })
    }

    /// Seek to an offset, in bytes, in BLOB.
    pub fn seek(&mut self, pos: SeekFrom) {
        self.pos = match pos {
            SeekFrom::Start(offset) => offset,
            SeekFrom::Current(offset) => self.pos + offset,
            SeekFrom::End(offset) => self.size() + offset,
        };
    }

    /// Close a BLOB handle
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

    fn close_(&mut self) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

#[allow(unused_must_use)]
impl<'conn> Drop for Blob<'conn> {
    fn drop(&mut self) {
        self.close_();
    }
}

#[cfg(test)]
mod test {
    use {Connection, DatabaseName};

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_blob() {
        let db = Connection::open_in_memory().unwrap();
        let sql = "BEGIN;
                CREATE TABLE test (content BLOB);
                INSERT INTO test VALUES (ZEROBLOB(10));
                END;";
        db.execute_batch(sql).unwrap();
        let rowid = db.last_insert_rowid();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        blob.write(b"Clob").unwrap();
        let err = blob.write(b"5678901");
        // writeln!(io::stderr(), "{:?}", err);
        assert!(err.is_err());

        assert!(blob.reopen(rowid).is_ok());
        assert!(blob.close().is_ok());

        blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true).unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        assert!(blob.reopen(rowid).is_ok());
        blob.seek(super::SeekFrom::Start(0));
    }
}
<commit_msg>Move Blob's `read` to an impl of std::io::Read.<commit_after>//! incremental BLOB I/O
use std::io;
use std::mem;
use std::ptr;

use super::ffi;
use {Error, Result, Connection, DatabaseName};

/// Handle to an open BLOB
pub struct Blob<'conn> {
    conn: &'conn Connection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

/// Enumeration of possible methods to seek within an BLOB.
pub enum SeekFrom {
    Start(i32),
    End(i32),
    Current(i32),
}

impl Connection {
    /// Open a handle to the BLOB located in `row`, `column`, `table` in database `db`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string or if the
    /// underlying SQLite BLOB open call fails.
    pub fn blob_open<'a>(&'a self,
                         db: DatabaseName,
                         table: &str,
                         column: &str,
                         row: i64,
                         read_only: bool)
                         -> Result<Blob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = try!(db.to_cstring());
        let table = try!(super::str_to_cstring(table));
        let column = try!(super::str_to_cstring(column));
        let rc = unsafe {
            ffi::sqlite3_blob_open(c.db(),
                                   db.as_ptr(),
                                   table.as_ptr(),
                                   column.as_ptr(),
                                   row,
                                   if read_only {
                                       0
                                   } else {
                                       1
                                   },
                                   &mut blob)
        };
        c.decode_result(rc).map(|_| {
            Blob {
                conn: self,
                blob: blob,
                pos: 0,
            }
        })
    }
}

impl<'conn> Blob<'conn> {
    /// Move a BLOB handle to a new row
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB
    pub fn size(&self) -> i32 {
        unsafe { ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Write data into a BLOB incrementally
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if `buf` length + offset > BLOB size
    /// or if the underlying SQLite write call fails.
    pub fn write(&mut self, buf: &[u8]) -> Result<i32> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(Error {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string(),
            });
        }
        let n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            return Err(Error {
                code: ffi::SQLITE_MISUSE,
                message: format!("pos = {} + n = {} > size = {}", self.pos, n, size),
            });
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n
        })
    }

    /// Seek to an offset, in bytes, in BLOB.
    pub fn seek(&mut self, pos: SeekFrom) {
        self.pos = match pos {
            SeekFrom::Start(offset) => offset,
            SeekFrom::Current(offset) => self.pos + offset,
            SeekFrom::End(offset) => self.size() + offset,
        };
    }

    /// Close a BLOB handle
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

    fn close_(&mut self) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

impl<'conn> io::Read for Blob<'conn> {
    /// Read data from a BLOB incrementally
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if the underlying SQLite read call fails.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(io::Error::new(io::ErrorKind::InvalidInput, Error {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string(),
            }));
        }
        let mut n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            n = size - self.pos;
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n as usize
        }).map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

#[allow(unused_must_use)]
impl<'conn> Drop for Blob<'conn> {
    fn drop(&mut self) {
        self.close_();
    }
}

#[cfg(test)]
mod test {
    use std::io::Read;
    use {Connection, DatabaseName};

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_blob() {
        let db = Connection::open_in_memory().unwrap();
        let sql = "BEGIN;
                CREATE TABLE test (content BLOB);
                INSERT INTO test VALUES (ZEROBLOB(10));
                END;";
        db.execute_batch(sql).unwrap();
        let rowid = db.last_insert_rowid();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        blob.write(b"Clob").unwrap();
        let err = blob.write(b"5678901");
        // writeln!(io::stderr(), "{:?}", err);
        assert!(err.is_err());

        assert!(blob.reopen(rowid).is_ok());
        assert!(blob.close().is_ok());

        blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true).unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        assert!(blob.reopen(rowid).is_ok());
        blob.seek(super::SeekFrom::Start(0));
    }
}
<|endoftext|>


<commit_before>extern crate snowchains;

extern crate env_logger;
extern crate failure;
extern crate structopt;

use snowchains::app::{App, Opt};
use snowchains::path::AbsPathBuf;
use snowchains::service::Credentials;
use snowchains::terminal::{Term, TermImpl, WriteAnsi as _WriteAnsi, WriteSpaces as _WriteSpaces};

use failure::Fail;
use structopt::StructOpt as _StructOpt;

use std::io::{self, Write as _Write};
use std::process;

fn main() -> io::Result<()> {
    env_logger::init();
    let opt = Opt::from_args();
    let (stdin, stdout, stderr) = (io::stdin(), io::stdout(), io::stderr());
    let mut term = TermImpl::new(&stdin, &stdout, &stderr);
    if let Err(err) = run(opt, &mut term) {
        term.stdout().flush()?;
        let mut stderr = term.stderr();
        writeln!(stderr)?;
        for (i, cause) in Fail::iter_chain(&err).enumerate() {
            let head = if i == 0 && err.cause().is_none() {
                "error: "
            } else if i == 0 {
                "    error: "
            } else {
                "caused by: "
            };
            stderr.with_reset(|o| o.fg(9)?.bold()?.write_str(head))?;
            for (i, line) in cause.to_string().lines().enumerate() {
                if i > 0 {
                    stderr.write_spaces(head.len())?;
                }
                writeln!(stderr, "{}", line)?;
            }
        }
        if let Some(backtrace) = err.backtrace() {
            writeln!(stderr, "{:?}", backtrace)?;
        }
        stderr.flush()?;
        process::exit(1)
    } else {
        Ok(())
    }
}

fn run(opt: Opt, term: impl Term) -> snowchains::Result<()> {
    let working_dir = AbsPathBuf::cwd()?;
    App {
        working_dir,
        cookies_on_init: "~/.local/share/snowchains/$service".into(),
        credentials: Credentials::default(),
        term,
    }.run(opt)
}
<commit_msg>Change colors of "error:" and "caused by"<commit_after>extern crate snowchains;

extern crate env_logger;
extern crate failure;
extern crate structopt;

use snowchains::app::{App, Opt};
use snowchains::path::AbsPathBuf;
use snowchains::service::Credentials;
use snowchains::terminal::{Term, TermImpl, WriteAnsi as _WriteAnsi, WriteSpaces as _WriteSpaces};

use failure::Fail;
use structopt::StructOpt as _StructOpt;

use std::io::{self, Write as _Write};
use std::process;

fn main() -> io::Result<()> {
    env_logger::init();
    let opt = Opt::from_args();
    let (stdin, stdout, stderr) = (io::stdin(), io::stdout(), io::stderr());
    let mut term = TermImpl::new(&stdin, &stdout, &stderr);
    if let Err(err) = run(opt, &mut term) {
        term.stdout().flush()?;
        let mut stderr = term.stderr();
        writeln!(stderr)?;
        for (i, cause) in Fail::iter_chain(&err).enumerate() {
            let head = if i == 0 && err.cause().is_none() {
                "error: "
            } else if i == 0 {
                "    error: "
            } else {
                "caused by: "
            };
            stderr.with_reset(|o| o.fg(1)?.bold()?.write_str(head))?;
            for (i, line) in cause.to_string().lines().enumerate() {
                if i > 0 {
                    stderr.write_spaces(head.len())?;
                }
                writeln!(stderr, "{}", line)?;
            }
        }
        if let Some(backtrace) = err.backtrace() {
            writeln!(stderr, "{:?}", backtrace)?;
        }
        stderr.flush()?;
        process::exit(1)
    } else {
        Ok(())
    }
}

fn run(opt: Opt, term: impl Term) -> snowchains::Result<()> {
    let working_dir = AbsPathBuf::cwd()?;
    App {
        working_dir,
        cookies_on_init: "~/.local/share/snowchains/$service".into(),
        credentials: Credentials::default(),
        term,
    }.run(opt)
}
<|endoftext|>


<commit_before><commit_msg>Clean-up main function<commit_after><|endoftext|>


<commit_before><commit_msg>Add a joke<commit_after><|endoftext|>


<commit_before>#[macro_use] extern crate log;

extern crate ansi_term;
use ansi_term::Colour::{Black, Red, Green, Yellow, Blue, Purple, Cyan, Fixed};
use ansi_term::Style::Plain;

use std::num::{Int, FromPrimitive};
use std::os;
use std::io::File;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::iter::{range_step, count};

fn vec_to_string(input: &Vec<char>) -> String {
    input.iter().map(|&c| { c }).collect()
}

// Index source
struct InputSource {
    haystack: Vec<char>,
    indexed_haystack: HashMap<char, Vec<usize>>,
}

fn index_chars(input: &Vec<char>) -> HashMap<char, Vec<usize>> {
    let mut indexed_haystack = HashMap::new();
    for (idx, &c) in input.iter().enumerate() {
        match indexed_haystack.entry(c) {
            Vacant(entry) => { entry.insert(vec![idx]); },
            Occupied(mut entry) => { (*entry.get_mut()).push(idx); }
        }
    }

    indexed_haystack
}

impl InputSource {
    fn new(haystack: Vec<char>) -> InputSource {
        let indexed_haystack = index_chars(&haystack);

        InputSource {
            haystack: haystack,
            indexed_haystack: indexed_haystack,
        }
    }

    fn search_for_anywhere<'a>(&'a self, needle: &'a Vec<char>) -> Option<EDS> {
        EDS::new(self, needle)
    }

    fn search_for<'a>(&'a self, needle: &'a Vec<char>, start_options: Vec<usize>, step_options: Vec<i64>) -> Option<EDS> {
        EDS::new(self, needle)
    }
}

// This is a struct for doing the searching
struct EDS<'a, 'b> {
    source: &'a InputSource,

    // String to search for
    needle: &'b Vec<char>,

    first_poses: Vec<usize>,
    second_poses: Vec<usize>,

    // keep track of state between runs
    first_poses_idx: usize,
    second_poses_idx: usize,

}

impl<'a, 'b> Iterator for EDS<'a, 'b> {
    // (start, offset)
    type Item = (usize, i64);

    // This actually does the searching
    fn next(&mut self) -> Option<(usize, i64)> {
        debug!("Start of next call");
        let len_first_poses = self.first_poses.len();
        let len_second_poses = self.second_poses.len();

        if self.first_poses_idx == len_first_poses {
            debug!("Reached end, finishing");
            // reached the end
            return None;
        }

        let len_needle = self.needle.len();
        let len_haystack = self.source.haystack.len();
        let mut have_done_one_loop = false;
        let first_run = (self.first_poses_idx == 0 && self.second_poses_idx == 0);

        loop {
            debug!("Start of loop");
            // Starts off at 0/0, and we don't want to increment it the first time
            if ! (self.first_poses_idx == 0 && self.second_poses_idx == 0 && !have_done_one_loop) {
                debug!("Incrementing counters");
                if self.second_poses_idx == len_second_poses - 1 {
                    self.second_poses_idx = 0;
                    self.first_poses_idx += 1;
                } else{
                    self.second_poses_idx += 1;
                }
            }
            have_done_one_loop = true;
            if self.first_poses_idx == len_first_poses {
                debug!("Reached end, finishing");
                // reached the end
                return None;
            }

            debug!("first_poses_idx {} second_poses_idx {}", self.first_poses_idx, self.second_poses_idx);
            let first_pos = self.first_poses[self.first_poses_idx];
            let second_pos = self.second_poses[self.second_poses_idx];
            debug!("first_pos {} second_pos {}", first_pos, second_pos);

            let step: i64 = (second_pos as i64) - (first_pos as i64);
            if step == 1 {
                continue;
            }
            let positions: Vec<i64> = std::iter::count(first_pos as i64, step as i64).take(len_needle).collect();
            //let positions: Vec<i64> = range_step(first_pos as i64, step*len_needle, step).collect();
            debug!("Start {} step {}", first_pos, step);
            if positions.iter().any(|&x| { x<0 }) {
                // TODO there's probably a better maths way to do this
                continue;
            }
            let positions: Vec<usize> = positions.iter().map(|&x| { FromPrimitive::from_i64(x).unwrap() }).collect();
            debug!("positions {:?}", positions);
            if positions.len() == 0 {
                // WTF
                continue;
            }

            if positions[positions.len()-1] > len_haystack - 1 {
                debug!("Past end");
                continue;
            }
            if positions.iter().map(|&c| { &self.source.haystack[c] }).zip(self.needle.iter()).all(|(&a, &b)| { a == b }) {
                //println!("Found starting at {} with step of {}", first_pos, step);
                return Some((first_pos, step));
            }
        }
        None
    }
}

impl<'a, 'b> EDS<'a, 'b> {
    fn new(source: &'a InputSource, needle: &'b Vec<char>) -> Option<EDS<'a, 'b>> {
        if needle.len() < 3 {
            return None;
        }
        let first_poses;
        match source.indexed_haystack.get(&needle[0]) {
            None => { return None ; }
            Some(ref entries) => {
                first_poses = (**entries).clone();
            }
        }

        let second_poses;
        match source.indexed_haystack.get(&needle[1]) {
            None => { return None ; }
            Some(ref entries) => {
                second_poses = (**entries).clone();
            }
        }

        let result = EDS {
            needle: needle, source: source,
            first_poses: first_poses, second_poses: second_poses,
            first_poses_idx: 0, second_poses_idx: 0,
        };

        return Some(result);

    }
}

fn print_results(source: &InputSource, start: usize, step: i64, len: usize) {
    let total_rows = (len + 2) as i64;
    let width: usize = 31; // 15 + 1 + 15
    let start_i = start as i64;

    for row_num in range(0, total_rows) {
        for idx in range(0, width as i64) {
            let source_idx = (row_num-1)*step + start_i - 15 + idx;
            let this_char = if source_idx < 0 { ' ' } else { source.haystack[source_idx as usize] };
            if idx == 15 && row_num != 0 && row_num != total_rows -1 {
                print!("{}", Red.paint(this_char.to_string().as_slice()));
            } else {
                print!("{}", Plain.paint(this_char.to_string().as_slice()));
            }
        }
        print!("\n");

    }

}

fn only_alphanumeric(input: String) -> Vec<char> {
    input.chars().filter(|c| { c.is_alphabetic() }).map(|c| { c.to_lowercase() }).collect()
}

fn main() {
    let file_to_search = &os::args()[1];
    println!("Reading in {}", file_to_search);
    let haystack: Vec<char> = only_alphanumeric(File::open(&Path::new(file_to_search)).read_to_string().unwrap());
    let source = InputSource::new(haystack);

    let needle = (&os::args()[2]).to_string();
    println!("Looking for {}", needle);
    let needle = only_alphanumeric(needle);
    let len_needle = needle.len();

    let has_second_arg = os::args().len() == 4;
    let needle2;
    let len_needle2;
    if has_second_arg {
        needle2 = only_alphanumeric((&os::args()[3]).to_string());
        let needle2_string: String = vec_to_string(&needle2);
        println!("Looking also for {}", needle2_string);
        len_needle2 = needle2.len();
    } else {
        needle2 = vec![];
    }

    match source.search_for_anywhere(&needle) {
        None => {
            println!("Cannot look for this string");
        }
        Some(eds_searcher) => {
            for (start, step) in eds_searcher.take(10) {
                println!("Found starting at {} with step of {}", start, step);
                print_results(&source, start, step, len_needle);
                if has_second_arg {
                    // now try to find the second needle2
                    match source.search_for_anywhere(&needle2) {
                        None => {
                            println!("Cannot look for {:?}", vec_to_string(&needle2));
                        }
                        Some(needle2_searcher) => {
                            for (start2, step2) in needle2_searcher.take(1) {
                                println!("Found {:?} starting at {} with step of {}", vec_to_string(&needle2), start2, step2);

                            }
                        }
                    }
                }
            }
        }
    }

}
<commit_msg>not needed<commit_after>#[macro_use] extern crate log;

extern crate ansi_term;
use ansi_term::Colour::{Black, Red, Green, Yellow, Blue, Purple, Cyan, Fixed};
use ansi_term::Style::Plain;

use std::num::{FromPrimitive};
use std::os;
use std::io::File;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::iter::{range_step, count};

fn vec_to_string(input: &Vec<char>) -> String {
    input.iter().map(|&c| { c }).collect()
}

// Index source
struct InputSource {
    haystack: Vec<char>,
    indexed_haystack: HashMap<char, Vec<usize>>,
}

fn index_chars(input: &Vec<char>) -> HashMap<char, Vec<usize>> {
    let mut indexed_haystack = HashMap::new();
    for (idx, &c) in input.iter().enumerate() {
        match indexed_haystack.entry(c) {
            Vacant(entry) => { entry.insert(vec![idx]); },
            Occupied(mut entry) => { (*entry.get_mut()).push(idx); }
        }
    }

    indexed_haystack
}

impl InputSource {
    fn new(haystack: Vec<char>) -> InputSource {
        let indexed_haystack = index_chars(&haystack);

        InputSource {
            haystack: haystack,
            indexed_haystack: indexed_haystack,
        }
    }

    fn search_for_anywhere<'a>(&'a self, needle: &'a Vec<char>) -> Option<EDS> {
        EDS::new(self, needle)
    }

    fn search_for<'a>(&'a self, needle: &'a Vec<char>, start_options: Vec<usize>, step_options: Vec<i64>) -> Option<EDS> {
        EDS::new(self, needle)
    }
}

// This is a struct for doing the searching
struct EDS<'a, 'b> {
    source: &'a InputSource,

    // String to search for
    needle: &'b Vec<char>,

    first_poses: Vec<usize>,
    second_poses: Vec<usize>,

    // keep track of state between runs
    first_poses_idx: usize,
    second_poses_idx: usize,

}

impl<'a, 'b> Iterator for EDS<'a, 'b> {
    // (start, offset)
    type Item = (usize, i64);

    // This actually does the searching
    fn next(&mut self) -> Option<(usize, i64)> {
        debug!("Start of next call");
        let len_first_poses = self.first_poses.len();
        let len_second_poses = self.second_poses.len();

        if self.first_poses_idx == len_first_poses {
            debug!("Reached end, finishing");
            // reached the end
            return None;
        }

        let len_needle = self.needle.len();
        let len_haystack = self.source.haystack.len();
        let mut have_done_one_loop = false;
        let first_run = (self.first_poses_idx == 0 && self.second_poses_idx == 0);

        loop {
            debug!("Start of loop");
            // Starts off at 0/0, and we don't want to increment it the first time
            if ! (self.first_poses_idx == 0 && self.second_poses_idx == 0 && !have_done_one_loop) {
                debug!("Incrementing counters");
                if self.second_poses_idx == len_second_poses - 1 {
                    self.second_poses_idx = 0;
                    self.first_poses_idx += 1;
                } else{
                    self.second_poses_idx += 1;
                }
            }
            have_done_one_loop = true;
            if self.first_poses_idx == len_first_poses {
                debug!("Reached end, finishing");
                // reached the end
                return None;
            }

            debug!("first_poses_idx {} second_poses_idx {}", self.first_poses_idx, self.second_poses_idx);
            let first_pos = self.first_poses[self.first_poses_idx];
            let second_pos = self.second_poses[self.second_poses_idx];
            debug!("first_pos {} second_pos {}", first_pos, second_pos);

            let step: i64 = (second_pos as i64) - (first_pos as i64);
            if step == 1 {
                continue;
            }
            let positions: Vec<i64> = std::iter::count(first_pos as i64, step as i64).take(len_needle).collect();
            //let positions: Vec<i64> = range_step(first_pos as i64, step*len_needle, step).collect();
            debug!("Start {} step {}", first_pos, step);
            if positions.iter().any(|&x| { x<0 }) {
                // TODO there's probably a better maths way to do this
                continue;
            }
            let positions: Vec<usize> = positions.iter().map(|&x| { FromPrimitive::from_i64(x).unwrap() }).collect();
            debug!("positions {:?}", positions);
            if positions.len() == 0 {
                // WTF
                continue;
            }

            if positions[positions.len()-1] > len_haystack - 1 {
                debug!("Past end");
                continue;
            }
            if positions.iter().map(|&c| { &self.source.haystack[c] }).zip(self.needle.iter()).all(|(&a, &b)| { a == b }) {
                //println!("Found starting at {} with step of {}", first_pos, step);
                return Some((first_pos, step));
            }
        }
        None
    }
}

impl<'a, 'b> EDS<'a, 'b> {
    fn new(source: &'a InputSource, needle: &'b Vec<char>) -> Option<EDS<'a, 'b>> {
        if needle.len() < 3 {
            return None;
        }
        let first_poses;
        match source.indexed_haystack.get(&needle[0]) {
            None => { return None ; }
            Some(ref entries) => {
                first_poses = (**entries).clone();
            }
        }

        let second_poses;
        match source.indexed_haystack.get(&needle[1]) {
            None => { return None ; }
            Some(ref entries) => {
                second_poses = (**entries).clone();
            }
        }

        let result = EDS {
            needle: needle, source: source,
            first_poses: first_poses, second_poses: second_poses,
            first_poses_idx: 0, second_poses_idx: 0,
        };

        return Some(result);

    }
}

fn print_results(source: &InputSource, start: usize, step: i64, len: usize) {
    let total_rows = (len + 2) as i64;
    let width: usize = 31; // 15 + 1 + 15
    let start_i = start as i64;

    for row_num in range(0, total_rows) {
        for idx in range(0, width as i64) {
            let source_idx = (row_num-1)*step + start_i - 15 + idx;
            let this_char = if source_idx < 0 { ' ' } else { source.haystack[source_idx as usize] };
            if idx == 15 && row_num != 0 && row_num != total_rows -1 {
                print!("{}", Red.paint(this_char.to_string().as_slice()));
            } else {
                print!("{}", Plain.paint(this_char.to_string().as_slice()));
            }
        }
        print!("\n");

    }

}

fn only_alphanumeric(input: String) -> Vec<char> {
    input.chars().filter(|c| { c.is_alphabetic() }).map(|c| { c.to_lowercase() }).collect()
}

fn main() {
    let file_to_search = &os::args()[1];
    println!("Reading in {}", file_to_search);
    let haystack: Vec<char> = only_alphanumeric(File::open(&Path::new(file_to_search)).read_to_string().unwrap());
    let source = InputSource::new(haystack);

    let needle = (&os::args()[2]).to_string();
    println!("Looking for {}", needle);
    let needle = only_alphanumeric(needle);
    let len_needle = needle.len();

    let has_second_arg = os::args().len() == 4;
    let needle2;
    let len_needle2;
    if has_second_arg {
        needle2 = only_alphanumeric((&os::args()[3]).to_string());
        let needle2_string: String = vec_to_string(&needle2);
        println!("Looking also for {}", needle2_string);
        len_needle2 = needle2.len();
    } else {
        needle2 = vec![];
    }

    match source.search_for_anywhere(&needle) {
        None => {
            println!("Cannot look for this string");
        }
        Some(eds_searcher) => {
            for (start, step) in eds_searcher.take(10) {
                println!("Found starting at {} with step of {}", start, step);
                print_results(&source, start, step, len_needle);
                if has_second_arg {
                    // now try to find the second needle2
                    match source.search_for_anywhere(&needle2) {
                        None => {
                            println!("Cannot look for {:?}", vec_to_string(&needle2));
                        }
                        Some(needle2_searcher) => {
                            for (start2, step2) in needle2_searcher.take(1) {
                                println!("Found {:?} starting at {} with step of {}", vec_to_string(&needle2), start2, step2);

                            }
                        }
                    }
                }
            }
        }
    }

}
<|endoftext|>


<commit_before>extern crate bullet;

use std::{env, process, mem};
use std::default::Default;

const USAGE: &'static str = "
Usage: bullet [options] <config>

Options:
    -h, --help   Display this message.
";

#[derive(Debug, Default)]
struct Arguments {
    config: String,
}

fn main() {
    let _args = setup();
    bullet::say("Hello!");
}

fn setup() -> Arguments {
    let mut arguments = Arguments::new();
    let mut name: Option<&str> = None;
    for argument in env::args() {
        match &argument[..] {
            "-h" | "--help" => usage(),
            "-c" | "--config" => name = Some("config"),
            _ => {
                if name.is_some() {
                    arguments.set(mem::replace(&mut name, None).unwrap(), argument);
                } else {
                    usage();
                }
            },
        }
    }
    arguments
}

fn usage() -> ! {
    fail(USAGE.trim());
}

fn fail(message: &str) -> ! {
    println!("{}", message);
    process::exit(1);
}

impl Arguments {
    #[inline]
    fn new() -> Arguments {
        Default::default()
    }

    fn set(&mut self, name: &str, value: String) {
        match name {
            "config" => self.config = value,
            _ => usage(),
        }
    }
}
<commit_msg>Refine the argument parsing<commit_after>extern crate bullet;

use std::{env, process, mem};
use std::default::Default;

const USAGE: &'static str = "
Usage: bullet [options]

Options:
    -c CONFIG, --config CONFIG         Configuration file in XML (required).
    -h, --help                         Display this message.
";

#[derive(Debug, Default)]
struct Arguments {
    config: String,
}

fn main() {
    let _args = setup();
    bullet::say("Hello!");
}

fn setup() -> Arguments {
    let mut arguments = Arguments::new();
    let mut name: Option<&str> = None;
    for argument in env::args().skip(1) {
        match &argument[..] {
            "-h" | "--help" => usage(),
            "-c" | "--config" => name = Some("config"),
            _ => match name {
                Some(_) => arguments.set(mem::replace(&mut name, None).unwrap(), argument),
                None => usage(),
            },
        }
    }
    if name.is_some() {
        usage();
    }
    arguments
}

fn usage() -> ! {
    fail(USAGE.trim());
}

fn fail(message: &str) -> ! {
    println!("{}", message);
    process::exit(1);
}

impl Arguments {
    #[inline]
    fn new() -> Arguments {
        Default::default()
    }

    fn set(&mut self, name: &str, value: String) {
        match name {
            "config" => self.config = value,
            _ => usage(),
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>comment outed debug code..<commit_after><|endoftext|>


<commit_before>//! Values taken from RFC 2616

/// OCTET: any 8-bit sequence of data (typechecking ensures this to be true)
#[inline]
pub fn is_octet(_: u8) -> bool { true }

/// CHAR: any US-ASCII character (octets 0 - 127)
#[inline]
pub fn is_char(octet: u8) -> bool { octet < 128 }

/// UPALPHA: any US-ASCII uppercase letter "A".."Z">
#[inline]
pub fn is_upalpha(octet: u8) -> bool { octet >= 65 && octet <= 90 }

/// LOALPHA: any US-ASCII lowercase letter "a".."z">
#[inline]
pub fn is_loalpha(octet: u8) -> bool { octet >= 97 && octet <= 122 }

/// ALPHA: UPALPHA | LOALPHA
#[inline]
pub fn is_alpha(octet: u8) -> bool { is_upalpha(octet) || is_loalpha(octet) }

/// DIGIT: any US-ASCII digit "0".."9"
#[inline]
pub fn is_digit(octet: u8) -> bool { octet >= 48 && octet <= 57 }

/// CTL: any US-ASCII control character (octets 0 - 31) and DEL (127)
#[inline]
pub fn is_ctl(octet: u8) -> bool { octet < 32 || octet == 127 }

/// CR: US-ASCII CR, carriage return (13)
pub static CR: u8 = 13;

/// LF: US-ASCII LF, linefeed (10)
pub static LF: u8 = 10;

/// SP: US-ASCII SP, space (32)
pub static SP: u8 = 32;

/// HT: US-ASCII HT, horizontal-tab (9)
pub static HT: u8 = 9;

/// US-ASCII colon (58)
pub static COLON: u8 = 58;

/// <">: US-ASCII double-quote mark (34)
pub static DOUBLE_QUOTE: u8 = 34;

/// TODO: check naming in RFC 2616. US-ASCII backslash (92)
pub static BACKSLASH: u8 = '\\' as u8;

#[inline]
pub fn is_sp_or_ht(octet: u8) -> bool { octet == SP || octet == HT }

// CRLF: CR LF
//static CRLF: [u8] = [CR, LF];

// LWS: [CRLF] 1*( SP | HT )
/*#[inline]
fn is_lws(octets: &[u8]) -> bool {
    let mut has_crlf = false;
    let mut iter = octets.iter();
    if len(octets) == 0 {
        return false;
    }
    if len(octets) > 2 && octets[0] == CR && octets[1] == LF {
        iter = iter.next().next();
    }
    iter.all(|&octet| octet == SP || octet == HT)
}
*/

/*
   The TEXT rule is only used for descriptive field contents and values
   that are not intended to be interpreted by the message parser. Words
   of *TEXT MAY contain characters from character sets other than ISO-
   8859-1 [22] only when encoded according to the rules of RFC 2047
   [14].

       TEXT           = <any OCTET except CTLs,
                        but including LWS>

   A CRLF is allowed in the definition of TEXT only as part of a header
   field continuation. It is expected that the folding LWS will be
   replaced with a single SP before interpretation of the TEXT value.
*/

/// HEX: "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" | DIGIT
#[inline]
pub fn is_hex(octet: u8) -> bool {
    (octet >= 65 && octet <= 70) || (octet >= 97 && octet <= 102) || is_digit(octet)
}

/// token          = 1*<any CHAR except CTLs or separators>
#[inline]
pub fn is_token_item(o: u8) -> bool {
    is_char(o) && !is_ctl(o) && !is_separator(o)
}

#[inline]
pub fn is_token(s: &str) -> bool {
    s.iter().all(|c| is_token_item(c as u8))
}

/// separators: "(" | ")" | "<" | ">" | "@" | "," | ";" | ":"
///           | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{"
///           | "}" | SP | HT
#[inline]
pub fn is_separator(o: u8) -> bool {
    o == 40 || o == 41 || o == 60 || o == 62 || o == 64 || o == 44 || o == 59 || o == 58 || o == 92
        || o == 34 || o == 47 || o == 91 || o == 93 || o == 63 || o == 61 || o == 123 ||
        o == 125 || o == SP || o == HT
}

/*
 * Comments can be included in some HTTP header fields by surrounding
 * the comment text with parentheses. Comments are only allowed in
 * fields containing "comment" as part of their field value definition.
 * In all other fields, parentheses are considered part of the field
 * value.
 *
 *     comment        = "(" *( ctext | quoted-pair | comment ) ")"
 *     ctext          = <any TEXT excluding "(" and ")">
 *
 * A string of text is parsed as a single word if it is quoted using
 * double-quote marks.
 *
 *     quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
 *     qdtext         = <any TEXT except <">>
 *
 * The backslash character ("\") MAY be used as a single-character
 * quoting mechanism only within quoted-string and comment constructs.
 *
 *     quoted-pair    = "\" CHAR
 */
//#[inline]
//fn is_quoted_pair(o: &[u8, ..2]) { o[0] == 92 }

// IANA is assigned as maintaining the registry for these things:
// see https://www.iana.org/assignments/http-parameters/http-parameters.xml

mod content_coding {
    /// Content-coding value tokens
    pub enum ValueToken {
        // An encoding format produced by the file compression program "gzip" (GNU zip) as described
        // in RFC 1952 [25]. This format is a Lempel-Ziv coding (LZ77) with a 32 bit CRC.
        Gzip,

        // The encoding format produced by the common UNIX file compression program "compress". This
        // format is an adaptive Lempel-Ziv-Welch coding (LZW).
        //
        // Use of program names for the identification of encoding formats is not desirable and is
        // discouraged for future encodings. Their use here is representative of historical
        // practice, not good design. For compatibility with previous implementations of HTTP,
        // applications SHOULD consider "x-gzip" and "x-compress" to be equivalent to "gzip" and
        // "compress" respectively.
        Compress,

        // The "zlib" format defined in RFC 1950 [31] in combination with the "deflate" compression
        // mechanism described in RFC 1951 [29].
        Deflate,

        // The default (identity) encoding; the use of no transformation whatsoever. This
        // content-coding is used only in the Accept- Encoding header, and SHOULD NOT be used in the
        // Content-Encoding header.
        Identity,

        // IANA has also assigned the following currently unsupported content codings:
        //
        // - "exi": W3C Efficient XML Interchange
        // - "pack200-gzip" (Network Transfer Format for Java Archives)
    }
    impl ToStr for ValueToken {
        fn to_str(&self) -> ~str {
            match *self {
                Gzip => ~"gzip",
                Compress => ~"compress",
                Deflate => ~"deflate",
                Identity => ~"identity",
            }
        }
    }
    impl FromStr for ValueToken {
        fn from_str(s: &str) -> Option<ValueToken> {
            use std::ascii::StrAsciiExt;
            match s.to_ascii_lower().as_slice() {
                "gzip" => Some(Gzip),
                "compress" => Some(Compress),
                "deflate" => Some(Deflate),
                "identity" => Some(Identity),
                _ => None,
            }
        }
    }
}

mod transfer_coding {
    /// Transfer-coding value tokens
    // Identity is in RFC 2616 but is withdrawn in RFC 2616 errata ID 408
    // http://www.rfc-editor.org/errata_search.php?rfc=2616&eid=408
    pub enum ValueToken {
        Chunked,   // RFC 2616, §3.6.1
        Gzip,      // See above
        Compress,  // See above
        Deflate,   // See above
    }
    impl ToStr for ValueToken {
        fn to_str(&self) -> ~str {
            match *self {
                Chunked => ~"chunked",
                Gzip => ~"gzip",
                Compress => ~"compress",
                Deflate => ~"deflate",
            }
        }
    }
}

// A server which receives an entity-body with a transfer-coding it does
// not understand SHOULD return 501 (Unimplemented), and close the
// connection. A server MUST NOT send transfer-codings to an HTTP/1.0
// client.

// [My note: implication of this is that I need to track HTTP version number of clients.]
<commit_msg>Use char literals instead of codepoint numbers for constants.<commit_after>//! Values taken from RFC 2616

/// OCTET: any 8-bit sequence of data (typechecking ensures this to be true)
#[inline]
pub fn is_octet(_: u8) -> bool { true }

/// CHAR: any US-ASCII character (octets 0 - 127)
#[inline]
pub fn is_char(octet: u8) -> bool { octet < 128 }

/// UPALPHA: any US-ASCII uppercase letter "A".."Z">
#[inline]
pub fn is_upalpha(octet: u8) -> bool { octet >= 'A' as u8 && octet <= 'Z' as u8 }

/// LOALPHA: any US-ASCII lowercase letter "a".."z">
#[inline]
pub fn is_loalpha(octet: u8) -> bool { octet >= 'a' as u8 && octet <= 'z' as u8 }

/// ALPHA: UPALPHA | LOALPHA
#[inline]
pub fn is_alpha(octet: u8) -> bool { is_upalpha(octet) || is_loalpha(octet) }

/// DIGIT: any US-ASCII digit "0".."9"
#[inline]
pub fn is_digit(octet: u8) -> bool { octet >= '0' as u8 && octet <= '9' as u8 }

/// CTL: any US-ASCII control character (octets 0 - 31) and DEL (127)
#[inline]
pub fn is_ctl(octet: u8) -> bool { octet < 32 || octet == 127 }

/// CR: US-ASCII CR, carriage return (13)
pub static CR: u8 = '\r' as u8;

/// LF: US-ASCII LF, linefeed (10)
pub static LF: u8 = '\n' as u8;

/// SP: US-ASCII SP, space (32)
pub static SP: u8 = ' ' as u8;

/// HT: US-ASCII HT, horizontal-tab (9)
pub static HT: u8 = '\t' as u8;

/// US-ASCII colon (58)
pub static COLON: u8 = ':' as u8;

/// <">: US-ASCII double-quote mark (34)
pub static DOUBLE_QUOTE: u8 = '"' as u8;

/// "\": US-ASCII backslash (92)
pub static BACKSLASH: u8 = '\\' as u8;

// CRLF: CR LF
//static CRLF: [u8] = [CR, LF];

// LWS: [CRLF] 1*( SP | HT )
/*#[inline]
fn is_lws(octets: &[u8]) -> bool {
    let mut has_crlf = false;
    let mut iter = octets.iter();
    if len(octets) == 0 {
        return false;
    }
    if len(octets) > 2 && octets[0] == CR && octets[1] == LF {
        iter = iter.next().next();
    }
    iter.all(|&octet| octet == SP || octet == HT)
}
*/

/*
   The TEXT rule is only used for descriptive field contents and values
   that are not intended to be interpreted by the message parser. Words
   of *TEXT MAY contain characters from character sets other than ISO-
   8859-1 [22] only when encoded according to the rules of RFC 2047
   [14].

       TEXT           = <any OCTET except CTLs,
                        but including LWS>

   A CRLF is allowed in the definition of TEXT only as part of a header
   field continuation. It is expected that the folding LWS will be
   replaced with a single SP before interpretation of the TEXT value.
*/

/// HEX: "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" | DIGIT
#[inline]
pub fn is_hex(octet: u8) -> bool {
    (octet >= 'A' as u8 && octet <= 'F' as u8) ||
    (octet >= 'a' as u8 && octet <= 'f' as u8) ||
    is_digit(octet)
}

/// token          = 1*<any CHAR except CTLs or separators>
#[inline]
pub fn is_token_item(o: u8) -> bool {
    is_char(o) && !is_ctl(o) && !is_separator(o)
}

#[inline]
pub fn is_token(s: &str) -> bool {
    s.byte_iter().all(|b| is_token_item(b))
}

/// separators: "(" | ")" | "<" | ">" | "@" | "," | ";" | ":"
///           | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{"
///           | "}" | SP | HT
#[inline]
pub fn is_separator(o: u8) -> bool {
    o == '(' as u8 || o == ')' as u8 || o == '<' as u8 || o == '>' as u8 || o == '@' as u8 ||
    o == ',' as u8 || o == ';' as u8 || o == ':' as u8 || o == '\\' as u8 || o == '"' as u8 ||
    o == '/' as u8 || o == '[' as u8 || o == ']' as u8 || o == '?' as u8 || o == '=' as u8 ||
    o == '{' as u8 || o == '}' as u8 || o == SP || o == HT
}

/*
 * Comments can be included in some HTTP header fields by surrounding
 * the comment text with parentheses. Comments are only allowed in
 * fields containing "comment" as part of their field value definition.
 * In all other fields, parentheses are considered part of the field
 * value.
 *
 *     comment        = "(" *( ctext | quoted-pair | comment ) ")"
 *     ctext          = <any TEXT excluding "(" and ")">
 *
 * A string of text is parsed as a single word if it is quoted using
 * double-quote marks.
 *
 *     quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
 *     qdtext         = <any TEXT except <">>
 *
 * The backslash character ("\") MAY be used as a single-character
 * quoting mechanism only within quoted-string and comment constructs.
 *
 *     quoted-pair    = "\" CHAR
 */
//#[inline]
//fn is_quoted_pair(o: &[u8, ..2]) { o[0] == 92 }

// IANA is assigned as maintaining the registry for these things:
// see https://www.iana.org/assignments/http-parameters/http-parameters.xml

mod content_coding {
    /// Content-coding value tokens
    pub enum ValueToken {
        // An encoding format produced by the file compression program "gzip" (GNU zip) as described
        // in RFC 1952 [25]. This format is a Lempel-Ziv coding (LZ77) with a 32 bit CRC.
        Gzip,

        // The encoding format produced by the common UNIX file compression program "compress". This
        // format is an adaptive Lempel-Ziv-Welch coding (LZW).
        //
        // Use of program names for the identification of encoding formats is not desirable and is
        // discouraged for future encodings. Their use here is representative of historical
        // practice, not good design. For compatibility with previous implementations of HTTP,
        // applications SHOULD consider "x-gzip" and "x-compress" to be equivalent to "gzip" and
        // "compress" respectively.
        Compress,

        // The "zlib" format defined in RFC 1950 [31] in combination with the "deflate" compression
        // mechanism described in RFC 1951 [29].
        Deflate,

        // The default (identity) encoding; the use of no transformation whatsoever. This
        // content-coding is used only in the Accept- Encoding header, and SHOULD NOT be used in the
        // Content-Encoding header.
        Identity,

        // IANA has also assigned the following currently unsupported content codings:
        //
        // - "exi": W3C Efficient XML Interchange
        // - "pack200-gzip" (Network Transfer Format for Java Archives)
    }
    impl ToStr for ValueToken {
        fn to_str(&self) -> ~str {
            match *self {
                Gzip => ~"gzip",
                Compress => ~"compress",
                Deflate => ~"deflate",
                Identity => ~"identity",
            }
        }
    }
    impl FromStr for ValueToken {
        fn from_str(s: &str) -> Option<ValueToken> {
            use std::ascii::StrAsciiExt;
            match s.to_ascii_lower().as_slice() {
                "gzip" => Some(Gzip),
                "compress" => Some(Compress),
                "deflate" => Some(Deflate),
                "identity" => Some(Identity),
                _ => None,
            }
        }
    }
}

mod transfer_coding {
    /// Transfer-coding value tokens
    // Identity is in RFC 2616 but is withdrawn in RFC 2616 errata ID 408
    // http://www.rfc-editor.org/errata_search.php?rfc=2616&eid=408
    pub enum ValueToken {
        Chunked,   // RFC 2616, §3.6.1
        Gzip,      // See above
        Compress,  // See above
        Deflate,   // See above
    }
    impl ToStr for ValueToken {
        fn to_str(&self) -> ~str {
            match *self {
                Chunked => ~"chunked",
                Gzip => ~"gzip",
                Compress => ~"compress",
                Deflate => ~"deflate",
            }
        }
    }
}

// A server which receives an entity-body with a transfer-coding it does
// not understand SHOULD return 501 (Unimplemented), and close the
// connection. A server MUST NOT send transfer-codings to an HTTP/1.0
// client.

// [My note: implication of this is that I need to track HTTP version number of clients.]
<|endoftext|>