<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Mesh loading.
//!
//! A `Mesh` describes the geometry of an object. All or part of a `Mesh` can be drawn with a
//! single draw call. A `Mesh` consists of a series of vertices, each with a certain amount of
//! user-specified attributes. These attributes are fed into shader programs. The easiest way to
//! create a mesh is to use the `#[vertex_format]` attribute on a struct, upload them into a
//! `Buffer`, and then use `Mesh::from`.

use device as d;
use device::attrib as a;

/// Describes a single attribute of a vertex buffer, including its type, name, etc.
#[deriving(Clone, PartialEq, Show)]
pub struct Attribute {
    /// Vertex buffer to contain the data
    pub buffer: d::RawBufferHandle,
    /// Number of elements per vertex
    pub elem_count: a::Count,
    /// Type of a single element
    pub elem_type: a::Type,
    /// Offset in bytes to the first vertex
    pub offset: a::Offset,
    /// Stride in bytes between consecutive vertices
    pub stride: a::Stride,
    /// A name to match the shader input
    pub name: String,
}

/// A trait implemented automatically for user vertex structure by
/// `#[vertex_format] attribute
pub trait VertexFormat {
    /// Create the attributes for this type, using the given buffer.
    fn generate(Option<Self>, buffer: d::RawBufferHandle) -> Vec<Attribute>;
}

/// Describes geometry to render.
#[deriving(Clone, Show)]
pub struct Mesh {
    /// Number of vertices in the mesh.
    pub num_vertices: d::VertexCount,
    /// Vertex attributes to use.
    pub attributes: Vec<Attribute>,
}

impl Mesh {
    /// Create a new mesh, which is a `TriangleList` with no attributes and `nv` vertices.
    pub fn new(nv: d::VertexCount) -> Mesh {
        Mesh {
            num_vertices: nv,
            attributes: Vec::new(),
        }
    }

    /// Create a new `Mesh` from a struct that implements `VertexFormat` and a buffer.
    pub fn from<V: VertexFormat>(buf: d::BufferHandle<V>, nv: d::VertexCount) -> Mesh {
        Mesh {
            num_vertices: nv,
            attributes: VertexFormat::generate(None::<V>, buf.raw()),
        }
    }

    /// Return a vertex slice of the whole mesh
    pub fn get_slice(&self, pt: d::PrimitiveType) -> Slice {
        VertexSlice(pt, 0, self.num_vertices)
    }
}

/// Description of a subset of `Mesh` data to render.
/// We provide a primitive type in a slice because it is how we interpret mesh
/// contents. For example, we can have a `Point` typed vertex slice to do shape
/// blending, while still rendereing it as an indexed `TriangleList`.
#[deriving(Clone, Show)]
pub enum Slice  {
    /// Render vertex data directly from the `Mesh`'s buffer, using only the vertices between the two
    /// endpoints.
    VertexSlice(d::PrimitiveType, d::VertexCount, d::VertexCount),
    /// The `IndexSlice*` buffer contains a list of indices into the `Mesh` data, so every vertex
    /// attribute does not need to be duplicated, only its position in the `Mesh`.  For example,
    /// when drawing a square, two triangles are needed.  Using only `VertexSlice`, one would need
    /// 6 separate vertices, 3 for each triangle. However, two of the vertices will be identical,
    /// wasting space for the duplicated attributes.  Instead, the `Mesh` can store 4 vertices and
    /// an `IndexSlice8` can be used instead.
    IndexSlice8(d::PrimitiveType, d::BufferHandle<u8>, d::IndexCount, d::IndexCount),
    /// As `IndexSlice8` but with `u16` indices
    IndexSlice16(d::PrimitiveType, d::BufferHandle<u16>, d::IndexCount, d::IndexCount),
    /// As `IndexSlice8` but with `u32` indices
    IndexSlice32(d::PrimitiveType, d::BufferHandle<u32>, d::IndexCount, d::IndexCount),
}

/// A slice of a mesh, with a given material.
#[deriving(Clone, Show)]
pub struct SubMesh {
    /// `Mesh` this `SubMesh` was created from.
    pub mesh: Mesh,
    /// Slice of the mesh to use.
    pub slice: Slice,
}
<commit_msg>Remove SubMesh type<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Mesh loading.
//!
//! A `Mesh` describes the geometry of an object. All or part of a `Mesh` can be drawn with a
//! single draw call. A `Mesh` consists of a series of vertices, each with a certain amount of
//! user-specified attributes. These attributes are fed into shader programs. The easiest way to
//! create a mesh is to use the `#[vertex_format]` attribute on a struct, upload them into a
//! `Buffer`, and then use `Mesh::from`.

use device as d;
use device::attrib as a;

/// Describes a single attribute of a vertex buffer, including its type, name, etc.
#[deriving(Clone, PartialEq, Show)]
pub struct Attribute {
    /// Vertex buffer to contain the data
    pub buffer: d::RawBufferHandle,
    /// Number of elements per vertex
    pub elem_count: a::Count,
    /// Type of a single element
    pub elem_type: a::Type,
    /// Offset in bytes to the first vertex
    pub offset: a::Offset,
    /// Stride in bytes between consecutive vertices
    pub stride: a::Stride,
    /// A name to match the shader input
    pub name: String,
}

/// A trait implemented automatically for user vertex structure by
/// `#[vertex_format] attribute
pub trait VertexFormat {
    /// Create the attributes for this type, using the given buffer.
    fn generate(Option<Self>, buffer: d::RawBufferHandle) -> Vec<Attribute>;
}

/// Describes geometry to render.
#[deriving(Clone, Show)]
pub struct Mesh {
    /// Number of vertices in the mesh.
    pub num_vertices: d::VertexCount,
    /// Vertex attributes to use.
    pub attributes: Vec<Attribute>,
}

impl Mesh {
    /// Create a new mesh, which is a `TriangleList` with no attributes and `nv` vertices.
    pub fn new(nv: d::VertexCount) -> Mesh {
        Mesh {
            num_vertices: nv,
            attributes: Vec::new(),
        }
    }

    /// Create a new `Mesh` from a struct that implements `VertexFormat` and a buffer.
    pub fn from<V: VertexFormat>(buf: d::BufferHandle<V>, nv: d::VertexCount) -> Mesh {
        Mesh {
            num_vertices: nv,
            attributes: VertexFormat::generate(None::<V>, buf.raw()),
        }
    }

    /// Return a vertex slice of the whole mesh
    pub fn get_slice(&self, pt: d::PrimitiveType) -> Slice {
        VertexSlice(pt, 0, self.num_vertices)
    }
}

/// Description of a subset of `Mesh` data to render.
/// We provide a primitive type in a slice because it is how we interpret mesh
/// contents. For example, we can have a `Point` typed vertex slice to do shape
/// blending, while still rendereing it as an indexed `TriangleList`.
#[deriving(Clone, Show)]
pub enum Slice  {
    /// Render vertex data directly from the `Mesh`'s buffer, using only the vertices between the two
    /// endpoints.
    VertexSlice(d::PrimitiveType, d::VertexCount, d::VertexCount),
    /// The `IndexSlice*` buffer contains a list of indices into the `Mesh` data, so every vertex
    /// attribute does not need to be duplicated, only its position in the `Mesh`.  For example,
    /// when drawing a square, two triangles are needed.  Using only `VertexSlice`, one would need
    /// 6 separate vertices, 3 for each triangle. However, two of the vertices will be identical,
    /// wasting space for the duplicated attributes.  Instead, the `Mesh` can store 4 vertices and
    /// an `IndexSlice8` can be used instead.
    IndexSlice8(d::PrimitiveType, d::BufferHandle<u8>, d::IndexCount, d::IndexCount),
    /// As `IndexSlice8` but with `u16` indices
    IndexSlice16(d::PrimitiveType, d::BufferHandle<u16>, d::IndexCount, d::IndexCount),
    /// As `IndexSlice8` but with `u32` indices
    IndexSlice32(d::PrimitiveType, d::BufferHandle<u32>, d::IndexCount, d::IndexCount),
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;

use {RngCore, CryptoRng, SeedableRng, Error};
use rngs::adapter::ReseedingRng;
use rngs::OsRng;
use rand_hc::Hc128Core;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
//
// The additional `Rc` is not strictly neccesary, and could be removed. For now
// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.

// Number of generated bytes after which to reseed `TreadRng`.
//
// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
// We pick a treshold here that is large enough to not reduce the average
// performance too much, but also small enough to not make reseeding something
// that basically never happens.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
/// which is reseeded after generating 32 MiB of random data. A single instance
/// is cached per thread and the returned `ThreadRng` is a reference to this
/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
/// within a single thread. This RNG is seeded and reseeded via [`OsRng`]
/// as required.
///
/// Note that the reseeding is done as an extra precaution against entropy
/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an
/// attacker would have to either determine most of the RNG's seed or internal
/// state, or crack the algorithm used.
///
/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
/// usage for better performance. This makes it similar to ISAAC, the algorithm
/// used in `ThreadRng` before rand 0.5.
///
/// Cloning this handle just produces a new reference to the same thread-local
/// generator.
///
/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
/// [`StdRng`]: crate::rngs::StdRng
/// [HC-128]: rand_hc::Hc128Rng
#[derive(Clone, Debug)]
pub struct ThreadRng {
    // use of raw pointer implies type is neither Send nor Sync
    rng: *mut ReseedingRng<Hc128Core, OsRng>,
}

thread_local!(
    static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Hc128Core, OsRng>> = {
        let r = Hc128Core::from_rng(OsRng).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    OsRng);
        UnsafeCell::new(rng)
    }
);

/// Retrieve the lazily-initialized thread-local random number generator,
/// seeded by the system. Intended to be used in method chaining style,
/// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.  Invoked by the `Default` trait, making
/// `ThreadRng::default()` equivalent.
///
/// For more information see [`ThreadRng`].
pub fn thread_rng() -> ThreadRng {
    ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.get()) }
}

impl Default for ThreadRng {
    fn default() -> ThreadRng {
        ::prelude::thread_rng()
    }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { (*self.rng).next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { (*self.rng).next_u64() }
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        unsafe { (*self.rng).fill_bytes(dest) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { (*self.rng).try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

#[cfg(test)]
mod test {
    #[test]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        assert_eq!(r.gen_range(0, 1), 0);
    }
}
<commit_msg>Make ThreadRng: Copy since it is just a handle<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;

use {RngCore, CryptoRng, SeedableRng, Error};
use rngs::adapter::ReseedingRng;
use rngs::OsRng;
use rand_hc::Hc128Core;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
//
// The additional `Rc` is not strictly neccesary, and could be removed. For now
// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.

// Number of generated bytes after which to reseed `TreadRng`.
//
// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
// We pick a treshold here that is large enough to not reduce the average
// performance too much, but also small enough to not make reseeding something
// that basically never happens.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
/// which is reseeded after generating 32 MiB of random data. A single instance
/// is cached per thread and the returned `ThreadRng` is a reference to this
/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
/// within a single thread. This RNG is seeded and reseeded via [`OsRng`]
/// as required.
///
/// Note that the reseeding is done as an extra precaution against entropy
/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an
/// attacker would have to either determine most of the RNG's seed or internal
/// state, or crack the algorithm used.
///
/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
/// usage for better performance. This makes it similar to ISAAC, the algorithm
/// used in `ThreadRng` before rand 0.5.
///
/// Cloning this handle just produces a new reference to the same thread-local
/// generator.
///
/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
/// [`StdRng`]: crate::rngs::StdRng
/// [HC-128]: rand_hc::Hc128Rng
#[derive(Copy, Clone, Debug)]
pub struct ThreadRng {
    // use of raw pointer implies type is neither Send nor Sync
    rng: *mut ReseedingRng<Hc128Core, OsRng>,
}

thread_local!(
    static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Hc128Core, OsRng>> = {
        let r = Hc128Core::from_rng(OsRng).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    OsRng);
        UnsafeCell::new(rng)
    }
);

/// Retrieve the lazily-initialized thread-local random number generator,
/// seeded by the system. Intended to be used in method chaining style,
/// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.  Invoked by the `Default` trait, making
/// `ThreadRng::default()` equivalent.
///
/// For more information see [`ThreadRng`].
pub fn thread_rng() -> ThreadRng {
    ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.get()) }
}

impl Default for ThreadRng {
    fn default() -> ThreadRng {
        ::prelude::thread_rng()
    }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { (*self.rng).next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { (*self.rng).next_u64() }
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        unsafe { (*self.rng).fill_bytes(dest) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { (*self.rng).try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

#[cfg(test)]
mod test {
    #[test]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        assert_eq!(r.gen_range(0, 1), 0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;
use std::rc::Rc;

use {RngCore, CryptoRng, SeedableRng, Error};
use rngs::adapter::ReseedingRng;
use rngs::EntropyRng;
use prng::hc128::Hc128Core;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
//
// The additional `Rc` is not strictly neccesary, and could be removed. For now
// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.

// Number of generated bytes after which to reseed `TreadRng`.
//
// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
// We pick a treshold here that is large enough to not reduce the average
// performance too much, but also small enough to not make reseeding something
// that basically never happens.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
/// which is reseeded after generating 32 MiB of random data. A single instance
/// is cached per thread and the returned `ThreadRng` is a reference to this
/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`]
/// as required.
///
/// Note that the reseeding is done as an extra precaution against entropy
/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an
/// attacker would have to either determine most of the RNG's seed or internal
/// state, or crack the algorithm used.
///
/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
/// usage for better performance. This makes it similar to ISAAC, the algorithm
/// used in `ThreadRng` before rand 0.5.
///
/// Cloning this handle just produces a new reference to the same thread-local
/// generator.
///
/// [`thread_rng`]: ../fn.thread_rng.html
/// [`ReseedingRng`]: adapter/struct.ReseedingRng.html
/// [`StdRng`]: struct.StdRng.html
/// [`EntropyRng`]: struct.EntropyRng.html
/// [HC-128]: ../prng/hc128/struct.Hc128Rng.html
#[derive(Clone, Debug)]
pub struct ThreadRng {
    rng: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>>,
}

thread_local!(
    static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>> = {
        let mut entropy_source = EntropyRng::new();
        let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    entropy_source);
        Rc::new(UnsafeCell::new(rng))
    }
);

/// Retrieve the lazily-initialized thread-local random number
/// generator, seeded by the system. Intended to be used in method
/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.
///
/// For more information see [`ThreadRng`].
///
/// [`ThreadRng`]: rngs/struct.ThreadRng.html
pub fn thread_rng() -> ThreadRng {
    ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { (*self.rng.get()).next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { (*self.rng.get()).next_u64() }
    }

    fn fill_bytes(&mut self, bytes: &mut [u8]) {
        unsafe { (*self.rng.get()).fill_bytes(bytes) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { (*self.rng.get()).try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

#[cfg(test)]
mod test {
    #[test]
    #[cfg(not(feature="stdweb"))]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        let mut v = [1, 1, 1];
        r.shuffle(&mut v);
        let b: &[_] = &[1, 1, 1];
        assert_eq!(v, b);
        assert_eq!(r.gen_range(0, 1), 0);
    }
}
<commit_msg>Use 'dest' as name for bytes param<commit_after>// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;
use std::rc::Rc;

use {RngCore, CryptoRng, SeedableRng, Error};
use rngs::adapter::ReseedingRng;
use rngs::EntropyRng;
use prng::hc128::Hc128Core;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
//
// The additional `Rc` is not strictly neccesary, and could be removed. For now
// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.

// Number of generated bytes after which to reseed `TreadRng`.
//
// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
// We pick a treshold here that is large enough to not reduce the average
// performance too much, but also small enough to not make reseeding something
// that basically never happens.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
/// which is reseeded after generating 32 MiB of random data. A single instance
/// is cached per thread and the returned `ThreadRng` is a reference to this
/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`]
/// as required.
///
/// Note that the reseeding is done as an extra precaution against entropy
/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an
/// attacker would have to either determine most of the RNG's seed or internal
/// state, or crack the algorithm used.
///
/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
/// usage for better performance. This makes it similar to ISAAC, the algorithm
/// used in `ThreadRng` before rand 0.5.
///
/// Cloning this handle just produces a new reference to the same thread-local
/// generator.
///
/// [`thread_rng`]: ../fn.thread_rng.html
/// [`ReseedingRng`]: adapter/struct.ReseedingRng.html
/// [`StdRng`]: struct.StdRng.html
/// [`EntropyRng`]: struct.EntropyRng.html
/// [HC-128]: ../prng/hc128/struct.Hc128Rng.html
#[derive(Clone, Debug)]
pub struct ThreadRng {
    rng: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>>,
}

thread_local!(
    static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>> = {
        let mut entropy_source = EntropyRng::new();
        let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    entropy_source);
        Rc::new(UnsafeCell::new(rng))
    }
);

/// Retrieve the lazily-initialized thread-local random number
/// generator, seeded by the system. Intended to be used in method
/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.
///
/// For more information see [`ThreadRng`].
///
/// [`ThreadRng`]: rngs/struct.ThreadRng.html
pub fn thread_rng() -> ThreadRng {
    ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { (*self.rng.get()).next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { (*self.rng.get()).next_u64() }
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        unsafe { (*self.rng.get()).fill_bytes(dest) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { (*self.rng.get()).try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

#[cfg(test)]
mod test {
    #[test]
    #[cfg(not(feature="stdweb"))]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        let mut v = [1, 1, 1];
        r.shuffle(&mut v);
        let b: &[_] = &[1, 1, 1];
        assert_eq!(v, b);
        assert_eq!(r.gen_range(0, 1), 0);
    }
}
<|endoftext|>


<commit_before>use std::io::fs;
use std::path::posix::Path;
use std::os::homedir;
#[cfg(test)] use test_helper::{cleanup_dir,random_name};

static MUXED_NAME_STR: &'static str = "muxed";

/// Create the muxed directory and return the path if creation is successful.
pub fn create_muxed_dir(path: &Path) -> Path {
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create muxed directory: {}", path.filename())
    }

    path.clone()
}

/// Return the users current homedir as a string.
pub fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

pub fn muxed_dir() -> Path {
    let path = muxed_path();
    match path.exists() {
        true  => path,
        false => create_muxed_dir(&path)
    }
}

#[cfg(test)] pub fn muxed_path() -> Path {
    Path::new(format!("/tmp/.muxed_{}/", random_name()))
}

#[cfg(not_test)] pub fn muxed_path() -> Path {
    Path::new(format!("{}/.{}/", root::homedir_string(), &MUXED_NAME_STR.to_string()))
}

#[test]
fn creates_muxed_dir() {
    let muxed_path = &muxed_path();
    create_muxed_dir(muxed_path);
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}

#[test]
fn muxed_dir_creates_dir() {
    let muxed_path = &muxed_dir();
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}

//#[test]
//fn muxed_dir_finds_existing_dir() {
//    let muxed_path = &muxed_path();
//    create_muxed_dir(muxed_path);
//    assert_eq!(muxed_path.as_str().unwrap(), muxed_dir().as_str().unwrap());
//    cleanup_dir(muxed_path);
//}
<commit_msg>Attempt to initialize a static constant using a function to get it's value.<commit_after>use std::io::fs;
use std::path::posix::Path;
use std::os::homedir;
#[cfg(test)] use test_helper::{cleanup_dir,random_name};

#[cfg(not_test)] static MUXED_NAME_STR: &'static str = "muxed";
#[cfg(test)]     static MUXED_NAME_STR: &'static String = format!("muxed_{}", random_name()).as_slice();

/// Create the muxed directory and return the path if creation is successful.
pub fn create_muxed_dir(path: &Path) -> Path {
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create muxed directory: {}", path.filename())
    }

    path.clone()
}

/// Return the users current homedir as a string.
pub fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

pub fn muxed_dir() -> Path {
    let path = muxed_path();
    match path.exists() {
        true  => path,
        false => create_muxed_dir(&path)
    }
}

#[cfg(test)] pub fn muxed_path() -> Path {
    Path::new(format!("/tmp/.{}/", &MUXED_NAME_STR.to_string()))
}

#[cfg(not_test)] pub fn muxed_path() -> Path {
    Path::new(format!("{}/.{}/", root::homedir_string(), &MUXED_NAME_STR.to_string()))
}

#[test]
fn creates_muxed_dir() {
    let muxed_path = &muxed_path();
    create_muxed_dir(muxed_path);
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}

#[test]
fn muxed_dir_creates_dir() {
    let muxed_path = &muxed_dir();
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}

//#[test]
//fn muxed_dir_finds_existing_dir() {
//    let muxed_path = &muxed_path();
//    create_muxed_dir(muxed_path);
//    assert_eq!(muxed_path.as_str().unwrap(), muxed_dir().as_str().unwrap());
//    cleanup_dir(muxed_path);
//}
<|endoftext|>


<commit_before>use crate::schema::{email, mailbox};
use crate::utils::{ConnectionPool, LoggedResult};
use anyhow::{format_err, Error};
use diesel::prelude::*;
use log::{debug, error};
use native_tls::{Identity, TlsAcceptor, TlsStream};
use std::io::{BufRead, BufReader, Write};
use std::iter::once;
use std::net::TcpStream;
use std::ops::Deref;
use std::time::SystemTime;

use crate::utils::StartsWithIgnoreCase;

const _MAX_LINE_LENGTH: usize = 1024;

#[derive(Debug)]
enum SMTPVerb<'a> {
    Helo,
    Ehlo,
    MailFrom(&'a str),
    RcptTo(&'a str),
    StartTLS,
    Data,
    Quit,
}

impl<'a> SMTPVerb<'a> {
    fn is_handshake(&self) -> bool {
        match self {
            Ehlo | Helo => true,
            _ => false,
        }
    }
}

use self::SMTPVerb::*;

pub struct SMTPSession {
    data: Option<String>,
    handshake_done: bool,
    recipients: Vec<String>,
    sender: Option<String>,
    plain_stream: BufReader<TcpStream>,
    tls_stream: Option<BufReader<TlsStream<TcpStream>>>,
}

impl SMTPSession {
    pub fn new(socket: TcpStream) -> Self {
        SMTPSession {
            data: None,
            handshake_done: false,
            recipients: Vec::new(),
            sender: None,
            plain_stream: BufReader::new(socket),
            tls_stream: None,
        }
    }

    fn send_invalid_command(&mut self) -> Result<(), Error> {
        self.send_status(503, "Invalid command")
    }

    fn send_ok(&mut self) -> Result<(), Error> {
        self.send_status(250, "Ok")
    }

    fn send_status(&mut self, code: u16, msg: &str) -> Result<(), Error> {
        let string = format!("{} {}\r\n", code, msg);
        debug!("--> {:?}", string);
        self.write_all(string.as_bytes())?;
        Ok(())
    }

    fn send_extended_status(
        &mut self,
        code: u16,
        msg: &str,
        extensions: &[&str],
    ) -> Result<(), Error> {
        let mut iterator = once(msg)
            .chain(extensions.iter().map(Deref::deref))
            .peekable();

        while let Some(item) = iterator.next() {
            let string = format!(
                "{}{}{}\r\n",
                code,
                if iterator.peek().is_none() { " " } else { "-" },
                item
            );
            debug!("--> {:?}", string);

            self.write_all(string.as_bytes())?;
        }

        Ok(())
    }

    fn write_all(&mut self, data: &[u8]) -> Result<(), Error> {
        let plain_writer = &mut self.plain_stream.get_mut();
        let writer: &mut dyn Write = if self.tls_stream.is_none() {
            plain_writer
        } else {
            self.tls_stream.as_mut().unwrap().get_mut()
        };
        writer.write_all(data).map_err(Error::from)
    }

    fn parse<'a>(&mut self, line: &'a str) -> Option<SMTPVerb<'a>> {
        if let Some(pos) = line.find(':') {
            let (command, rest) = line.split_at(pos);
            let rest = &rest[1..];
            let trimmed = command.trim();

            if trimmed.eq_ignore_ascii_case("rcpt to") {
                Some(RcptTo(parse_recipient(rest.trim()).ok()?))
            } else if trimmed.eq_ignore_ascii_case("mail from") {
                Some(MailFrom(rest.trim()))
            } else {
                error!("Unknown verb: {:?}", trimmed);
                None
            }
        } else if line.starts_with_ignore_case("ehlo ") {
            Some(Ehlo)
        } else if line.starts_with_ignore_case("helo ") {
            Some(Helo)
        } else if line.trim().eq_ignore_ascii_case("starttls") {
            Some(StartTLS)
        } else {
            let trimmed = line.trim();
            if trimmed.eq_ignore_ascii_case("data") {
                Some(Data)
            } else if trimmed.eq_ignore_ascii_case("quit") {
                Some(Quit)
            } else {
                None
            }
        }
    }

    fn read_line(&mut self) -> Result<String, Error> {
        let mut returned = String::new();
        let reader = self.get_reader();

        reader.read_line(&mut returned)?;
        Ok(returned)
    }

    // TODO stream should be a sum type
    fn get_reader(&mut self) -> &mut dyn BufRead {
        if self.tls_stream.is_none() {
            &mut self.plain_stream
        } else {
            self.tls_stream.as_mut().unwrap()
        }
    }

    fn enqueue(&mut self, pool: &ConnectionPool) -> Result<(), Error> {
        if self.sender.is_none() {
            return Err(format_err!("Sender is missing"));
        }
        if self.data.is_none() {
            return Err(format_err!("Data is missing"));
        }

        let data = self.data.as_ref().unwrap();

        let conn = pool.get()?;

        for recipient in &self.recipients {
            if let Some(mailbox_id) = mailbox::table
                .select(mailbox::columns::id)
                .filter(mailbox::columns::address.eq(&recipient))
                .first::<i32>(&conn)
                .optional()?
            {
                diesel::insert_into(email::table)
                    .values((
                        email::columns::fromaddr.eq(self.sender.as_ref().unwrap()),
                        email::columns::mailbox_id.eq(mailbox_id),
                        email::columns::timestamp.eq(SystemTime::now()),
                        email::columns::message.eq(&data),
                        email::columns::sent_via_ssl.eq(self.tls_stream.is_some()),
                    ))
                    .execute(&conn)
                    .log_errors()?;

                diesel::update(mailbox::table.filter(mailbox::columns::id.eq(mailbox_id)))
                    .set(mailbox::columns::last_activity.eq(SystemTime::now()))
                    .execute(&conn)
                    .log_errors()?;

                debug!("Enqueued message for {}", recipient);
            } else {
                debug!("Recipient {} not found", recipient);
            }
        }
        Ok(())
    }

    fn setup_tls(&mut self) -> Result<(), Error> {
        let stream = self.plain_stream.get_mut().try_clone()?;
        let acceptor = TlsAcceptor::new(load_tls_identity())?;
        self.tls_stream = Some(BufReader::new(acceptor.accept(stream)?));
        self.handshake_done = false;
        debug!("!!! established TLS connection");
        Ok(())
    }

    pub fn run(mut self, pool: &ConnectionPool) -> Result<(), Error> {
        self.send_status(220, "Mailboxer")?;
        loop {
            let line = self.read_line()?;
            debug!("<-- {:?}", line);

            let msg = if line.is_empty() {
                Some(Quit)
            } else {
                self.parse(&line)
            };

            if msg.is_none() {
                self.send_status(500, "Syntax error")?;
                continue;
            }

            let parsed = msg.unwrap();
            debug!("Parsed: {:?}", parsed);

            if let Quit = parsed {
                let returned = self.enqueue(pool);
                self.send_status(221, "Bye")?;
                return returned;
            }

            if self.handshake_done {
                match parsed {
                    RcptTo(recipient) => {
                        self.recipients.push(recipient.into());
                        self.send_ok()?;
                    }
                    MailFrom(sender) => {
                        if self.sender.is_some() {
                            self.send_invalid_command()?;
                        } else {
                            self.sender = Some(parse_recipient(sender)?.into());
                            self.send_ok()?;
                        }
                    }
                    StartTLS => {
                        if self.tls_stream.is_some() {
                            self.send_invalid_command()?;
                        } else {
                            self.send_status(220, "Ready to start TLS")?;
                            self.setup_tls()?;
                        }
                    }
                    Data => {
                        if self.data.is_none() {
                            self.send_status(354, "End data with <CR><LF>.<CR><LF>")?;
                            self.data = Some(read_to_end_of_data(self.get_reader())?);
                            self.send_ok()?;
                        } else {
                            self.send_invalid_command()?;
                        }
                    }
                    _ => {
                        self.send_invalid_command()?;
                    }
                }
            } else if parsed.is_handshake() {
                if let Ehlo = parsed {
                    self.send_extended_status(250, "Mailboxer", &["STARTTLS"])?;
                } else {
                    self.send_status(250, "Mailboxer")?;
                }
                self.handshake_done = true;
            } else {
                self.send_invalid_command()?;
            }
        }
    }
}

fn parse_recipient(recipient_string: &str) -> Result<&str, Error> {
    if !recipient_string.starts_with('<') || !recipient_string.ends_with('>') {
        error!("Invalid recipient string: {:?}", recipient_string);
        Err(format_err!(
            "Invalid recipient string: {}",
            recipient_string
        ))
    } else {
        Ok(&recipient_string[1..recipient_string.len() - 1])
    }
}

fn read_to_end_of_data(stream: &mut dyn BufRead) -> Result<String, Error> {
    let mut returned = Vec::new();
    let pattern = b"\r\n.\r\n";

    loop {
        let prev_pos = returned.len();
        let read_size = stream.read_until(b'\n', &mut returned)?;

        if read_size == 0 || returned[returned.len() - 1] != b'\n' {
            return Err(format_err!("EOF encountered"));
        }

        debug!("<-- {:?}", &returned[prev_pos..]);

        if let Some(pos) = returned
            .windows(pattern.len())
            .position(|subseq| subseq == pattern)
        {
            returned.truncate(pos);
            return String::from_utf8(returned).map_err(Error::from);
        }
    }
}

#[cfg(test)]
mod tests {

    use std::io::Cursor;

    use std::io::{BufReader, Read};

    fn check_read_to_end(data: &'static str, remainder: &'static str) {
        let buf = format!("{}\r\n.\r\n{}", data, remainder);

        assert_eq!(
            super::read_to_end_of_data(&mut BufReader::new(buf.as_bytes())).unwrap(),
            data
        );
    }

    #[test]
    fn test_read_to_end_of_data_no_suffix() {
        check_read_to_end("hello", "");
    }

    #[test]
    fn test_read_to_end_of_data_no_suffix_with_cr() {
        check_read_to_end("hello\rthere", "");
    }

    #[test]
    fn test_read_to_end_of_data_with_suffix_with_cr() {
        check_read_to_end("hello\rthere", "and there\r");
    }

    #[test]
    fn test_read_to_end_of_data_leaves_suffix() {
        let data = b"some data here\rwith\r\na suffix\r\n.\r\nquit\r\n";
        let mut buf_reader = Cursor::new(data.iter());
        assert!(super::read_to_end_of_data(&mut buf_reader).is_ok());
        let mut remainder = Vec::new();
        buf_reader.read_to_end(&mut remainder).unwrap();
        assert_eq!(String::from_utf8(remainder).unwrap(), "quit\r\n");
    }

    #[test]
    fn test_parse_recipient() {
        assert_eq!(
            super::parse_recipient("<some@email.com>").unwrap(),
            "some@email.com"
        );
    }
}

fn load_tls_identity() -> Identity {
    Identity::from_pkcs12(include_bytes!("../tls_identity.pfx"), "mailboxer")
        .expect("Unable to load identity")
}
<commit_msg>Clippy warnings<commit_after>use crate::schema::{email, mailbox};
use crate::utils::{ConnectionPool, LoggedResult};
use anyhow::{format_err, Error};
use diesel::prelude::*;
use log::{debug, error};
use native_tls::{Identity, TlsAcceptor, TlsStream};
use std::io::{BufRead, BufReader, Write};
use std::iter::once;
use std::net::TcpStream;
use std::ops::Deref;
use std::time::SystemTime;

use crate::utils::StartsWithIgnoreCase;

const _MAX_LINE_LENGTH: usize = 1024;

#[derive(Debug)]
enum SMTPVerb<'a> {
    Helo,
    Ehlo,
    MailFrom(&'a str),
    RcptTo(&'a str),
    StartTLS,
    Data,
    Quit,
}

impl<'a> SMTPVerb<'a> {
    fn is_handshake(&self) -> bool {
        matches!(self, Ehlo | Helo)
    }
}

use self::SMTPVerb::*;

pub struct SMTPSession {
    data: Option<String>,
    handshake_done: bool,
    recipients: Vec<String>,
    sender: Option<String>,
    plain_stream: BufReader<TcpStream>,
    tls_stream: Option<BufReader<TlsStream<TcpStream>>>,
}

impl SMTPSession {
    pub fn new(socket: TcpStream) -> Self {
        SMTPSession {
            data: None,
            handshake_done: false,
            recipients: Vec::new(),
            sender: None,
            plain_stream: BufReader::new(socket),
            tls_stream: None,
        }
    }

    fn send_invalid_command(&mut self) -> Result<(), Error> {
        self.send_status(503, "Invalid command")
    }

    fn send_ok(&mut self) -> Result<(), Error> {
        self.send_status(250, "Ok")
    }

    fn send_status(&mut self, code: u16, msg: &str) -> Result<(), Error> {
        let string = format!("{} {}\r\n", code, msg);
        debug!("--> {:?}", string);
        self.write_all(string.as_bytes())?;
        Ok(())
    }

    fn send_extended_status(
        &mut self,
        code: u16,
        msg: &str,
        extensions: &[&str],
    ) -> Result<(), Error> {
        let mut iterator = once(msg)
            .chain(extensions.iter().map(Deref::deref))
            .peekable();

        while let Some(item) = iterator.next() {
            let string = format!(
                "{}{}{}\r\n",
                code,
                if iterator.peek().is_none() { " " } else { "-" },
                item
            );
            debug!("--> {:?}", string);

            self.write_all(string.as_bytes())?;
        }

        Ok(())
    }

    fn write_all(&mut self, data: &[u8]) -> Result<(), Error> {
        let plain_writer = &mut self.plain_stream.get_mut();
        let writer: &mut dyn Write = if self.tls_stream.is_none() {
            plain_writer
        } else {
            self.tls_stream.as_mut().unwrap().get_mut()
        };
        writer.write_all(data).map_err(Error::from)
    }

    fn parse<'a>(&mut self, line: &'a str) -> Option<SMTPVerb<'a>> {
        if let Some(pos) = line.find(':') {
            let (command, rest) = line.split_at(pos);
            let rest = &rest[1..];
            let trimmed = command.trim();

            if trimmed.eq_ignore_ascii_case("rcpt to") {
                Some(RcptTo(parse_recipient(rest.trim()).ok()?))
            } else if trimmed.eq_ignore_ascii_case("mail from") {
                Some(MailFrom(rest.trim()))
            } else {
                error!("Unknown verb: {:?}", trimmed);
                None
            }
        } else if line.starts_with_ignore_case("ehlo ") {
            Some(Ehlo)
        } else if line.starts_with_ignore_case("helo ") {
            Some(Helo)
        } else if line.trim().eq_ignore_ascii_case("starttls") {
            Some(StartTLS)
        } else {
            let trimmed = line.trim();
            if trimmed.eq_ignore_ascii_case("data") {
                Some(Data)
            } else if trimmed.eq_ignore_ascii_case("quit") {
                Some(Quit)
            } else {
                None
            }
        }
    }

    fn read_line(&mut self) -> Result<String, Error> {
        let mut returned = String::new();
        let reader = self.get_reader();

        reader.read_line(&mut returned)?;
        Ok(returned)
    }

    // TODO stream should be a sum type
    fn get_reader(&mut self) -> &mut dyn BufRead {
        if self.tls_stream.is_none() {
            &mut self.plain_stream
        } else {
            self.tls_stream.as_mut().unwrap()
        }
    }

    fn enqueue(&mut self, pool: &ConnectionPool) -> Result<(), Error> {
        if self.sender.is_none() {
            return Err(format_err!("Sender is missing"));
        }
        if self.data.is_none() {
            return Err(format_err!("Data is missing"));
        }

        let data = self.data.as_ref().unwrap();

        let conn = pool.get()?;

        for recipient in &self.recipients {
            if let Some(mailbox_id) = mailbox::table
                .select(mailbox::columns::id)
                .filter(mailbox::columns::address.eq(&recipient))
                .first::<i32>(&conn)
                .optional()?
            {
                diesel::insert_into(email::table)
                    .values((
                        email::columns::fromaddr.eq(self.sender.as_ref().unwrap()),
                        email::columns::mailbox_id.eq(mailbox_id),
                        email::columns::timestamp.eq(SystemTime::now()),
                        email::columns::message.eq(&data),
                        email::columns::sent_via_ssl.eq(self.tls_stream.is_some()),
                    ))
                    .execute(&conn)
                    .log_errors()?;

                diesel::update(mailbox::table.filter(mailbox::columns::id.eq(mailbox_id)))
                    .set(mailbox::columns::last_activity.eq(SystemTime::now()))
                    .execute(&conn)
                    .log_errors()?;

                debug!("Enqueued message for {}", recipient);
            } else {
                debug!("Recipient {} not found", recipient);
            }
        }
        Ok(())
    }

    fn setup_tls(&mut self) -> Result<(), Error> {
        let stream = self.plain_stream.get_mut().try_clone()?;
        let acceptor = TlsAcceptor::new(load_tls_identity())?;
        self.tls_stream = Some(BufReader::new(acceptor.accept(stream)?));
        self.handshake_done = false;
        debug!("!!! established TLS connection");
        Ok(())
    }

    pub fn run(mut self, pool: &ConnectionPool) -> Result<(), Error> {
        self.send_status(220, "Mailboxer")?;
        loop {
            let line = self.read_line()?;
            debug!("<-- {:?}", line);

            let msg = if line.is_empty() {
                Some(Quit)
            } else {
                self.parse(&line)
            };

            if msg.is_none() {
                self.send_status(500, "Syntax error")?;
                continue;
            }

            let parsed = msg.unwrap();
            debug!("Parsed: {:?}", parsed);

            if let Quit = parsed {
                let returned = self.enqueue(pool);
                self.send_status(221, "Bye")?;
                return returned;
            }

            if self.handshake_done {
                match parsed {
                    RcptTo(recipient) => {
                        self.recipients.push(recipient.into());
                        self.send_ok()?;
                    }
                    MailFrom(sender) => {
                        if self.sender.is_some() {
                            self.send_invalid_command()?;
                        } else {
                            self.sender = Some(parse_recipient(sender)?.into());
                            self.send_ok()?;
                        }
                    }
                    StartTLS => {
                        if self.tls_stream.is_some() {
                            self.send_invalid_command()?;
                        } else {
                            self.send_status(220, "Ready to start TLS")?;
                            self.setup_tls()?;
                        }
                    }
                    Data => {
                        if self.data.is_none() {
                            self.send_status(354, "End data with <CR><LF>.<CR><LF>")?;
                            self.data = Some(read_to_end_of_data(self.get_reader())?);
                            self.send_ok()?;
                        } else {
                            self.send_invalid_command()?;
                        }
                    }
                    _ => {
                        self.send_invalid_command()?;
                    }
                }
            } else if parsed.is_handshake() {
                if let Ehlo = parsed {
                    self.send_extended_status(250, "Mailboxer", &["STARTTLS"])?;
                } else {
                    self.send_status(250, "Mailboxer")?;
                }
                self.handshake_done = true;
            } else {
                self.send_invalid_command()?;
            }
        }
    }
}

fn parse_recipient(recipient_string: &str) -> Result<&str, Error> {
    if !recipient_string.starts_with('<') || !recipient_string.ends_with('>') {
        error!("Invalid recipient string: {:?}", recipient_string);
        Err(format_err!(
            "Invalid recipient string: {}",
            recipient_string
        ))
    } else {
        Ok(&recipient_string[1..recipient_string.len() - 1])
    }
}

fn read_to_end_of_data(stream: &mut dyn BufRead) -> Result<String, Error> {
    let mut returned = Vec::new();
    let pattern = b"\r\n.\r\n";

    loop {
        let prev_pos = returned.len();
        let read_size = stream.read_until(b'\n', &mut returned)?;

        if read_size == 0 || returned[returned.len() - 1] != b'\n' {
            return Err(format_err!("EOF encountered"));
        }

        debug!("<-- {:?}", &returned[prev_pos..]);

        if let Some(pos) = returned
            .windows(pattern.len())
            .position(|subseq| subseq == pattern)
        {
            returned.truncate(pos);
            return String::from_utf8(returned).map_err(Error::from);
        }
    }
}

#[cfg(test)]
mod tests {

    use std::io::Cursor;

    use std::io::{BufReader, Read};

    fn check_read_to_end(data: &'static str, remainder: &'static str) {
        let buf = format!("{}\r\n.\r\n{}", data, remainder);

        assert_eq!(
            super::read_to_end_of_data(&mut BufReader::new(buf.as_bytes())).unwrap(),
            data
        );
    }

    #[test]
    fn test_read_to_end_of_data_no_suffix() {
        check_read_to_end("hello", "");
    }

    #[test]
    fn test_read_to_end_of_data_no_suffix_with_cr() {
        check_read_to_end("hello\rthere", "");
    }

    #[test]
    fn test_read_to_end_of_data_with_suffix_with_cr() {
        check_read_to_end("hello\rthere", "and there\r");
    }

    #[test]
    fn test_read_to_end_of_data_leaves_suffix() {
        let data = b"some data here\rwith\r\na suffix\r\n.\r\nquit\r\n";
        let mut buf_reader = Cursor::new(data.iter());
        assert!(super::read_to_end_of_data(&mut buf_reader).is_ok());
        let mut remainder = Vec::new();
        buf_reader.read_to_end(&mut remainder).unwrap();
        assert_eq!(String::from_utf8(remainder).unwrap(), "quit\r\n");
    }

    #[test]
    fn test_parse_recipient() {
        assert_eq!(
            super::parse_recipient("<some@email.com>").unwrap(),
            "some@email.com"
        );
    }
}

fn load_tls_identity() -> Identity {
    Identity::from_pkcs12(include_bytes!("../tls_identity.pfx"), "mailboxer")
        .expect("Unable to load identity")
}
<|endoftext|>


<commit_before>#[doc = "Generate markdown from a document tree"];

import std::io;
import std::io::writer_util;

export mk_pass;

fn mk_pass(
    writer: fn~() -> io::writer
) -> pass {
    ret fn~(
        _srv: astsrv::srv,
        doc: doc::cratedoc
    ) -> doc::cratedoc {
        write_markdown(doc, writer());
        doc
    };
}

type ctxt = {
    w: io::writer
};

fn write_markdown(
    doc: doc::cratedoc,
    writer: io::writer
) {
    let ctxt = {
        w: writer
    };

    write_crate(ctxt, doc);
}

enum hlvl {
    h1 = 1,
    h2 = 2,
    h3 = 3
}

fn write_header(ctxt: ctxt, lvl: hlvl, title: str) {
    let hashes = str::from_chars(vec::init_elt(lvl as uint, '#'));
    ctxt.w.write_line(#fmt("%s %s", hashes, title));
    ctxt.w.write_line("");
}

fn write_crate(
    ctxt: ctxt,
    doc: doc::cratedoc
) {
    write_header(ctxt, h1, #fmt("Crate %s", doc.topmod.name));
    write_top_module(ctxt, doc.topmod);
}

fn write_top_module(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    write_mod_contents(ctxt, moddoc);
}

fn write_mod(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    let fullpath = str::connect(moddoc.path + [moddoc.name], "::");
    write_header(ctxt, h2, #fmt("Module `%s`", fullpath));
    write_mod_contents(ctxt, moddoc);
}

#[test]
fn should_write_full_path_to_mod() {
    let markdown = test::render("mod a { mod b { mod c { } } }");
    assert str::contains(markdown, "## Module `a::b::c`");
}

fn write_mod_contents(
    ctxt: ctxt,
    doc: doc::moddoc
) {
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);

    for fndoc in *doc.fns {
        write_fn(ctxt, fndoc);
    }

    for moddoc in *doc.mods {
        write_mod(ctxt, moddoc);
    }
}

#[test]
fn should_write_crate_brief_description() {
    let markdown = test::render("#[doc(brief = \"this is the crate\")];");
    assert str::contains(markdown, "this is the crate");
}

#[test]
fn should_write_crate_description() {
    let markdown = test::render("#[doc = \"this is the crate\"];");
    assert str::contains(markdown, "this is the crate");
}

fn write_fn(
    ctxt: ctxt,
    doc: doc::fndoc
) {
    write_header(ctxt, h3, #fmt("Function `%s`", doc.name));
    write_sig(ctxt, doc.sig);
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);
    write_args(ctxt, doc.args);
    write_return(ctxt, doc.return);
}

fn write_sig(ctxt: ctxt, sig: option<str>) {
    alt sig {
      some(sig) {
        ctxt.w.write_line("```");
        ctxt.w.write_line(#fmt("%s", sig));
        ctxt.w.write_line("```");
        ctxt.w.write_line("");
      }
      none { fail "unimplemented" }
    }
}

#[test]
fn should_write_the_function_signature() {
    let markdown = test::render("#[doc = \"f\"] fn a() { }");
    assert str::contains(markdown, "```\nfn a()\n```");
}

#[test]
fn should_insert_blank_line_after_fn_signature() {
    let markdown = test::render("#[doc = \"f\"] fn a() { }");
    assert str::contains(markdown, "fn a()\n```\n\n");
}

fn write_brief(
    ctxt: ctxt,
    brief: option<str>
) {
    alt brief {
      some(brief) {
        ctxt.w.write_line(brief);
        ctxt.w.write_line("");
      }
      none { }
    }
}

fn write_desc(
    ctxt: ctxt,
    desc: option<str>
) {
    alt desc {
        some(desc) {
            ctxt.w.write_line(desc);
            ctxt.w.write_line("");
        }
        none { }
    }
}

fn write_args(
    ctxt: ctxt,
    args: [doc::argdoc]
) {
    if vec::is_not_empty(args) {
        ctxt.w.write_line("Arguments:");
        ctxt.w.write_line("");
        vec::iter(args) {|arg| write_arg(ctxt, arg) };
        ctxt.w.write_line("");
    }
}

fn write_arg(ctxt: ctxt, arg: doc::argdoc) {
    assert option::is_some(arg.ty);
    ctxt.w.write_str(#fmt(
        "* `%s`: `%s`",
        arg.name,
        option::get(arg.ty)
    ));
    alt arg.desc {
      some(desc) {
        ctxt.w.write_str(#fmt(" - %s", desc));
      }
      none { }
    }
    ctxt.w.write_line("");
}

#[test]
fn should_write_argument_list() {
    let source = "fn a(b: int, c: int) { }";
    let markdown = test::render(source);
    assert str::contains(
        markdown,
        "Arguments:\n\
         \n\
         * `b`: `int`\n\
         * `c`: `int`\n\
         \n"
    );
}

#[test]
fn should_not_write_arguments_if_none() {
    let source = "fn a() { } fn b() { }";
    let markdown = test::render(source);
    assert !str::contains(markdown, "Arguments");
}

#[test]
fn should_write_argument_description() {
    let source = "#[doc(args(a = \"milk\"))] fn f(a: bool) { }";
    let markdown = test::render(source);
    assert str::contains(markdown, "`a`: `bool` - milk");
}

fn write_return(
    ctxt: ctxt,
    doc: doc::retdoc
) {
    alt doc.ty {
      some(ty) {
        ctxt.w.write_line(#fmt("Returns `%s`", ty));
        ctxt.w.write_line("");
        alt doc.desc {
          some(d) {
            ctxt.w.write_line(d);
            ctxt.w.write_line("");
          }
          none { }
        }
      }
      none { }
    }
}

#[test]
fn should_write_return_type_on_new_line() {
    let markdown = test::render("fn a() -> int { }");
    assert str::contains(markdown, "\nReturns `int`");
}

#[test]
fn should_write_blank_line_between_return_type_and_next_header() {
    let markdown = test::render(
        "fn a() -> int { } \
         fn b() -> int { }"
    );
    assert str::contains(markdown, "Returns `int`\n\n##");
}

#[test]
fn should_not_write_return_type_when_there_is_none() {
    let markdown = test::render("fn a() { }");
    assert !str::contains(markdown, "Returns");
}

#[test]
fn should_write_blank_line_after_return_description() {
    let markdown = test::render(
        "#[doc(return = \"blorp\")] fn a() -> int { }"
    );
    assert str::contains(markdown, "blorp\n\n");
}

#[cfg(test)]
mod test {
    fn render(source: str) -> str {
        let srv = astsrv::mk_srv_from_str(source);
        let doc = extract::from_srv(srv, "");
        #debug("doc (extract): %?", doc);
        let doc = tystr_pass::mk_pass()(srv, doc);
        #debug("doc (tystr): %?", doc);
        let doc = path_pass::mk_pass()(srv, doc);
        #debug("doc (path): %?", doc);
        let doc = attr_pass::mk_pass()(srv, doc);
        #debug("doc (attr): %?", doc);
        let markdown = write_markdown_str(doc);
        #debug("markdown: %s", markdown);
        markdown
    }

    fn write_markdown_str(
        doc: doc::cratedoc
    ) -> str {
        let buffer = io::mk_mem_buffer();
        let writer = io::mem_buffer_writer(buffer);
        write_markdown(doc, writer);
        ret io::mem_buffer_str(buffer);
    }

    #[test]
    fn write_markdown_should_write_crate_header() {
        let srv = astsrv::mk_srv_from_str("");
        let doc = extract::from_srv(srv, "belch");
        let doc = attr_pass::mk_pass()(srv, doc);
        let markdown = write_markdown_str(doc);
        assert str::contains(markdown, "# Crate belch");
    }

    #[test]
    fn write_markdown_should_write_function_header() {
        let markdown = render("fn func() { }");
        assert str::contains(markdown, "## Function `func`");
    }

    #[test]
    fn write_markdown_should_write_mod_headers() {
        let markdown = render("mod moo { }");
        assert str::contains(markdown, "## Module `moo`");
    }

    #[test]
    fn should_leave_blank_line_after_header() {
        let markdown = render("mod morp { }");
        assert str::contains(markdown, "Module `morp`\n\n");
    }

    #[test]
    fn should_leave_blank_line_between_fn_header_and_sig() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "Function `a`\n\n```\nfn a()");
    }

    #[test]
    fn should_leave_blank_line_after_brief() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "brief\n\n");
    }

    #[test]
    fn should_leave_blank_line_between_brief_and_desc() {
        let markdown = render(
            "#[doc(brief = \"brief\", desc = \"desc\")] fn a() { }"
        );
        assert str::contains(markdown, "brief\n\ndesc");
    }

}<commit_msg>rustdoc: Print return value descriptions on same line as type<commit_after>#[doc = "Generate markdown from a document tree"];

import std::io;
import std::io::writer_util;

export mk_pass;

fn mk_pass(
    writer: fn~() -> io::writer
) -> pass {
    ret fn~(
        _srv: astsrv::srv,
        doc: doc::cratedoc
    ) -> doc::cratedoc {
        write_markdown(doc, writer());
        doc
    };
}

type ctxt = {
    w: io::writer
};

fn write_markdown(
    doc: doc::cratedoc,
    writer: io::writer
) {
    let ctxt = {
        w: writer
    };

    write_crate(ctxt, doc);
}

enum hlvl {
    h1 = 1,
    h2 = 2,
    h3 = 3
}

fn write_header(ctxt: ctxt, lvl: hlvl, title: str) {
    let hashes = str::from_chars(vec::init_elt(lvl as uint, '#'));
    ctxt.w.write_line(#fmt("%s %s", hashes, title));
    ctxt.w.write_line("");
}

fn write_crate(
    ctxt: ctxt,
    doc: doc::cratedoc
) {
    write_header(ctxt, h1, #fmt("Crate %s", doc.topmod.name));
    write_top_module(ctxt, doc.topmod);
}

fn write_top_module(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    write_mod_contents(ctxt, moddoc);
}

fn write_mod(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    let fullpath = str::connect(moddoc.path + [moddoc.name], "::");
    write_header(ctxt, h2, #fmt("Module `%s`", fullpath));
    write_mod_contents(ctxt, moddoc);
}

#[test]
fn should_write_full_path_to_mod() {
    let markdown = test::render("mod a { mod b { mod c { } } }");
    assert str::contains(markdown, "## Module `a::b::c`");
}

fn write_mod_contents(
    ctxt: ctxt,
    doc: doc::moddoc
) {
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);

    for fndoc in *doc.fns {
        write_fn(ctxt, fndoc);
    }

    for moddoc in *doc.mods {
        write_mod(ctxt, moddoc);
    }
}

#[test]
fn should_write_crate_brief_description() {
    let markdown = test::render("#[doc(brief = \"this is the crate\")];");
    assert str::contains(markdown, "this is the crate");
}

#[test]
fn should_write_crate_description() {
    let markdown = test::render("#[doc = \"this is the crate\"];");
    assert str::contains(markdown, "this is the crate");
}

fn write_fn(
    ctxt: ctxt,
    doc: doc::fndoc
) {
    write_header(ctxt, h3, #fmt("Function `%s`", doc.name));
    write_sig(ctxt, doc.sig);
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);
    write_args(ctxt, doc.args);
    write_return(ctxt, doc.return);
}

fn write_sig(ctxt: ctxt, sig: option<str>) {
    alt sig {
      some(sig) {
        ctxt.w.write_line("```");
        ctxt.w.write_line(#fmt("%s", sig));
        ctxt.w.write_line("```");
        ctxt.w.write_line("");
      }
      none { fail "unimplemented" }
    }
}

#[test]
fn should_write_the_function_signature() {
    let markdown = test::render("#[doc = \"f\"] fn a() { }");
    assert str::contains(markdown, "```\nfn a()\n```");
}

#[test]
fn should_insert_blank_line_after_fn_signature() {
    let markdown = test::render("#[doc = \"f\"] fn a() { }");
    assert str::contains(markdown, "fn a()\n```\n\n");
}

fn write_brief(
    ctxt: ctxt,
    brief: option<str>
) {
    alt brief {
      some(brief) {
        ctxt.w.write_line(brief);
        ctxt.w.write_line("");
      }
      none { }
    }
}

fn write_desc(
    ctxt: ctxt,
    desc: option<str>
) {
    alt desc {
        some(desc) {
            ctxt.w.write_line(desc);
            ctxt.w.write_line("");
        }
        none { }
    }
}

fn write_args(
    ctxt: ctxt,
    args: [doc::argdoc]
) {
    if vec::is_not_empty(args) {
        ctxt.w.write_line("Arguments:");
        ctxt.w.write_line("");
        vec::iter(args) {|arg| write_arg(ctxt, arg) };
        ctxt.w.write_line("");
    }
}

fn write_arg(ctxt: ctxt, arg: doc::argdoc) {
    assert option::is_some(arg.ty);
    ctxt.w.write_str(#fmt(
        "* `%s`: `%s`",
        arg.name,
        option::get(arg.ty)
    ));
    alt arg.desc {
      some(desc) {
        ctxt.w.write_str(#fmt(" - %s", desc));
      }
      none { }
    }
    ctxt.w.write_line("");
}

#[test]
fn should_write_argument_list() {
    let source = "fn a(b: int, c: int) { }";
    let markdown = test::render(source);
    assert str::contains(
        markdown,
        "Arguments:\n\
         \n\
         * `b`: `int`\n\
         * `c`: `int`\n\
         \n"
    );
}

#[test]
fn should_not_write_arguments_if_none() {
    let source = "fn a() { } fn b() { }";
    let markdown = test::render(source);
    assert !str::contains(markdown, "Arguments");
}

#[test]
fn should_write_argument_description() {
    let source = "#[doc(args(a = \"milk\"))] fn f(a: bool) { }";
    let markdown = test::render(source);
    assert str::contains(markdown, "`a`: `bool` - milk");
}

fn write_return(
    ctxt: ctxt,
    doc: doc::retdoc
) {
    alt doc.ty {
      some(ty) {
        ctxt.w.write_str(#fmt("Returns `%s`", ty));
        alt doc.desc {
          some(d) {
            ctxt.w.write_line(#fmt(" - %s", d));
            ctxt.w.write_line("");
          }
          none {
            ctxt.w.write_line("");
            ctxt.w.write_line("");
          }
        }
      }
      none { }
    }
}

#[test]
fn should_write_return_type_on_new_line() {
    let markdown = test::render("fn a() -> int { }");
    assert str::contains(markdown, "\nReturns `int`");
}

#[test]
fn should_write_blank_line_between_return_type_and_next_header() {
    let markdown = test::render(
        "fn a() -> int { } \
         fn b() -> int { }"
    );
    assert str::contains(markdown, "Returns `int`\n\n##");
}

#[test]
fn should_not_write_return_type_when_there_is_none() {
    let markdown = test::render("fn a() { }");
    assert !str::contains(markdown, "Returns");
}

#[test]
fn should_write_blank_line_after_return_description() {
    let markdown = test::render(
        "#[doc(return = \"blorp\")] fn a() -> int { }"
    );
    assert str::contains(markdown, "blorp\n\n");
}

#[test]
fn should_write_return_description_on_same_line_as_type() {
    let markdown = test::render(
        "#[doc(return = \"blorp\")] fn a() -> int { }"
    );
    assert str::contains(markdown, "Returns `int` - blorp");
}

#[cfg(test)]
mod test {
    fn render(source: str) -> str {
        let srv = astsrv::mk_srv_from_str(source);
        let doc = extract::from_srv(srv, "");
        #debug("doc (extract): %?", doc);
        let doc = tystr_pass::mk_pass()(srv, doc);
        #debug("doc (tystr): %?", doc);
        let doc = path_pass::mk_pass()(srv, doc);
        #debug("doc (path): %?", doc);
        let doc = attr_pass::mk_pass()(srv, doc);
        #debug("doc (attr): %?", doc);
        let markdown = write_markdown_str(doc);
        #debug("markdown: %s", markdown);
        markdown
    }

    fn write_markdown_str(
        doc: doc::cratedoc
    ) -> str {
        let buffer = io::mk_mem_buffer();
        let writer = io::mem_buffer_writer(buffer);
        write_markdown(doc, writer);
        ret io::mem_buffer_str(buffer);
    }

    #[test]
    fn write_markdown_should_write_crate_header() {
        let srv = astsrv::mk_srv_from_str("");
        let doc = extract::from_srv(srv, "belch");
        let doc = attr_pass::mk_pass()(srv, doc);
        let markdown = write_markdown_str(doc);
        assert str::contains(markdown, "# Crate belch");
    }

    #[test]
    fn write_markdown_should_write_function_header() {
        let markdown = render("fn func() { }");
        assert str::contains(markdown, "## Function `func`");
    }

    #[test]
    fn write_markdown_should_write_mod_headers() {
        let markdown = render("mod moo { }");
        assert str::contains(markdown, "## Module `moo`");
    }

    #[test]
    fn should_leave_blank_line_after_header() {
        let markdown = render("mod morp { }");
        assert str::contains(markdown, "Module `morp`\n\n");
    }

    #[test]
    fn should_leave_blank_line_between_fn_header_and_sig() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "Function `a`\n\n```\nfn a()");
    }

    #[test]
    fn should_leave_blank_line_after_brief() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "brief\n\n");
    }

    #[test]
    fn should_leave_blank_line_between_brief_and_desc() {
        let markdown = render(
            "#[doc(brief = \"brief\", desc = \"desc\")] fn a() { }"
        );
        assert str::contains(markdown, "brief\n\ndesc");
    }

}<|endoftext|>


<commit_before>use score::Match;

#[derive(PartialEq, Debug)]
pub enum Text<'a> {
    Colored(Match<'a>),
    Normal(String),
    Highlight(String),
    Blank,
}

impl<'a> Text<'a> {
    pub fn printable(self) -> String {
        match self {
            Text::Normal(t) => t,
            _ => "fail".to_string(),
        }
    }
}
<commit_msg>Panic instead of returning a dummy value<commit_after>use score::Match;

#[derive(PartialEq, Debug)]
pub enum Text<'a> {
    Colored(Match<'a>),
    Normal(String),
    Highlight(String),
    Blank,
}

impl<'a> Text<'a> {
    pub fn printable(self) -> String {
        match self {
            Text::Normal(t) => t,
            _ => panic!("only normal is plrintable?")
        }
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;
use std::str;
use collections::Deque;
use collections::ringbuf::RingBuf;

pub struct WrapLineIterator<T> {
    /// Input iterator
    iter: T,
    /// Maximum line length
    line_len: uint,
    /// Characters output since last newline
    current_line_len: uint,
    /// Incoming elements
    buffer: RingBuf<char>,
    /// Peek window
    peek: Option<char>,
}

impl<T: Iterator<char>> WrapLineIterator<T> {
    fn fill_buffer(&mut self) {
        assert!(self.buffer.is_empty());
        let mut seen_text = false;
        let mut text_length = 0;
        match self.peek {
            Some(c) => {
                assert!(c.is_whitespace());
                self.buffer.push_back(c);
                self.peek = None;
            },
            None => ()
        }
        loop {
            let c = match self.iter.next() {
                None => break,
                Some(c) => c
            };

            // Break before non-newline whitespace after
            // non-whitespace text has been seen. (Newlines will be
            // included in the buffer.)
            if seen_text && c.is_whitespace() && c != '\n' {
                self.peek = Some(c);
                break;
            }
            self.buffer.push_back(c);
            if !c.is_whitespace() {
                seen_text = true;
                text_length += 1;
            }

            if text_length >= self.line_len {
                // The word is longer than the allowed line length,
                // need to break it.
                break;
            }
            // Break after hyphen or newline.
            if c == '-' || c == '\n' {
                break;
            }
        }
    }

    fn trim_buffer_left(&mut self) {
        while !self.buffer.is_empty() && self.buffer.front().unwrap().is_whitespace() {
            self.buffer.pop_front();
        }
    }
}

impl<T: Iterator<char>> Iterator<char> for WrapLineIterator<T> {
    fn next(&mut self) -> Option<char> {
        if self.buffer.is_empty() {
            return None;
        }
        if self.current_line_len + self.buffer.len() > self.line_len {
            // Next word won't fit, insert a newline.
            self.current_line_len = 0;
            self.trim_buffer_left();
            return Some('\n');
        }
        let c = self.buffer.pop_front().unwrap();
        self.current_line_len += 1;
        if c == '\n' {
            self.current_line_len = 0;
        }
        if self.buffer.is_empty() {
            self.fill_buffer();
        }
        Some(c)
    }
}

// All char iterators get this trait and the new method.
pub trait WrapUtil {
    fn wrap(self, line_len: uint) -> WrapLineIterator<Self>;
}

impl<T: Iterator<char>> WrapUtil for T {
    fn wrap(self, line_len: uint) -> WrapLineIterator<T> {
        assert!(line_len > 0);
        let mut ret = WrapLineIterator{
            iter: self,
            line_len: line_len,
            current_line_len: 0,
            buffer: RingBuf::new(),
            peek: None,
        };
        ret.fill_buffer();
        ret
    }
}

pub fn wrap_lines(line_len: uint, s: &str) -> String {
    str::from_chars(s.chars().wrap(line_len).collect::<Vec<char>>().as_slice())
}

pub struct Map2DIterator<T> {
    /// Input iterator
    iter: T,
    x: int,
    y: int,
}

impl<T: Iterator<char>> Iterator<(char, int, int)> for Map2DIterator<T> {
    fn next(&mut self) -> Option<(char, int, int)> {
        loop {
            match self.iter.next() {
                None => { return None }
                Some(c) if c == '\n' => { self.y += 1; self.x = 0; }
                Some(c) if (c as u32) < 32 => { }
                Some(c) => { self.x += 1; return Some((c, self.x - 1, self.y)) }
            }
        }
    }
}

pub trait Map2DUtil {
    fn map2d(self) -> Map2DIterator<Self>;
}

impl<T: Iterator<char>> Map2DUtil for T {
    fn map2d(self) -> Map2DIterator<T> {
        Map2DIterator{ iter: self, x: 0, y: 0 }
    }
}
<commit_msg>Fix some warnings<commit_after>use std::vec::Vec;
use collections::Deque;
use collections::ringbuf::RingBuf;

pub struct WrapLineIterator<T> {
    /// Input iterator
    iter: T,
    /// Maximum line length
    line_len: uint,
    /// Characters output since last newline
    current_line_len: uint,
    /// Incoming elements
    buffer: RingBuf<char>,
    /// Peek window
    peek: Option<char>,
}

impl<T: Iterator<char>> WrapLineIterator<T> {
    fn fill_buffer(&mut self) {
        assert!(self.buffer.is_empty());
        let mut seen_text = false;
        let mut text_length = 0;
        match self.peek {
            Some(c) => {
                assert!(c.is_whitespace());
                self.buffer.push(c);
                self.peek = None;
            },
            None => ()
        }
        loop {
            let c = match self.iter.next() {
                None => break,
                Some(c) => c
            };

            // Break before non-newline whitespace after
            // non-whitespace text has been seen. (Newlines will be
            // included in the buffer.)
            if seen_text && c.is_whitespace() && c != '\n' {
                self.peek = Some(c);
                break;
            }
            self.buffer.push(c);
            if !c.is_whitespace() {
                seen_text = true;
                text_length += 1;
            }

            if text_length >= self.line_len {
                // The word is longer than the allowed line length,
                // need to break it.
                break;
            }
            // Break after hyphen or newline.
            if c == '-' || c == '\n' {
                break;
            }
        }
    }

    fn trim_buffer_left(&mut self) {
        while !self.buffer.is_empty() && self.buffer.front().unwrap().is_whitespace() {
            self.buffer.pop_front();
        }
    }
}

impl<T: Iterator<char>> Iterator<char> for WrapLineIterator<T> {
    fn next(&mut self) -> Option<char> {
        if self.buffer.is_empty() {
            return None;
        }
        if self.current_line_len + self.buffer.len() > self.line_len {
            // Next word won't fit, insert a newline.
            self.current_line_len = 0;
            self.trim_buffer_left();
            return Some('\n');
        }
        let c = self.buffer.pop_front().unwrap();
        self.current_line_len += 1;
        if c == '\n' {
            self.current_line_len = 0;
        }
        if self.buffer.is_empty() {
            self.fill_buffer();
        }
        Some(c)
    }
}

// All char iterators get this trait and the new method.
pub trait WrapUtil {
    fn wrap(self, line_len: uint) -> WrapLineIterator<Self>;
}

impl<T: Iterator<char>> WrapUtil for T {
    fn wrap(self, line_len: uint) -> WrapLineIterator<T> {
        assert!(line_len > 0);
        let mut ret = WrapLineIterator{
            iter: self,
            line_len: line_len,
            current_line_len: 0,
            buffer: RingBuf::new(),
            peek: None,
        };
        ret.fill_buffer();
        ret
    }
}

pub fn wrap_lines(line_len: uint, s: &str) -> String {
    String::from_chars(s.chars().wrap(line_len).collect::<Vec<char>>().as_slice())
}

pub struct Map2DIterator<T> {
    /// Input iterator
    iter: T,
    x: int,
    y: int,
}

impl<T: Iterator<char>> Iterator<(char, int, int)> for Map2DIterator<T> {
    fn next(&mut self) -> Option<(char, int, int)> {
        loop {
            match self.iter.next() {
                None => { return None }
                Some(c) if c == '\n' => { self.y += 1; self.x = 0; }
                Some(c) if (c as u32) < 32 => { }
                Some(c) => { self.x += 1; return Some((c, self.x - 1, self.y)) }
            }
        }
    }
}

pub trait Map2DUtil {
    fn map2d(self) -> Map2DIterator<Self>;
}

impl<T: Iterator<char>> Map2DUtil for T {
    fn map2d(self) -> Map2DIterator<T> {
        Map2DIterator{ iter: self, x: 0, y: 0 }
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use super::Field;
use crate::common;
use crate::schema::Facet;
use crate::DateTime;
use std::str;

/// Size (in bytes) of the buffer of a int field.
const INT_TERM_LEN: usize = 4 + 8;

/// Term represents the value that the token can take.
///
/// It actually wraps a `Vec<u8>`.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct Term<B = Vec<u8>>(B)
where
    B: AsRef<[u8]>;

impl Term {
    pub(crate) fn new() -> Term {
        Term(Vec::with_capacity(100))
    }

    /// Builds a term given a field, and a i64-value
    ///
    /// Assuming the term has a field id of 1, and a i64 value of 3234,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the u64 value.
    pub fn from_field_i64(field: Field, val: i64) -> Term {
        let val_u64: u64 = common::i64_to_u64(val);
        Term::from_field_u64(field, val_u64)
    }

    /// Builds a term given a field, and a f64-value
    ///
    /// Assuming the term has a field id of 1, and a f64 value of 1.5,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the f64 as a u64 value.
    pub fn from_field_f64(field: Field, val: f64) -> Term {
        let val_u64: u64 = common::f64_to_u64(val);
        Term::from_field_u64(field, val_u64)
    }

    /// Builds a term given a field, and a DateTime value
    ///
    /// Assuming the term has a field id of 1, and a timestamp i64 value of 3234,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the DateTime as i64 timestamp value.
    pub fn from_field_date(field: Field, val: &DateTime) -> Term {
        let val_timestamp = val.timestamp();
        Term::from_field_i64(field, val_timestamp)
    }

    /// Creates a `Term` given a facet.
    pub fn from_facet(field: Field, facet: &Facet) -> Term {
        let bytes = facet.encoded_str().as_bytes();
        let buffer = Vec::with_capacity(4 + bytes.len());
        let mut term = Term(buffer);
        term.set_field(field);
        term.set_bytes(bytes);
        term
    }

    /// Builds a term given a field, and a string value
    ///
    /// Assuming the term has a field id of 2, and a text value of "abc",
    /// the Term will have 4 bytes.
    /// The first byte is 2, and the three following bytes are the utf-8
    /// representation of "abc".
    pub fn from_field_text(field: Field, text: &str) -> Term {
        let buffer = Vec::with_capacity(4 + text.len());
        let mut term = Term(buffer);
        term.set_field(field);
        term.set_text(text);
        term
    }

    /// Builds a term given a field, and a u64-value
    ///
    /// Assuming the term has a field id of 1, and a u64 value of 3234,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the u64 value.
    pub fn from_field_u64(field: Field, val: u64) -> Term {
        let mut term = Term(vec![0u8; INT_TERM_LEN]);
        term.set_field(field);
        term.set_u64(val);
        term
    }

    pub(crate) fn from_field_bytes(field: Field, bytes: &[u8]) -> Term {
        let mut term = Term::for_field(field);
        term.set_bytes(bytes);
        term
    }

    /// Creates a new Term for a given field.
    pub(crate) fn for_field(field: Field) -> Term {
        let mut term = Term(Vec::with_capacity(100));
        term.set_field(field);
        term
    }

    pub(crate) fn set_field(&mut self, field: Field) {
        self.0.clear();
        self.0
            .extend_from_slice(field.field_id().to_be_bytes().as_ref());
    }

    /// Sets a u64 value in the term.
    ///
    /// U64 are serialized using (8-byte) BigEndian
    /// representation.
    /// The use of BigEndian has the benefit of preserving
    /// the natural order of the values.
    pub fn set_u64(&mut self, val: u64) {
        self.0.resize(INT_TERM_LEN, 0u8);
        self.set_bytes(val.to_be_bytes().as_ref());
    }

    /// Sets a `i64` value in the term.
    pub fn set_i64(&mut self, val: i64) {
        self.set_u64(common::i64_to_u64(val));
    }

    /// Sets a `f64` value in the term.
    pub fn set_f64(&mut self, val: f64) {
        self.set_u64(common::f64_to_u64(val));
    }

    /// Sets the value of a `Bytes` field.
    pub fn set_bytes(&mut self, bytes: &[u8]) {
        self.0.resize(4, 0u8);
        self.0.extend(bytes);
    }

    /// Set the texts only, keeping the field untouched.
    pub fn set_text(&mut self, text: &str) {
        self.set_bytes(text.as_bytes());
    }
}

impl<B> Term<B>
where
    B: AsRef<[u8]>,
{
    /// Wraps a object holding bytes
    pub fn wrap(data: B) -> Term<B> {
        Term(data)
    }

    /// Returns the field.
    pub fn field(&self) -> Field {
        let mut field_id_bytes = [0u8; 4];
        field_id_bytes.copy_from_slice(&self.0.as_ref()[..4]);
        Field::from_field_id(u32::from_be_bytes(field_id_bytes))
    }

    /// Returns the `u64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `u64` field.
    pub fn get_u64(&self) -> u64 {
        let mut field_id_bytes = [0u8; 8];
        field_id_bytes.copy_from_slice(self.value_bytes());
        u64::from_be_bytes(field_id_bytes)
    }

    /// Returns the `i64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `i64` field.
    pub fn get_i64(&self) -> i64 {
        common::u64_to_i64(self.get_u64())
    }

    /// Returns the `f64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `f64` field.
    pub fn get_f64(&self) -> f64 {
        common::u64_to_f64(self.get_u64())
    }

    /// Returns the text associated with the term.
    ///
    /// # Panics
    /// If the value is not valid utf-8. This may happen
    /// if the index is corrupted or if you try to
    /// call this method on a non-string type.
    pub fn text(&self) -> &str {
        str::from_utf8(self.value_bytes()).expect("Term does not contain valid utf-8.")
    }

    /// Returns the serialized value of the term.
    /// (this does not include the field.)
    ///
    /// If the term is a string, its value is utf-8 encoded.
    /// If the term is a u64, its value is encoded according
    /// to `byteorder::LittleEndian`.
    pub fn value_bytes(&self) -> &[u8] {
        &self.0.as_ref()[4..]
    }

    /// Returns the underlying `&[u8]`
    pub fn as_slice(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl<B> AsRef<[u8]> for Term<B>
where
    B: AsRef<[u8]>,
{
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl fmt::Debug for Term {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Term(field={},bytes={:?})",
            self.field().field_id(),
            self.value_bytes()
        )
    }
}

#[cfg(test)]
mod tests {

    use crate::schema::*;

    #[test]
    pub fn test_term() {
        let mut schema_builder = Schema::builder();
        schema_builder.add_text_field("text", STRING);
        let title_field = schema_builder.add_text_field("title", STRING);
        let count_field = schema_builder.add_text_field("count", STRING);
        {
            let term = Term::from_field_text(title_field, "test");
            assert_eq!(term.field(), title_field);
            assert_eq!(&term.as_slice()[0..4], &[0u8, 0u8, 0u8, 1u8]);
            assert_eq!(&term.as_slice()[4..], "test".as_bytes());
        }
        {
            let term = Term::from_field_u64(count_field, 983u64);
            assert_eq!(term.field(), count_field);
            assert_eq!(&term.as_slice()[0..4], &[0u8, 0u8, 0u8, 2u8]);
            assert_eq!(term.as_slice().len(), 4 + 8);
            assert_eq!(term.as_slice()[4], 0u8);
            assert_eq!(term.as_slice()[5], 0u8);
            assert_eq!(term.as_slice()[6], 0u8);
            assert_eq!(term.as_slice()[7], 0u8);
            assert_eq!(term.as_slice()[8], 0u8);
            assert_eq!(term.as_slice()[9], 0u8);
            assert_eq!(term.as_slice()[10], (933u64 / 256u64) as u8);
            assert_eq!(term.as_slice()[11], (983u64 % 256u64) as u8);
        }
    }
}
<commit_msg>Made  public.<commit_after>use std::fmt;

use super::Field;
use crate::common;
use crate::schema::Facet;
use crate::DateTime;
use std::str;

/// Size (in bytes) of the buffer of a int field.
const INT_TERM_LEN: usize = 4 + 8;

/// Term represents the value that the token can take.
///
/// It actually wraps a `Vec<u8>`.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct Term<B = Vec<u8>>(B)
where
    B: AsRef<[u8]>;

impl Term {
    pub(crate) fn new() -> Term {
        Term(Vec::with_capacity(100))
    }

    /// Builds a term given a field, and a i64-value
    ///
    /// Assuming the term has a field id of 1, and a i64 value of 3234,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the u64 value.
    pub fn from_field_i64(field: Field, val: i64) -> Term {
        let val_u64: u64 = common::i64_to_u64(val);
        Term::from_field_u64(field, val_u64)
    }

    /// Builds a term given a field, and a f64-value
    ///
    /// Assuming the term has a field id of 1, and a f64 value of 1.5,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the f64 as a u64 value.
    pub fn from_field_f64(field: Field, val: f64) -> Term {
        let val_u64: u64 = common::f64_to_u64(val);
        Term::from_field_u64(field, val_u64)
    }

    /// Builds a term given a field, and a DateTime value
    ///
    /// Assuming the term has a field id of 1, and a timestamp i64 value of 3234,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the DateTime as i64 timestamp value.
    pub fn from_field_date(field: Field, val: &DateTime) -> Term {
        let val_timestamp = val.timestamp();
        Term::from_field_i64(field, val_timestamp)
    }

    /// Creates a `Term` given a facet.
    pub fn from_facet(field: Field, facet: &Facet) -> Term {
        let bytes = facet.encoded_str().as_bytes();
        let buffer = Vec::with_capacity(4 + bytes.len());
        let mut term = Term(buffer);
        term.set_field(field);
        term.set_bytes(bytes);
        term
    }

    /// Builds a term given a field, and a string value
    ///
    /// Assuming the term has a field id of 2, and a text value of "abc",
    /// the Term will have 4 bytes.
    /// The first byte is 2, and the three following bytes are the utf-8
    /// representation of "abc".
    pub fn from_field_text(field: Field, text: &str) -> Term {
        let buffer = Vec::with_capacity(4 + text.len());
        let mut term = Term(buffer);
        term.set_field(field);
        term.set_text(text);
        term
    }

    /// Builds a term given a field, and a u64-value
    ///
    /// Assuming the term has a field id of 1, and a u64 value of 3234,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the u64 value.
    pub fn from_field_u64(field: Field, val: u64) -> Term {
        let mut term = Term(vec![0u8; INT_TERM_LEN]);
        term.set_field(field);
        term.set_u64(val);
        term
    }

    pub fn from_field_bytes(field: Field, bytes: &[u8]) -> Term {
        let mut term = Term::for_field(field);
        term.set_bytes(bytes);
        term
    }

    /// Creates a new Term for a given field.
    pub(crate) fn for_field(field: Field) -> Term {
        let mut term = Term(Vec::with_capacity(100));
        term.set_field(field);
        term
    }

    pub(crate) fn set_field(&mut self, field: Field) {
        self.0.clear();
        self.0
            .extend_from_slice(field.field_id().to_be_bytes().as_ref());
    }

    /// Sets a u64 value in the term.
    ///
    /// U64 are serialized using (8-byte) BigEndian
    /// representation.
    /// The use of BigEndian has the benefit of preserving
    /// the natural order of the values.
    pub fn set_u64(&mut self, val: u64) {
        self.0.resize(INT_TERM_LEN, 0u8);
        self.set_bytes(val.to_be_bytes().as_ref());
    }

    /// Sets a `i64` value in the term.
    pub fn set_i64(&mut self, val: i64) {
        self.set_u64(common::i64_to_u64(val));
    }

    /// Sets a `f64` value in the term.
    pub fn set_f64(&mut self, val: f64) {
        self.set_u64(common::f64_to_u64(val));
    }

    /// Sets the value of a `Bytes` field.
    pub fn set_bytes(&mut self, bytes: &[u8]) {
        self.0.resize(4, 0u8);
        self.0.extend(bytes);
    }

    /// Set the texts only, keeping the field untouched.
    pub fn set_text(&mut self, text: &str) {
        self.set_bytes(text.as_bytes());
    }
}

impl<B> Term<B>
where
    B: AsRef<[u8]>,
{
    /// Wraps a object holding bytes
    pub fn wrap(data: B) -> Term<B> {
        Term(data)
    }

    /// Returns the field.
    pub fn field(&self) -> Field {
        let mut field_id_bytes = [0u8; 4];
        field_id_bytes.copy_from_slice(&self.0.as_ref()[..4]);
        Field::from_field_id(u32::from_be_bytes(field_id_bytes))
    }

    /// Returns the `u64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `u64` field.
    pub fn get_u64(&self) -> u64 {
        let mut field_id_bytes = [0u8; 8];
        field_id_bytes.copy_from_slice(self.value_bytes());
        u64::from_be_bytes(field_id_bytes)
    }

    /// Returns the `i64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `i64` field.
    pub fn get_i64(&self) -> i64 {
        common::u64_to_i64(self.get_u64())
    }

    /// Returns the `f64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `f64` field.
    pub fn get_f64(&self) -> f64 {
        common::u64_to_f64(self.get_u64())
    }

    /// Returns the text associated with the term.
    ///
    /// # Panics
    /// If the value is not valid utf-8. This may happen
    /// if the index is corrupted or if you try to
    /// call this method on a non-string type.
    pub fn text(&self) -> &str {
        str::from_utf8(self.value_bytes()).expect("Term does not contain valid utf-8.")
    }

    /// Returns the serialized value of the term.
    /// (this does not include the field.)
    ///
    /// If the term is a string, its value is utf-8 encoded.
    /// If the term is a u64, its value is encoded according
    /// to `byteorder::LittleEndian`.
    pub fn value_bytes(&self) -> &[u8] {
        &self.0.as_ref()[4..]
    }

    /// Returns the underlying `&[u8]`
    pub fn as_slice(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl<B> AsRef<[u8]> for Term<B>
where
    B: AsRef<[u8]>,
{
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl fmt::Debug for Term {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Term(field={},bytes={:?})",
            self.field().field_id(),
            self.value_bytes()
        )
    }
}

#[cfg(test)]
mod tests {

    use crate::schema::*;

    #[test]
    pub fn test_term() {
        let mut schema_builder = Schema::builder();
        schema_builder.add_text_field("text", STRING);
        let title_field = schema_builder.add_text_field("title", STRING);
        let count_field = schema_builder.add_text_field("count", STRING);
        {
            let term = Term::from_field_text(title_field, "test");
            assert_eq!(term.field(), title_field);
            assert_eq!(&term.as_slice()[0..4], &[0u8, 0u8, 0u8, 1u8]);
            assert_eq!(&term.as_slice()[4..], "test".as_bytes());
        }
        {
            let term = Term::from_field_u64(count_field, 983u64);
            assert_eq!(term.field(), count_field);
            assert_eq!(&term.as_slice()[0..4], &[0u8, 0u8, 0u8, 2u8]);
            assert_eq!(term.as_slice().len(), 4 + 8);
            assert_eq!(term.as_slice()[4], 0u8);
            assert_eq!(term.as_slice()[5], 0u8);
            assert_eq!(term.as_slice()[6], 0u8);
            assert_eq!(term.as_slice()[7], 0u8);
            assert_eq!(term.as_slice()[8], 0u8);
            assert_eq!(term.as_slice()[9], 0u8);
            assert_eq!(term.as_slice()[10], (933u64 / 256u64) as u8);
            assert_eq!(term.as_slice()[11], (983u64 % 256u64) as u8);
        }
    }
}
<|endoftext|>