<commit_before>use std::borrow::Cow;
use std::collections::BTreeMap;
use std::marker::PhantomData;
use std::ops::Deref;

use serde;
use serde_json;

use sodiumoxide::crypto::sign;

use ser::signatures::Base64Signature;

pub trait Signatures {
    fn get_signature(&self, entity: &str, key_id: &str) -> Option<&sign::Signature>;
    fn get_signatures_for_entity<'a>(
        &'a self,
        entity: &'a str
    ) -> Box<Iterator<Item = (&'a str, &sign::Signature)> + 'a>;
    fn get_signatures<'a>(&'a self)
        -> Box<Iterator<Item = (&'a str, &'a str, &sign::Signature)> + 'a>;
    fn get_entities<'a>(&'a self) -> Box<Iterator<Item = &'a str> + 'a>;
    fn as_map<'a>(&'a self) -> BTreeMap<&'a str, BTreeMap<&'a str, &sign::Signature>>;
}

pub trait SignaturesMut {
    fn add_signature(&mut self, entity: &str, key_id: &str, sig: sign::Signature);
    fn clear(&mut self);
}

pub trait Signed {
    fn signatures(&self) -> &Signatures;
}

pub trait SignedMut: Signed {
    fn signatures_mut(&mut self) -> &mut SignaturesMut;
}

pub trait AsCanonical {
    fn as_canonical(&self) -> Cow<[u8]>;
}

pub trait GetUnsigned {
    fn get_unsigned(&self) -> Option<serde_json::Value>;
}

impl<S> Signatures for BTreeMap<String, BTreeMap<String, S>>
    where S: Deref<Target = sign::Signature>
{
    fn get_signature(&self, entity: &str, key_id: &str) -> Option<&sign::Signature> {
        self.get(entity).and_then(|sigs| sigs.get(key_id)).map(|s| s.deref())
    }

    fn get_signatures_for_entity<'a>(
        &'a self,
        entity: &'a str
    ) -> Box<Iterator<Item = (&'a str, &sign::Signature)> + 'a> {
        Box::new(self.iter()
                     .filter_map(move |(d, sigs)| if d == entity {
                         Some(sigs)
                     } else {
                         None
                     })
                     .flat_map(|s| s.iter())
                     .map(|(k, v)| (&k[..], v.deref())))
    }

    fn get_signatures<'a>(&'a self)
        -> Box<Iterator<Item = (&'a str, &'a str, &sign::Signature)> + 'a> {
        Box::new(self.iter()
                     .flat_map(|(e, sigs)| sigs.iter().map(move |(n, sig)| (e, n, sig)))
                     .map(|(e, n, sig)| (&e[..], &n[..], sig.deref())))
    }

    fn get_entities<'a>(&'a self) -> Box<Iterator<Item = &'a str> + 'a> {
        Box::new(self.keys().map(|s| &s[..]))
    }

    fn as_map<'a>(&'a self) -> BTreeMap<&'a str, BTreeMap<&'a str, &'a sign::Signature>> {
        self.iter()
            .map(|(e, v)| {
                let map = v.iter()
                           .map(|(n, s)| -> (&'a str, &'a sign::Signature) { (n, s) })
                           .collect();
                (e as &'a str, map)
            })
            .collect()
    }
}

impl<S> SignaturesMut for BTreeMap<String, BTreeMap<String, S>>
    where S: From<sign::Signature>
{
    fn add_signature(&mut self, entity: &str, key_id: &str, sig: sign::Signature) {
        self.entry(entity.to_string())
            .or_insert_with(BTreeMap::new)
            .insert(key_id.to_string(), S::from(sig));
    }

    fn clear(&mut self) {
        self.clear();
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SimpleSigned {
    pub signatures: BTreeMap<String, BTreeMap<String, Base64Signature>>,
}

impl Signed for SimpleSigned {
    fn signatures(&self) -> &Signatures {
        &self.signatures
    }
}

impl SignedMut for SimpleSigned {
    fn signatures_mut(&mut self) -> &mut SignaturesMut {
        &mut self.signatures
    }
}

enum SimpleSignedField {
    SIGNATURES,
    IGNORE,
}
impl serde::de::Deserialize for SimpleSignedField {
    #[inline]
    fn deserialize<D>(deserializer: &mut D) -> Result<SimpleSignedField, D::Error>
        where D: serde::de::Deserializer
    {
        deserializer.deserialize_struct_field(SimpleSignedFieldVisitor::<D> {
            phantom: PhantomData,
        })
    }
}

struct SimpleSignedFieldVisitor<D> {
    phantom: PhantomData<D>,
}
impl<D> serde::de::Visitor for SimpleSignedFieldVisitor<D>
    where D: serde::de::Deserializer
{
    type Value = SimpleSignedField;

    fn visit_usize<E>(&mut self, value: usize) -> Result<SimpleSignedField, E>
        where E: serde::de::Error
    {
        match value {
            0usize => Ok(SimpleSignedField::SIGNATURES),
            _ => Ok(SimpleSignedField::IGNORE),
        }
    }
    fn visit_str<E>(&mut self, value: &str) -> Result<SimpleSignedField, E>
        where E: serde::de::Error
    {
        match value {
            "signatures" => Ok(SimpleSignedField::SIGNATURES),
            _ => Ok(SimpleSignedField::IGNORE),
        }
    }
    fn visit_bytes<E>(&mut self, value: &[u8]) -> Result<SimpleSignedField, E>
        where E: serde::de::Error
    {
        match value {
            b"signatures" => Ok(SimpleSignedField::SIGNATURES),
            _ => Ok(SimpleSignedField::IGNORE),
        }
    }
}

struct SimpleSignedVisitor<D: serde::de::Deserializer>(PhantomData<D>);
impl<D: serde::de::Deserializer> serde::de::Visitor for SimpleSignedVisitor<D> {
    type Value = SimpleSigned;

    #[inline]
    fn visit_seq<V>(&mut self, mut visitor: V) -> Result<SimpleSigned, V::Error>
        where V: serde::de::SeqVisitor
    {
        {
            let sigs = match try!(visitor.visit()) {
                Some(value) => value,
                None => {
                    return Err(serde::de::Error::end_of_stream());
                }
            };
            try!(visitor.end());
            Ok(SimpleSigned { signatures: sigs })
        }
    }
    #[inline]
    fn visit_map<V>(&mut self, mut visitor: V) -> Result<SimpleSigned, V::Error>
        where V: serde::de::MapVisitor
    {
        {
            let mut sigs = None;
            while let Some(key) = try!(visitor.visit_key()) {
                match key {
                    SimpleSignedField::SIGNATURES => {
                        sigs = Some(try!(visitor.visit_value()));
                    }
                    _ => {
                        try!(visitor.visit_value::<serde::de::impls::IgnoredAny>());
                    }
                }
            }
            let sigs = match sigs {
                Some(sigs) => sigs,
                None => {
                    match visitor.missing_field("signatures") {
                        Ok(value) => value,
                        Err(value) => return Err(value),
                    }
                }
            };
            try!(visitor.end());
            Ok(SimpleSigned { signatures: sigs })
        }
    }
}

impl serde::de::Deserialize for SimpleSigned {
    fn deserialize<D>(deserializer: &mut D) -> Result<SimpleSigned, D::Error>
        where D: serde::de::Deserializer
    {
        {
            const FIELDS: &'static [&'static str] = &["signatures"];
            deserializer.deserialize_struct("SimpleSigned",
                                            FIELDS,
                                            SimpleSignedVisitor::<D>(PhantomData))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::BTreeMap;
    use ser::signatures::Base64Signature;
    use sodiumoxide::crypto::sign;
    use serde_json;
    use itertools::Itertools;

    #[test]
    fn map_sigs() {
        let map: BTreeMap<String, BTreeMap<String, Base64Signature>> = serde_json::from_slice(br#"{
            "jki.re":{
                "ed25519:auto":"X2t7jN0jaJsiZWp57da9GqmQ874QFbukCMSqc5VclaB+2n4i8LPcZDkD6+fzg4tkfpSsiIDogkY4HWv1cnGhAg"
            }
        }"#).unwrap();

        let sig = map.get_signature("jki.re", "ed25519:auto").expect("Missing signature");

        let expected_sig_bytes = b"_k{\x8c\xdd#h\x9b\"ejy\xed\xd6\xbd\x1a\xa9\x90\xf3\xbe\x10\x15\xbb\xa4\x08\xc4\xaas\x95\\\x95\xa0~\xda~\"\xf0\xb3\xdcd9\x03\xeb\xe7\xf3\x83\x8bd~\x94\xac\x88\x80\xe8\x82F8\x1dk\xf5rq\xa1\x02";
        let expected_sig = sign::Signature::from_slice(expected_sig_bytes).unwrap();
        assert_eq!(sig, &expected_sig);

        assert!(map.get_signature("jki.re", "ed25519:test").is_none());
        assert!(map.get_signature("example.com", "ed25519:auto").is_none());

        let entities = &map.get_entities().collect_vec();
        assert_eq!(&entities[..], &["jki.re"]);

        let sigs_for_entites = &map.get_signatures_for_entity("jki.re").collect_vec();
        assert_eq!(&sigs_for_entites[..], &[("ed25519:auto", &expected_sig)]);

        let entities = &map.get_signatures().collect_vec();
        assert_eq!(&entities[..], &[("jki.re", "ed25519:auto", &expected_sig)]);
    }
}
<commit_msg>Signature field is optional<commit_after>use std::borrow::Cow;
use std::collections::BTreeMap;
use std::marker::PhantomData;
use std::ops::Deref;

use serde;
use serde_json;

use sodiumoxide::crypto::sign;

use ser::signatures::Base64Signature;

pub trait Signatures {
    fn get_signature(&self, entity: &str, key_id: &str) -> Option<&sign::Signature>;
    fn get_signatures_for_entity<'a>(
        &'a self,
        entity: &'a str
    ) -> Box<Iterator<Item = (&'a str, &sign::Signature)> + 'a>;
    fn get_signatures<'a>(&'a self)
        -> Box<Iterator<Item = (&'a str, &'a str, &sign::Signature)> + 'a>;
    fn get_entities<'a>(&'a self) -> Box<Iterator<Item = &'a str> + 'a>;
    fn as_map<'a>(&'a self) -> BTreeMap<&'a str, BTreeMap<&'a str, &sign::Signature>>;
}

pub trait SignaturesMut {
    fn add_signature(&mut self, entity: &str, key_id: &str, sig: sign::Signature);
    fn clear(&mut self);
}

pub trait Signed {
    fn signatures(&self) -> &Signatures;
}

pub trait SignedMut: Signed {
    fn signatures_mut(&mut self) -> &mut SignaturesMut;
}

pub trait AsCanonical {
    fn as_canonical(&self) -> Cow<[u8]>;
}

pub trait GetUnsigned {
    fn get_unsigned(&self) -> Option<serde_json::Value>;
}

impl<S> Signatures for BTreeMap<String, BTreeMap<String, S>>
    where S: Deref<Target = sign::Signature>
{
    fn get_signature(&self, entity: &str, key_id: &str) -> Option<&sign::Signature> {
        self.get(entity).and_then(|sigs| sigs.get(key_id)).map(|s| s.deref())
    }

    fn get_signatures_for_entity<'a>(
        &'a self,
        entity: &'a str
    ) -> Box<Iterator<Item = (&'a str, &sign::Signature)> + 'a> {
        Box::new(self.iter()
                     .filter_map(move |(d, sigs)| if d == entity {
                         Some(sigs)
                     } else {
                         None
                     })
                     .flat_map(|s| s.iter())
                     .map(|(k, v)| (&k[..], v.deref())))
    }

    fn get_signatures<'a>(&'a self)
        -> Box<Iterator<Item = (&'a str, &'a str, &sign::Signature)> + 'a> {
        Box::new(self.iter()
                     .flat_map(|(e, sigs)| sigs.iter().map(move |(n, sig)| (e, n, sig)))
                     .map(|(e, n, sig)| (&e[..], &n[..], sig.deref())))
    }

    fn get_entities<'a>(&'a self) -> Box<Iterator<Item = &'a str> + 'a> {
        Box::new(self.keys().map(|s| &s[..]))
    }

    fn as_map<'a>(&'a self) -> BTreeMap<&'a str, BTreeMap<&'a str, &'a sign::Signature>> {
        self.iter()
            .map(|(e, v)| {
                let map = v.iter()
                           .map(|(n, s)| -> (&'a str, &'a sign::Signature) { (n, s) })
                           .collect();
                (e as &'a str, map)
            })
            .collect()
    }
}

impl<S> SignaturesMut for BTreeMap<String, BTreeMap<String, S>>
    where S: From<sign::Signature>
{
    fn add_signature(&mut self, entity: &str, key_id: &str, sig: sign::Signature) {
        self.entry(entity.to_string())
            .or_insert_with(BTreeMap::new)
            .insert(key_id.to_string(), S::from(sig));
    }

    fn clear(&mut self) {
        self.clear();
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SimpleSigned {
    pub signatures: BTreeMap<String, BTreeMap<String, Base64Signature>>,
}

impl Signed for SimpleSigned {
    fn signatures(&self) -> &Signatures {
        &self.signatures
    }
}

impl SignedMut for SimpleSigned {
    fn signatures_mut(&mut self) -> &mut SignaturesMut {
        &mut self.signatures
    }
}

enum SimpleSignedField {
    SIGNATURES,
    IGNORE,
}
impl serde::de::Deserialize for SimpleSignedField {
    #[inline]
    fn deserialize<D>(deserializer: &mut D) -> Result<SimpleSignedField, D::Error>
        where D: serde::de::Deserializer
    {
        deserializer.deserialize_struct_field(SimpleSignedFieldVisitor::<D> {
            phantom: PhantomData,
        })
    }
}

struct SimpleSignedFieldVisitor<D> {
    phantom: PhantomData<D>,
}
impl<D> serde::de::Visitor for SimpleSignedFieldVisitor<D>
    where D: serde::de::Deserializer
{
    type Value = SimpleSignedField;

    fn visit_usize<E>(&mut self, value: usize) -> Result<SimpleSignedField, E>
        where E: serde::de::Error
    {
        match value {
            0usize => Ok(SimpleSignedField::SIGNATURES),
            _ => Ok(SimpleSignedField::IGNORE),
        }
    }
    fn visit_str<E>(&mut self, value: &str) -> Result<SimpleSignedField, E>
        where E: serde::de::Error
    {
        match value {
            "signatures" => Ok(SimpleSignedField::SIGNATURES),
            _ => Ok(SimpleSignedField::IGNORE),
        }
    }
    fn visit_bytes<E>(&mut self, value: &[u8]) -> Result<SimpleSignedField, E>
        where E: serde::de::Error
    {
        match value {
            b"signatures" => Ok(SimpleSignedField::SIGNATURES),
            _ => Ok(SimpleSignedField::IGNORE),
        }
    }
}

struct SimpleSignedVisitor<D: serde::de::Deserializer>(PhantomData<D>);
impl<D: serde::de::Deserializer> serde::de::Visitor for SimpleSignedVisitor<D> {
    type Value = SimpleSigned;

    #[inline]
    fn visit_seq<V>(&mut self, mut visitor: V) -> Result<SimpleSigned, V::Error>
        where V: serde::de::SeqVisitor
    {
        {
            let sigs = match try!(visitor.visit()) {
                Some(value) => value,
                None => {
                    return Err(serde::de::Error::end_of_stream());
                }
            };
            try!(visitor.end());
            Ok(SimpleSigned { signatures: sigs })
        }
    }
    #[inline]
    fn visit_map<V>(&mut self, mut visitor: V) -> Result<SimpleSigned, V::Error>
        where V: serde::de::MapVisitor
    {
        {
            let mut sigs = None;
            while let Some(key) = try!(visitor.visit_key()) {
                match key {
                    SimpleSignedField::SIGNATURES => {
                        sigs = Some(try!(visitor.visit_value()));
                    }
                    _ => {
                        try!(visitor.visit_value::<serde::de::impls::IgnoredAny>());
                    }
                }
            }
            let sigs = match sigs {
                Some(sigs) => sigs,
                None => {
                    match visitor.missing_field("signatures") {
                        Ok(value) => value,
                        Err(_) => BTreeMap::new(),
                    }
                }
            };
            try!(visitor.end());
            Ok(SimpleSigned { signatures: sigs })
        }
    }
}

impl serde::de::Deserialize for SimpleSigned {
    fn deserialize<D>(deserializer: &mut D) -> Result<SimpleSigned, D::Error>
        where D: serde::de::Deserializer
    {
        {
            const FIELDS: &'static [&'static str] = &["signatures"];
            deserializer.deserialize_struct("SimpleSigned",
                                            FIELDS,
                                            SimpleSignedVisitor::<D>(PhantomData))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::BTreeMap;
    use ser::signatures::Base64Signature;
    use sodiumoxide::crypto::sign;
    use serde_json;
    use itertools::Itertools;

    #[test]
    fn map_sigs() {
        let map: BTreeMap<String, BTreeMap<String, Base64Signature>> = serde_json::from_slice(br#"{
            "jki.re":{
                "ed25519:auto":"X2t7jN0jaJsiZWp57da9GqmQ874QFbukCMSqc5VclaB+2n4i8LPcZDkD6+fzg4tkfpSsiIDogkY4HWv1cnGhAg"
            }
        }"#).unwrap();

        let sig = map.get_signature("jki.re", "ed25519:auto").expect("Missing signature");

        let expected_sig_bytes = b"_k{\x8c\xdd#h\x9b\"ejy\xed\xd6\xbd\x1a\xa9\x90\xf3\xbe\x10\x15\xbb\xa4\x08\xc4\xaas\x95\\\x95\xa0~\xda~\"\xf0\xb3\xdcd9\x03\xeb\xe7\xf3\x83\x8bd~\x94\xac\x88\x80\xe8\x82F8\x1dk\xf5rq\xa1\x02";
        let expected_sig = sign::Signature::from_slice(expected_sig_bytes).unwrap();
        assert_eq!(sig, &expected_sig);

        assert!(map.get_signature("jki.re", "ed25519:test").is_none());
        assert!(map.get_signature("example.com", "ed25519:auto").is_none());

        let entities = &map.get_entities().collect_vec();
        assert_eq!(&entities[..], &["jki.re"]);

        let sigs_for_entites = &map.get_signatures_for_entity("jki.re").collect_vec();
        assert_eq!(&sigs_for_entites[..], &[("ed25519:auto", &expected_sig)]);

        let entities = &map.get_signatures().collect_vec();
        assert_eq!(&entities[..], &[("jki.re", "ed25519:auto", &expected_sig)]);
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::marker::PhantomData;
use std::borrow::{Borrow, BorrowMut};
use gl;
use gl::types::*;
use ref_into::{RefInto, MutInto};
use context::ContextOf;
use framebuffer::FramebufferBinding;
use types::{DrawingMode, GLError};
use index_data::{IndexData, IndexDatum, IndexDatumType};

pub struct Buffer {
    gl_id: GLuint
}

impl Buffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenBuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Buffer { gl_id: id }
        }
    }
}

impl<BA, BE, F, P, R, T> ContextOf<BufferBinderOf<BA, BE>, F, P, R, T> {
    pub fn split_array_buffer(self)
        -> (BA, ContextOf<BufferBinderOf<(), BE>, F, P, R, T>)
    {
        let (buffers, gl) = self.split_buffers();
        let (ba_binder, rest_buffers) = buffers.split_array();

        (ba_binder, gl.join_buffers(rest_buffers))
    }

    pub fn split_element_array_buffer(self)
        -> (BE, ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>)
    {
        let (buffers, gl) = self.split_buffers();
        let (be_binder, rest_buffers) = buffers.split_element_array();
        (be_binder, gl.join_buffers(rest_buffers))
    }
}

pub trait ArrayBufferContext {
    type Rest;

    fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ArrayBufferBinding<'a>, Self::Rest);
}

pub trait ElementArrayBufferContext {
    type Rest;

    fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ElementArrayBufferBinding<'a>, Self::Rest);
}

impl<BA, BE, F, P, R, T> ArrayBufferContext
    for ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BA: BorrowMut<ArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<(), BE>, F, P, R, T>;

    fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ArrayBufferBinding<'a>, Self::Rest)
    {
        let (mut ba_binder, rest) = self.split_array_buffer();
        (ba_binder.borrow_mut().bind(buffer), rest)
    }
}

impl<BA, BE, F, P, R, T> ElementArrayBufferContext
    for ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BE: BorrowMut<ElementArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>;

    fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ElementArrayBufferBinding<'a>, Self::Rest)
    {
        let (mut be_binder, rest) = self.split_element_array_buffer();
        (be_binder.borrow_mut().bind(buffer), rest)
    }
}

pub trait BufferContext: ArrayBufferContext + ElementArrayBufferContext {

}

impl<BA, BE, F, P, R, T> BufferContext
    for ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BA: BorrowMut<ArrayBufferBinder>,
          BE: BorrowMut<ElementArrayBufferBinder>
{

}

gl_enum! {
    pub gl_enum BufferDataUsage {
        StreamDraw as STREAM_DRAW = gl::STREAM_DRAW,
        StaticDraw as STATIC_DRAW = gl::STATIC_DRAW,
        DynamicDraw as DYNAMIC_DRAW = gl::DYNAMIC_DRAW
    }
}

gl_enum! {
    pub gl_enum BufferBindingTarget {
        ArrayBuffer as ARRAY_BUFFER = gl::ARRAY_BUFFER,
        ElementArrayBuffer as ELEMENT_ARRAY_BUFFER = gl::ELEMENT_ARRAY_BUFFER
    }
}

pub trait BufferBinding {
    fn target(&self) -> BufferBindingTarget;

    fn buffer_bytes(&mut self, bytes: &[u8], usage: BufferDataUsage) {
        let ptr = bytes.as_ptr();
        let size = bytes.len() * mem::size_of::<u8>();
        unsafe {
            gl::BufferData(self.target().gl_enum(),
                           size as GLsizeiptr,
                           ptr as *const GLvoid,
                           usage.gl_enum());
            dbg_gl_error! {
                GLError::InvalidEnum => "Invalid `target` or `usage`",
                GLError::InvalidValue => "`size` is negative",
                GLError::InvalidOperation => "Object 0 is bound to buffer target",
                GLError::OutOfMemory => "Unable to create a large enough buffer",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ARRAY_BUFFER
    }
}

unsafe fn _draw_elements(mode: DrawingMode,
                         count: usize,
                         index_type: IndexDatumType,
                         indices: *const GLvoid)
{
    let gl_index_type: GLenum = match index_type {
        IndexDatumType::UnsignedByte => gl::UNSIGNED_BYTE,
        IndexDatumType::UnsignedShort => gl::UNSIGNED_SHORT
    };
    gl::DrawElements(mode.gl_enum(),
                     count as GLsizei,
                     gl_index_type,
                     indices);
    dbg_gl_error! {
        GLError::InvalidEnum => "`mode` or `type` is not an accepted value",
        GLError::InvalidValue => "`count` is negative",
        GLError::InvalidFramebufferOperation => "The current framebuffer is not framebuffer-complete",
        _ => "Unknown error"
    }
}

impl<'a> ArrayBufferBinding<'a> {
    pub unsafe fn vertex_attrib_pointer(&self,
                                        attrib: super::ProgramAttrib,
                                        components: i8,
                                        gl_type: super::DataType,
                                        normalized: bool,
                                        stride: usize,
                                        offset: usize)
    {
        debug_assert!(1 <= components && components <= 4);

        let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
        gl::VertexAttribPointer(attrib.gl_index,
                                components as GLint,
                                gl_type.gl_enum(),
                                gl_normalized,
                                stride as GLsizei,
                                offset as *const GLvoid);
        dbg_gl_error! {
            GLError::InvalidEnum => "Illegal vertex attribute type",
            GLError::InvalidValue => "`stride` is negative, `size` is not in range, or `index` is >= GL_MAX_VERTEX_ATTRIBS",
            GLError::InvalidFramebufferOperation => "Currently bound framebuffer is not framebuffer complete",
            _ => "Unknown error"
        }
    }
}

impl<'a> FramebufferBinding<'a> {
    pub unsafe fn draw_arrays_range(&mut self,
                                    _ab: &ArrayBufferBinding,
                                    mode: DrawingMode,
                                    first: u32,
                                    count: usize)
    {
        gl::DrawArrays(mode.gl_enum(), first as GLint, count as GLsizei);
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`mode` is not an accepted value",
            GLError::InvalidValue => "`count` is negative",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_n_elements_buffered(&mut self,
                                           _ab: &ArrayBufferBinding,
                                           _eab: &ElementArrayBufferBinding,
                                           mode: DrawingMode,
                                           count: usize,
                                           index_type: IndexDatumType)
    {
        _draw_elements(mode, count, index_type, ptr::null());
    }

    pub unsafe fn draw_n_elements<I>(&mut self,
                                     _ab: &ArrayBufferBinding,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        debug_assert!(count <= indices.len());

        let ptr = indices.index_bytes().as_ptr();
        let index_type = I::index_datum_type();
        _draw_elements(mode, count, index_type, mem::transmute(ptr));
    }

    pub unsafe fn draw_elements<I>(&mut self,
                                   _ab: &ArrayBufferBinding,
                                   mode: DrawingMode,
                                   indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        self.draw_n_elements(_ab, mode, indices.len(), indices);
    }
}

pub struct ElementArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ElementArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ELEMENT_ARRAY_BUFFER
    }
}

fn _bind_buffer(target: BufferBindingTarget, buffer: &mut Buffer) {
    unsafe {
        gl::BindBuffer(target as GLuint, buffer.gl_id());
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`target` is not an allowed value",
            _ => "Unknown error"
        }
    }
}

pub struct BufferBinderOf<A, E> {
    array: A,
    element_array: E
}

pub type BufferBinder = BufferBinderOf<ArrayBufferBinder,
                                       ElementArrayBufferBinder>;

pub type BufferBinderRef<'a> = BufferBinderOf<&'a ArrayBufferBinder,
                                              &'a ElementArrayBufferBinder>;

pub type BufferBinderMut<'a> = BufferBinderOf<&'a mut ArrayBufferBinder,
                                              &'a mut ElementArrayBufferBinder>;

impl<A, E> BufferBinderOf<A, E> {
    pub unsafe fn current() -> BufferBinder {
        BufferBinderOf {
            array: ArrayBufferBinder,
            element_array: ElementArrayBufferBinder
        }
    }

    pub fn borrowed<'a, BA = A, BE = E>(&'a self)
        -> BufferBinderOf<&'a BA, &'a BE>
        where A: Borrow<BA>,
              E: Borrow<BE>
    {
        BufferBinderOf {
            array: self.array.borrow(),
            element_array: self.element_array.borrow()
        }
    }

    pub fn borrowed_mut<'a, BA = A, BE = E>(&'a mut self)
        -> BufferBinderOf<&'a mut BA, &'a mut BE>
        where A: BorrowMut<BA>,
              E: BorrowMut<BE>
    {
        BufferBinderOf {
            array: self.array.borrow_mut(),
            element_array: self.element_array.borrow_mut()
        }
    }

    pub fn split_array(self) -> (A, BufferBinderOf<(), E>) {
        (
            self.array,
            BufferBinderOf {
                array: (),
                element_array: self.element_array
            }
        )
    }

    pub fn split_element_array(self) -> (E, BufferBinderOf<A, ()>) {
        (
            self.element_array,
            BufferBinderOf {
                array: self.array,
                element_array: ()
            }
        )
    }
}

impl<'a, A, E, AI, EI> RefInto<'a, BufferBinderOf<AI, EI>>
    for BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn ref_into(&'a self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> RefInto<'a, BufferBinderOf<AI, EI>>
    for &'a BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn ref_into(&'a self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for BufferBinderOf<A, E>
    where A: MutInto<'a, AI>,
          E: MutInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.mut_into(),
            element_array: self.element_array.mut_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for &'a BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for &'a mut BufferBinderOf<A, E>
    where A: MutInto<'a, AI>,
          E: MutInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.mut_into(),
            element_array: self.element_array.mut_into()
        }
    }
}

pub struct ArrayBufferBinder;
impl ArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer) -> ArrayBufferBinding<'a>
    {
        let binding = ArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}

pub struct ElementArrayBufferBinder;
impl ElementArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer)
        -> ElementArrayBufferBinding<'a>
    {
        let binding = ElementArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}
<commit_msg>Add `*BufferContext` impls for `&mut ContextOf<...>`<commit_after>use std::mem;
use std::ptr;
use std::marker::PhantomData;
use std::borrow::{Borrow, BorrowMut};
use gl;
use gl::types::*;
use ref_into::{RefInto, MutInto};
use context::ContextOf;
use framebuffer::FramebufferBinding;
use types::{DrawingMode, GLError};
use index_data::{IndexData, IndexDatum, IndexDatumType};

pub struct Buffer {
    gl_id: GLuint
}

impl Buffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenBuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Buffer { gl_id: id }
        }
    }
}

impl<BA, BE, F, P, R, T> ContextOf<BufferBinderOf<BA, BE>, F, P, R, T> {
    pub fn split_array_buffer(self)
        -> (BA, ContextOf<BufferBinderOf<(), BE>, F, P, R, T>)
    {
        let (buffers, gl) = self.split_buffers();
        let (ba_binder, rest_buffers) = buffers.split_array();

        (ba_binder, gl.join_buffers(rest_buffers))
    }

    pub fn split_element_array_buffer(self)
        -> (BE, ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>)
    {
        let (buffers, gl) = self.split_buffers();
        let (be_binder, rest_buffers) = buffers.split_element_array();
        (be_binder, gl.join_buffers(rest_buffers))
    }
}

pub trait ArrayBufferContext {
    type Rest;

    fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ArrayBufferBinding<'a>, Self::Rest);
}

pub trait ElementArrayBufferContext {
    type Rest;

    fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ElementArrayBufferBinding<'a>, Self::Rest);
}

impl<BA, BE, F, P, R, T> ArrayBufferContext
    for ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BA: BorrowMut<ArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<(), BE>, F, P, R, T>;

    fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ArrayBufferBinding<'a>, Self::Rest)
    {
        let (mut ba_binder, rest) = self.split_array_buffer();
        (ba_binder.borrow_mut().bind(buffer), rest)
    }
}

impl<'b, BA, BE, F, P, R, T> ArrayBufferContext
    for &'b mut ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BA: BorrowMut<ArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<(), &'b mut BE>,
                          &'b mut F,
                          &'b mut P,
                          &'b mut R,
                          &'b mut T>;

    fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ArrayBufferBinding<'a>, Self::Rest)
    {
        let gl = self.mut_into();
        let (ba_binder, rest): (&mut BA, _) = gl.split_array_buffer();
        (ba_binder.borrow_mut().bind(buffer), rest)
    }
}

impl<BA, BE, F, P, R, T> ElementArrayBufferContext
    for ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BE: BorrowMut<ElementArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>;

    fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ElementArrayBufferBinding<'a>, Self::Rest)
    {
        let (mut be_binder, rest) = self.split_element_array_buffer();
        (be_binder.borrow_mut().bind(buffer), rest)
    }
}

impl<'b, BA, BE, F, P, R, T> ElementArrayBufferContext
    for &'b mut ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BE: BorrowMut<ElementArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<&'b mut BA, ()>,
                          &'b mut F,
                          &'b mut P,
                          &'b mut R,
                          &'b mut T>;

    fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ElementArrayBufferBinding<'a>, Self::Rest)
    {
        let gl = self.mut_into();
        let (be_binder, rest): (&mut BE, _) = gl.split_element_array_buffer();
        (be_binder.borrow_mut().bind(buffer), rest)
    }
}

pub trait BufferContext: ArrayBufferContext + ElementArrayBufferContext {

}

impl<BA, BE, F, P, R, T> BufferContext
    for ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BA: BorrowMut<ArrayBufferBinder>,
          BE: BorrowMut<ElementArrayBufferBinder>
{

}

impl<'a, BA, BE, F, P, R, T> BufferContext
    for &'a mut ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BA: BorrowMut<ArrayBufferBinder>,
          BE: BorrowMut<ElementArrayBufferBinder>
{

}

gl_enum! {
    pub gl_enum BufferDataUsage {
        StreamDraw as STREAM_DRAW = gl::STREAM_DRAW,
        StaticDraw as STATIC_DRAW = gl::STATIC_DRAW,
        DynamicDraw as DYNAMIC_DRAW = gl::DYNAMIC_DRAW
    }
}

gl_enum! {
    pub gl_enum BufferBindingTarget {
        ArrayBuffer as ARRAY_BUFFER = gl::ARRAY_BUFFER,
        ElementArrayBuffer as ELEMENT_ARRAY_BUFFER = gl::ELEMENT_ARRAY_BUFFER
    }
}

pub trait BufferBinding {
    fn target(&self) -> BufferBindingTarget;

    fn buffer_bytes(&mut self, bytes: &[u8], usage: BufferDataUsage) {
        let ptr = bytes.as_ptr();
        let size = bytes.len() * mem::size_of::<u8>();
        unsafe {
            gl::BufferData(self.target().gl_enum(),
                           size as GLsizeiptr,
                           ptr as *const GLvoid,
                           usage.gl_enum());
            dbg_gl_error! {
                GLError::InvalidEnum => "Invalid `target` or `usage`",
                GLError::InvalidValue => "`size` is negative",
                GLError::InvalidOperation => "Object 0 is bound to buffer target",
                GLError::OutOfMemory => "Unable to create a large enough buffer",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ARRAY_BUFFER
    }
}

unsafe fn _draw_elements(mode: DrawingMode,
                         count: usize,
                         index_type: IndexDatumType,
                         indices: *const GLvoid)
{
    let gl_index_type: GLenum = match index_type {
        IndexDatumType::UnsignedByte => gl::UNSIGNED_BYTE,
        IndexDatumType::UnsignedShort => gl::UNSIGNED_SHORT
    };
    gl::DrawElements(mode.gl_enum(),
                     count as GLsizei,
                     gl_index_type,
                     indices);
    dbg_gl_error! {
        GLError::InvalidEnum => "`mode` or `type` is not an accepted value",
        GLError::InvalidValue => "`count` is negative",
        GLError::InvalidFramebufferOperation => "The current framebuffer is not framebuffer-complete",
        _ => "Unknown error"
    }
}

impl<'a> ArrayBufferBinding<'a> {
    pub unsafe fn vertex_attrib_pointer(&self,
                                        attrib: super::ProgramAttrib,
                                        components: i8,
                                        gl_type: super::DataType,
                                        normalized: bool,
                                        stride: usize,
                                        offset: usize)
    {
        debug_assert!(1 <= components && components <= 4);

        let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
        gl::VertexAttribPointer(attrib.gl_index,
                                components as GLint,
                                gl_type.gl_enum(),
                                gl_normalized,
                                stride as GLsizei,
                                offset as *const GLvoid);
        dbg_gl_error! {
            GLError::InvalidEnum => "Illegal vertex attribute type",
            GLError::InvalidValue => "`stride` is negative, `size` is not in range, or `index` is >= GL_MAX_VERTEX_ATTRIBS",
            GLError::InvalidFramebufferOperation => "Currently bound framebuffer is not framebuffer complete",
            _ => "Unknown error"
        }
    }
}

impl<'a> FramebufferBinding<'a> {
    pub unsafe fn draw_arrays_range(&mut self,
                                    _ab: &ArrayBufferBinding,
                                    mode: DrawingMode,
                                    first: u32,
                                    count: usize)
    {
        gl::DrawArrays(mode.gl_enum(), first as GLint, count as GLsizei);
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`mode` is not an accepted value",
            GLError::InvalidValue => "`count` is negative",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_n_elements_buffered(&mut self,
                                           _ab: &ArrayBufferBinding,
                                           _eab: &ElementArrayBufferBinding,
                                           mode: DrawingMode,
                                           count: usize,
                                           index_type: IndexDatumType)
    {
        _draw_elements(mode, count, index_type, ptr::null());
    }

    pub unsafe fn draw_n_elements<I>(&mut self,
                                     _ab: &ArrayBufferBinding,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        debug_assert!(count <= indices.len());

        let ptr = indices.index_bytes().as_ptr();
        let index_type = I::index_datum_type();
        _draw_elements(mode, count, index_type, mem::transmute(ptr));
    }

    pub unsafe fn draw_elements<I>(&mut self,
                                   _ab: &ArrayBufferBinding,
                                   mode: DrawingMode,
                                   indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        self.draw_n_elements(_ab, mode, indices.len(), indices);
    }
}

pub struct ElementArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ElementArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ELEMENT_ARRAY_BUFFER
    }
}

fn _bind_buffer(target: BufferBindingTarget, buffer: &mut Buffer) {
    unsafe {
        gl::BindBuffer(target as GLuint, buffer.gl_id());
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`target` is not an allowed value",
            _ => "Unknown error"
        }
    }
}

pub struct BufferBinderOf<A, E> {
    array: A,
    element_array: E
}

pub type BufferBinder = BufferBinderOf<ArrayBufferBinder,
                                       ElementArrayBufferBinder>;

pub type BufferBinderRef<'a> = BufferBinderOf<&'a ArrayBufferBinder,
                                              &'a ElementArrayBufferBinder>;

pub type BufferBinderMut<'a> = BufferBinderOf<&'a mut ArrayBufferBinder,
                                              &'a mut ElementArrayBufferBinder>;

impl<A, E> BufferBinderOf<A, E> {
    pub unsafe fn current() -> BufferBinder {
        BufferBinderOf {
            array: ArrayBufferBinder,
            element_array: ElementArrayBufferBinder
        }
    }

    pub fn borrowed<'a, BA = A, BE = E>(&'a self)
        -> BufferBinderOf<&'a BA, &'a BE>
        where A: Borrow<BA>,
              E: Borrow<BE>
    {
        BufferBinderOf {
            array: self.array.borrow(),
            element_array: self.element_array.borrow()
        }
    }

    pub fn borrowed_mut<'a, BA = A, BE = E>(&'a mut self)
        -> BufferBinderOf<&'a mut BA, &'a mut BE>
        where A: BorrowMut<BA>,
              E: BorrowMut<BE>
    {
        BufferBinderOf {
            array: self.array.borrow_mut(),
            element_array: self.element_array.borrow_mut()
        }
    }

    pub fn split_array(self) -> (A, BufferBinderOf<(), E>) {
        (
            self.array,
            BufferBinderOf {
                array: (),
                element_array: self.element_array
            }
        )
    }

    pub fn split_element_array(self) -> (E, BufferBinderOf<A, ()>) {
        (
            self.element_array,
            BufferBinderOf {
                array: self.array,
                element_array: ()
            }
        )
    }
}

impl<'a, A, E, AI, EI> RefInto<'a, BufferBinderOf<AI, EI>>
    for BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn ref_into(&'a self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> RefInto<'a, BufferBinderOf<AI, EI>>
    for &'a BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn ref_into(&'a self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for BufferBinderOf<A, E>
    where A: MutInto<'a, AI>,
          E: MutInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.mut_into(),
            element_array: self.element_array.mut_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for &'a BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for &'a mut BufferBinderOf<A, E>
    where A: MutInto<'a, AI>,
          E: MutInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.mut_into(),
            element_array: self.element_array.mut_into()
        }
    }
}

pub struct ArrayBufferBinder;
impl ArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer) -> ArrayBufferBinding<'a>
    {
        let binding = ArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}

pub struct ElementArrayBufferBinder;
impl ElementArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer)
        -> ElementArrayBufferBinding<'a>
    {
        let binding = ElementArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}
<|endoftext|>


<commit_before>use std::f32::consts;
use std::ops::{Add, Div, Mul, Sub};
use nalgebra::{UnitQuaternion, Vector2, Vector3, Vector4};

/// Time used as sampling type in splines.
pub type Time = f32;

/// A spline control point.
///
/// This type associates a value at a given type. It also contains an interpolation object used to
/// determine how to interpolate values on the segment defined by this key and the next one.
#[derive(Copy, Clone, Debug)]
pub struct Key<T> {
  /// Time at which the `Key` should be reached.
  pub t: Time,
  /// Actual value.
  pub value: T,
  /// Interpolation mode.
  pub interpolation: Interpolation
}

impl<T> Key<T> {
  pub fn new(t: Time, value: T, interpolation: Interpolation) -> Self {
    Key {
      t: t,
      value: value,
      interpolation: interpolation
    }
  }
}

/// Interpolation mode.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub enum Interpolation {
  /// Hold a `Key` until the time passes the normalized step threshold, in which case the next
  /// key is used.
  ///
  /// *Note: if you set the threshold to `0.5`, the first key will be used until the time is half
  /// between the two keys; the second key will be in used afterwards. If you set it to `1.0`, the
  /// first key will be kept until the next key.*
  Step(f32),
  /// Linear interpolation between a key and the next one.
  Linear,
  /// Cosine interpolation between a key and the next one.
  Cosine,
  /// Catmull-Rom interpolation.
  CatmullRom
}

/// Spline curve used to provide interpolation between control points (keys).
#[derive(Debug)]
pub struct Spline<T> {
  keys: Vec<Key<T>>,
}

impl<T> Spline<T> {
  pub fn new(mut cps: Vec<Key<T>>) -> Self {
    cps.sort_by(|k0, k1| k0.t.partial_cmp(&k1.t).unwrap());

    Spline {
      keys: cps
    }
  }
}

pub struct SplineIterator<'a, T> where T: 'a {
  anim_param: &'a Spline<T>,
  i: usize
}

impl<'a, T> Iterator for SplineIterator<'a, T> {
  type Item = &'a Key<T>;

  fn next(&mut self) -> Option<Self::Item> {
    let r = self.anim_param.keys.get(self.i);

    if let Some(_) = r {
      self.i += 1;
    }

    r
  }
}

impl<'a, T> IntoIterator for &'a Spline<T> {
  type Item = &'a Key<T>;
  type IntoIter = SplineIterator<'a, T>;

  fn into_iter(self) -> Self::IntoIter {
    SplineIterator {
      anim_param: self,
      i: 0
    }
  }
}

/// Implement this trait if your type is a key you want to sample with.
pub trait Interpolate: Copy {
  /// Linear interpolation.
  fn lerp(a: Self, b: Self, t: Time) -> Self;
  /// Cubic hermite interpolation.
  fn cubic_hermite(_: (Self, Time), a: (Self, Time), b: (Self, Time), _: (Self, Time), t: Time) -> Self {
    Self::lerp(a.0, b.0, t)
  }
}

impl Interpolate for f32 {
  fn lerp(a: Self, b: Self, t: Time) -> Self {
    lerp(a, b, t)
  }

  fn cubic_hermite(x: (Self, Time), a: (Self, Time), b: (Self, Time), y: (Self, Time), t: Time) -> Self {
    cubic_hermite(x, a, b, y, t)
  }
}

impl Interpolate for Vector2<f32> {
  fn lerp(a: Self, b: Self, t: Time) -> Self {
    lerp(a, b, t)
  }

  fn cubic_hermite(x: (Self, Time), a: (Self, Time), b: (Self, Time), y: (Self, Time), t: Time) -> Self {
    cubic_hermite(x, a, b, y, t)
  }
}

impl Interpolate for Vector3<f32> {
  fn lerp(a: Self, b: Self, t: Time) -> Self {
    lerp(a, b, t)
  }

  fn cubic_hermite(x: (Self, Time), a: (Self, Time), b: (Self, Time), y: (Self, Time), t: Time) -> Self {
    cubic_hermite(x, a, b, y, t)
  }
}

impl Interpolate for Vector4<f32> {
  fn lerp(a: Self, b: Self, t: Time) -> Self {
    lerp(a, b, t)
  }

  fn cubic_hermite(x: (Self, Time), a: (Self, Time), b: (Self, Time), y: (Self, Time), t: Time) -> Self {
    cubic_hermite(x, a, b, y, t)
  }
}

impl Interpolate for UnitQuaternion<f32> {
  fn lerp(a: Self, b: Self, t: Time) -> Self {
    a * UnitQuaternion::new(&(UnitQuaternion::new(&a.quaternion().conjugate()) * b).quaternion().powf(t))
  }
}

// Default implementation of Interpolate::lerp.
fn lerp<T>(a: T, b: T, t: Time) -> T where T: Add<Output = T> + Mul<Time, Output = T> {
  a * (1. - t) + b * t
}

// Default implementation of Interpolate::cubic_hermit.

fn cubic_hermite<T>(x: (T, Time), a: (T, Time), b: (T, Time), y: (T, Time), t: Time) -> T
    where T: Copy + Add<Output = T> + Sub<Output = T> + Mul<Time, Output = T> + Div<Time, Output = T> {
  // time stuff
  let t2 = t * t;
  let t3 = t2 * t;
  let two_t3 = 2. * t3;
  let three_t2 = 3. * t2;

  // tangents
  let m0 = (b.0 - x.0) / (b.1 - x.1);
	let m1 = (y.0 - a.0) / (y.1 - a.1);

  a.0 * (two_t3 - three_t2 + 1.) + m0 * (t3 - 2. * t2 + t) + b.0 * (-two_t3 + three_t2) + m1 * (t3 - t2)
}

/// Samplers can sample `Spline` by providing a `Time`. They should be mutable so that they can
/// maintain an internal state for optimization purposes.
#[derive(Default)]
pub struct Sampler {
  /// Playback cursor – gives the lower control point index of the current portion of the curve
  /// we’re sampling at.
  cursor: usize
}

impl Sampler {
  pub fn new() -> Self {
    Sampler {
      cursor: 0
    }
  }

  /// Sample a spline. If `random_sampling` is set, random sampling is generally faster than
  /// continuous sampling. Though, if you use continuous sampling, set `random_sampling` to `false`
	/// for max speed performance.
  pub fn sample<T>(&mut self, t: Time, param: &Spline<T>, random_sampling: bool) -> Option<T>
      where T: Interpolate {
    let i = if random_sampling {
      binary_search_lower_cp(&param.keys, t)
    } else {
      let i = around_search_lower_cp(&param.keys, self.cursor, t);

      // if we’ve found the index, replace the cursor to speed up next searches
      if let Some(cursor) = i {
        self.cursor = cursor;
      }

      i
    };

    let i = match i {
      Some(i) => i,
      None => return None
    };

    let cp0 = &param.keys[i];

    match cp0.interpolation {
      Interpolation::Step(threshold) => {
        let cp1 = &param.keys[i+1];
        Some(if t < threshold { cp0.value } else { cp1.value })
      },
      Interpolation::Linear => {
        let cp1 = &param.keys[i+1];
        let nt = normalize_time(t, cp0, cp1);

        Some(Interpolate::lerp(cp0.value, cp1.value, nt))
      },
      Interpolation::Cosine => {
        let cp1 = &param.keys[i+1];
        let nt = normalize_time(t, cp0, cp1);
        let cos_nt = (1. - f32::cos(nt * consts::PI)) * 0.5;

        Some(Interpolate::lerp(cp0.value, cp1.value, cos_nt))
      },
      Interpolation::CatmullRom => {
        // We need at least four points for Catmull Rom; ensure we have them, otherwise, return
        // None.
        if i == 0 || i >= param.keys.len() - 2 {
          None
        } else {
          let cp1 = &param.keys[i+1];
          let cpm0 = &param.keys[i-1];
          let cpm1 = &param.keys[i+2];
          let nt = normalize_time(t, cp0, cp1);

          Some(Interpolate::cubic_hermite((cpm0.value, cpm0.t), (cp0.value, cp0.t), (cp1.value, cp1.t), (cpm1.value, cpm1.t), nt))
        }
      }
    }
  }
}

// Normalize a time ([0;1]) given two control points.
fn normalize_time<T>(t: Time, cp: &Key<T>, cp1: &Key<T>) -> Time {
  (t - cp.t) / (cp1.t - cp.t)
}

// Find the lower control point corresponding to a given time. Random version.
fn binary_search_lower_cp<T>(cps: &[Key<T>], t: Time) -> Option<usize> {
  let len = cps.len() as i32;
  if len < 2 {
    return None;
  }

  let mut down = 0;
  let mut up = len - 1;

  while down <= up {
    let m = (up + down) / 2;
    if m < 0 || m >= len - 1 {
      return None;
    }

    let cp0 = &cps[m as usize];

    if cp0.t > t {
      up = m-1;
    } else {
      let cp1 = &cps[(m+1) as usize];

      if t >= cp1.t {
        down = m+1;
      } else {
        return Some(m as usize)
      }
    }
  }

  None
}

// Find the lower control point corresponding to a given time. Continuous version. `i` is the last
// known found index.
fn around_search_lower_cp<T>(cps: &[Key<T>], mut i: usize, t: Time) -> Option<usize> {
  let len = cps.len();

  if len < 2 {
    return None;
  }

  loop {
    let cp = &cps[i];
    let cp1 = &cps[i+1];

    if t >= cp1.t {
      if i >= len - 2 {
        return None;
      }

      i += 1;
    } else if t < cp.t {
      if i == 0 {
        return None;
      }

      i -= 1;
    } else {
      break; // found
    }
  }

  Some(i)
}
<commit_msg>serde_json impl for spline stuff.<commit_after>use std::f32::consts;
use std::ops::{Add, Div, Mul, Sub};
use nalgebra::{UnitQuaternion, Vector2, Vector3, Vector4};

pub use serde_json::ser::to_string;

/// Time used as sampling type in splines.
pub type Time = f32;

/// A spline control point.
///
/// This type associates a value at a given type. It also contains an interpolation object used to
/// determine how to interpolate values on the segment defined by this key and the next one.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub struct Key<T> {
  /// Time at which the `Key` should be reached.
  pub t: Time,
  /// Actual value.
  pub value: T,
  /// Interpolation mode.
  pub interpolation: Interpolation
}

impl<T> Key<T> {
  pub fn new(t: Time, value: T, interpolation: Interpolation) -> Self {
    Key {
      t: t,
      value: value,
      interpolation: interpolation
    }
  }
}

/// Interpolation mode.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub enum Interpolation {
  /// Hold a `Key` until the time passes the normalized step threshold, in which case the next
  /// key is used.
  ///
  /// *Note: if you set the threshold to `0.5`, the first key will be used until the time is half
  /// between the two keys; the second key will be in used afterwards. If you set it to `1.0`, the
  /// first key will be kept until the next key.*
  #[serde(rename = "step")]
  Step(f32),
  /// Linear interpolation between a key and the next one.
  #[serde(rename = "linear")]
  Linear,
  /// Cosine interpolation between a key and the next one.
  #[serde(rename = "cosine")]
  Cosine,
  /// Catmull-Rom interpolation.
  #[serde(rename = "catmull_rom")]
  CatmullRom
}

/// Spline curve used to provide interpolation between control points (keys).
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Spline<T> {
  keys: Vec<Key<T>>,
}

impl<T> Spline<T> {
  pub fn new(mut cps: Vec<Key<T>>) -> Self {
    cps.sort_by(|k0, k1| k0.t.partial_cmp(&k1.t).unwrap());

    Spline {
      keys: cps
    }
  }
}

pub struct SplineIterator<'a, T> where T: 'a {
  anim_param: &'a Spline<T>,
  i: usize
}

impl<'a, T> Iterator for SplineIterator<'a, T> {
  type Item = &'a Key<T>;

  fn next(&mut self) -> Option<Self::Item> {
    let r = self.anim_param.keys.get(self.i);

    if let Some(_) = r {
      self.i += 1;
    }

    r
  }
}

impl<'a, T> IntoIterator for &'a Spline<T> {
  type Item = &'a Key<T>;
  type IntoIter = SplineIterator<'a, T>;

  fn into_iter(self) -> Self::IntoIter {
    SplineIterator {
      anim_param: self,
      i: 0
    }
  }
}

/// Implement this trait if your type is a key you want to sample with.
pub trait Interpolate: Copy {
  /// Linear interpolation.
  fn lerp(a: Self, b: Self, t: Time) -> Self;
  /// Cubic hermite interpolation.
  fn cubic_hermite(_: (Self, Time), a: (Self, Time), b: (Self, Time), _: (Self, Time), t: Time) -> Self {
    Self::lerp(a.0, b.0, t)
  }
}

impl Interpolate for f32 {
  fn lerp(a: Self, b: Self, t: Time) -> Self {
    lerp(a, b, t)
  }

  fn cubic_hermite(x: (Self, Time), a: (Self, Time), b: (Self, Time), y: (Self, Time), t: Time) -> Self {
    cubic_hermite(x, a, b, y, t)
  }
}

impl Interpolate for Vector2<f32> {
  fn lerp(a: Self, b: Self, t: Time) -> Self {
    lerp(a, b, t)
  }

  fn cubic_hermite(x: (Self, Time), a: (Self, Time), b: (Self, Time), y: (Self, Time), t: Time) -> Self {
    cubic_hermite(x, a, b, y, t)
  }
}

impl Interpolate for Vector3<f32> {
  fn lerp(a: Self, b: Self, t: Time) -> Self {
    lerp(a, b, t)
  }

  fn cubic_hermite(x: (Self, Time), a: (Self, Time), b: (Self, Time), y: (Self, Time), t: Time) -> Self {
    cubic_hermite(x, a, b, y, t)
  }
}

impl Interpolate for Vector4<f32> {
  fn lerp(a: Self, b: Self, t: Time) -> Self {
    lerp(a, b, t)
  }

  fn cubic_hermite(x: (Self, Time), a: (Self, Time), b: (Self, Time), y: (Self, Time), t: Time) -> Self {
    cubic_hermite(x, a, b, y, t)
  }
}

impl Interpolate for UnitQuaternion<f32> {
  fn lerp(a: Self, b: Self, t: Time) -> Self {
    a * UnitQuaternion::new(&(UnitQuaternion::new(&a.quaternion().conjugate()) * b).quaternion().powf(t))
  }
}

// Default implementation of Interpolate::lerp.
fn lerp<T>(a: T, b: T, t: Time) -> T where T: Add<Output = T> + Mul<Time, Output = T> {
  a * (1. - t) + b * t
}

// Default implementation of Interpolate::cubic_hermit.

fn cubic_hermite<T>(x: (T, Time), a: (T, Time), b: (T, Time), y: (T, Time), t: Time) -> T
    where T: Copy + Add<Output = T> + Sub<Output = T> + Mul<Time, Output = T> + Div<Time, Output = T> {
  // time stuff
  let t2 = t * t;
  let t3 = t2 * t;
  let two_t3 = 2. * t3;
  let three_t2 = 3. * t2;

  // tangents
  let m0 = (b.0 - x.0) / (b.1 - x.1);
	let m1 = (y.0 - a.0) / (y.1 - a.1);

  a.0 * (two_t3 - three_t2 + 1.) + m0 * (t3 - 2. * t2 + t) + b.0 * (-two_t3 + three_t2) + m1 * (t3 - t2)
}

/// Samplers can sample `Spline` by providing a `Time`. They should be mutable so that they can
/// maintain an internal state for optimization purposes.
#[derive(Copy, Clone, Default)]
pub struct Sampler {
  /// Playback cursor – gives the lower control point index of the current portion of the curve
  /// we’re sampling at.
  cursor: usize
}

impl Sampler {
  pub fn new() -> Self {
    Sampler {
      cursor: 0
    }
  }

  /// Sample a spline. If `random_sampling` is set, random sampling is generally faster than
  /// continuous sampling. Though, if you use continuous sampling, set `random_sampling` to `false`
	/// for max speed performance.
  pub fn sample<T>(&mut self, t: Time, param: &Spline<T>, random_sampling: bool) -> Option<T>
      where T: Interpolate {
    let i = if random_sampling {
      binary_search_lower_cp(&param.keys, t)
    } else {
      let i = around_search_lower_cp(&param.keys, self.cursor, t);

      // if we’ve found the index, replace the cursor to speed up next searches
      if let Some(cursor) = i {
        self.cursor = cursor;
      }

      i
    };

    let i = match i {
      Some(i) => i,
      None => return None
    };

    let cp0 = &param.keys[i];

    match cp0.interpolation {
      Interpolation::Step(threshold) => {
        let cp1 = &param.keys[i+1];
        Some(if t < threshold { cp0.value } else { cp1.value })
      },
      Interpolation::Linear => {
        let cp1 = &param.keys[i+1];
        let nt = normalize_time(t, cp0, cp1);

        Some(Interpolate::lerp(cp0.value, cp1.value, nt))
      },
      Interpolation::Cosine => {
        let cp1 = &param.keys[i+1];
        let nt = normalize_time(t, cp0, cp1);
        let cos_nt = (1. - f32::cos(nt * consts::PI)) * 0.5;

        Some(Interpolate::lerp(cp0.value, cp1.value, cos_nt))
      },
      Interpolation::CatmullRom => {
        // We need at least four points for Catmull Rom; ensure we have them, otherwise, return
        // None.
        if i == 0 || i >= param.keys.len() - 2 {
          None
        } else {
          let cp1 = &param.keys[i+1];
          let cpm0 = &param.keys[i-1];
          let cpm1 = &param.keys[i+2];
          let nt = normalize_time(t, cp0, cp1);

          Some(Interpolate::cubic_hermite((cpm0.value, cpm0.t), (cp0.value, cp0.t), (cp1.value, cp1.t), (cpm1.value, cpm1.t), nt))
        }
      }
    }
  }
}

// Normalize a time ([0;1]) given two control points.
fn normalize_time<T>(t: Time, cp: &Key<T>, cp1: &Key<T>) -> Time {
  (t - cp.t) / (cp1.t - cp.t)
}

// Find the lower control point corresponding to a given time. Random version.
fn binary_search_lower_cp<T>(cps: &[Key<T>], t: Time) -> Option<usize> {
  let len = cps.len() as i32;
  if len < 2 {
    return None;
  }

  let mut down = 0;
  let mut up = len - 1;

  while down <= up {
    let m = (up + down) / 2;
    if m < 0 || m >= len - 1 {
      return None;
    }

    let cp0 = &cps[m as usize];

    if cp0.t > t {
      up = m-1;
    } else {
      let cp1 = &cps[(m+1) as usize];

      if t >= cp1.t {
        down = m+1;
      } else {
        return Some(m as usize)
      }
    }
  }

  None
}

// Find the lower control point corresponding to a given time. Continuous version. `i` is the last
// known found index.
fn around_search_lower_cp<T>(cps: &[Key<T>], mut i: usize, t: Time) -> Option<usize> {
  let len = cps.len();

  if len < 2 {
    return None;
  }

  loop {
    let cp = &cps[i];
    let cp1 = &cps[i+1];

    if t >= cp1.t {
      if i >= len - 2 {
        return None;
      }

      i += 1;
    } else if t < cp.t {
      if i == 0 {
        return None;
      }

      i -= 1;
    } else {
      break; // found
    }
  }

  Some(i)
}
<|endoftext|>


<commit_before>use crate::Color;
use std::fmt;
use std::iter;

const ASCII_1: u8 = b'1';
const ASCII_9: u8 = b'9';
const ASCII_LOWER_A: u8 = b'a';
const ASCII_LOWER_I: u8 = b'i';

/// Represents a position of each cell in the game board.
///
/// # Examples
///
/// ```
/// use shogi::Square;
///
/// let sq = Square::new(4, 4).unwrap();
/// assert_eq!("5e", sq.to_string());
/// ```
///
/// `Square` can be created by parsing a SFEN formatted string as well.
///
/// ```
/// use shogi::Square;
///
/// let sq = Square::from_sfen("5e").unwrap();
/// assert_eq!(4, sq.file());
/// assert_eq!(4, sq.rank());
/// ```
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct Square {
    inner: u8,
}

impl Square {
    /// Creates a new instance of `Square`.
    ///
    /// `file` can take a value from 0('1') to 8('9'), while `rank` is from 0('a') to 9('i').
    pub fn new(file: u8, rank: u8) -> Option<Square> {
        if file > 8 || rank > 8 {
            return None;
        }

        Some(Square {
            inner: file * 9 + rank,
        })
    }

    /// Creates a new instance of `Square` from SFEN formatted string.
    pub fn from_sfen(s: &str) -> Option<Square> {
        let bytes: &[u8] = s.as_bytes();

        if bytes.len() != 2
            || bytes[0] < ASCII_1
            || bytes[0] > ASCII_9
            || bytes[1] < ASCII_LOWER_A
            || bytes[1] > ASCII_LOWER_I
        {
            return None;
        }

        let file = bytes[0] - ASCII_1;
        let rank = bytes[1] - ASCII_LOWER_A;

        debug_assert!(
            file < 9 && rank < 9,
            "{} parsed as (file: {}, rank: {})",
            s,
            file,
            rank
        );

        Some(Square {
            inner: file * 9 + rank,
        })
    }

    /// Creates a new instance of `Square` with the given index value.
    pub fn from_index(index: u8) -> Option<Square> {
        if index >= 81 {
            return None;
        }

        Some(Square { inner: index })
    }

    /// Returns an iterator of all variants.
    pub fn iter() -> SquareIter {
        SquareIter { current: 0 }
    }

    /// Returns a file of the square.
    pub fn file(self) -> u8 {
        self.inner / 9
    }

    /// Returns a rank of the square.
    pub fn rank(self) -> u8 {
        self.inner % 9
    }

    /// Returns a new `Square` instance by moving the file and the rank values.
    ///
    /// # Examples
    ///
    /// ```
    /// use shogi::square::consts::*;
    ///
    /// let sq = SQ_2B;
    /// let shifted = sq.shift(2, 3).unwrap();
    ///
    /// assert_eq!(3, shifted.file());
    /// assert_eq!(4, shifted.rank());
    /// ```
    pub fn shift(self, df: i8, dr: i8) -> Option<Square> {
        let f = self.file() as i8 + df;
        let r = self.rank() as i8 + dr;

        if f < 0 || f > 8 || r < 0 || r > 8 {
            return None;
        }

        Some(Square {
            inner: (f * 9 + r) as u8,
        })
    }

    /// Returns a relative rank as if the specified color is black.
    ///
    /// # Examples
    ///
    /// ```
    /// use shogi::Color;
    /// use shogi::square::consts::*;
    ///
    /// let sq = SQ_1G;
    ///
    /// assert_eq!(6, sq.relative_rank(Color::Black));
    /// assert_eq!(2, sq.relative_rank(Color::White));
    /// ```
    pub fn relative_rank(self, c: Color) -> u8 {
        if c == Color::Black {
            self.rank()
        } else {
            8 - self.rank()
        }
    }

    /// Tests if the square is in a promotion zone.
    pub fn in_promotion_zone(self, c: Color) -> bool {
        self.relative_rank(c) < 3
    }

    /// Converts the instance into the unique number for array indexing purpose.
    #[inline(always)]
    pub fn index(self) -> usize {
        self.inner as usize
    }
}

impl fmt::Display for Square {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        debug_assert!(
            self.file() < 9 && self.rank() < 9,
            "trying to stringify an invalid square: {:?}",
            self
        );
        write!(
            f,
            "{}{}",
            (self.file() + ASCII_1) as char,
            (self.rank() + ASCII_LOWER_A) as char
        )
    }
}

pub mod consts {
    use super::Square;

    macro_rules! make_square {
        {0, $t:ident $($ts:ident)+} => {
            pub const $t: Square = Square { inner: 0 };
            make_square!{1, $($ts)*}
        };
        {$n:expr, $t:ident $($ts:ident)+} => {
            pub const $t: Square = Square { inner: $n };
            make_square!{($n + 1), $($ts)*}
        };
        {$n:expr, $t:ident} => {
            pub const $t: Square = Square { inner: $n };
        };
    }

    make_square! {0, SQ_1A SQ_1B SQ_1C SQ_1D SQ_1E SQ_1F SQ_1G SQ_1H SQ_1I
    SQ_2A SQ_2B SQ_2C SQ_2D SQ_2E SQ_2F SQ_2G SQ_2H SQ_2I
    SQ_3A SQ_3B SQ_3C SQ_3D SQ_3E SQ_3F SQ_3G SQ_3H SQ_3I
    SQ_4A SQ_4B SQ_4C SQ_4D SQ_4E SQ_4F SQ_4G SQ_4H SQ_4I
    SQ_5A SQ_5B SQ_5C SQ_5D SQ_5E SQ_5F SQ_5G SQ_5H SQ_5I
    SQ_6A SQ_6B SQ_6C SQ_6D SQ_6E SQ_6F SQ_6G SQ_6H SQ_6I
    SQ_7A SQ_7B SQ_7C SQ_7D SQ_7E SQ_7F SQ_7G SQ_7H SQ_7I
    SQ_8A SQ_8B SQ_8C SQ_8D SQ_8E SQ_8F SQ_8G SQ_8H SQ_8I
    SQ_9A SQ_9B SQ_9C SQ_9D SQ_9E SQ_9F SQ_9G SQ_9H SQ_9I}
}

/// This struct is created by the [`iter`] method on [`Square`].
///
/// [`iter`]: ./struct.Square.html#method.iter
/// [`Square`]: struct.Square.html
pub struct SquareIter {
    current: u8,
}

impl iter::Iterator for SquareIter {
    type Item = Square;

    fn next(&mut self) -> Option<Self::Item> {
        let cur = self.current;

        if cur >= 81 {
            return None;
        }

        self.current += 1;

        Some(Square { inner: cur })
    }
}

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

    #[test]
    fn new() {
        for file in 0..9 {
            for rank in 0..9 {
                let sq = Square::new(file, rank).unwrap();
                assert_eq!(file, sq.file());
                assert_eq!(rank, sq.rank());
            }
        }

        assert_eq!(None, Square::new(10, 0));
        assert_eq!(None, Square::new(0, 10));
        assert_eq!(None, Square::new(10, 10));
    }

    #[test]
    fn from_sfen() {
        let ok_cases = [
            ("9a", 8, 0),
            ("1a", 0, 0),
            ("5e", 4, 4),
            ("9i", 8, 8),
            ("1i", 0, 8),
        ];
        let ng_cases = ["", "9j", "_a", "a9", "9 ", " a", "9", "foo"];

        for case in ok_cases.iter() {
            let sq = Square::from_sfen(case.0);
            assert!(sq.is_some());
            assert_eq!(case.1, sq.unwrap().file());
            assert_eq!(case.2, sq.unwrap().rank());
        }

        for case in ng_cases.iter() {
            assert!(
                Square::from_sfen(case).is_none(),
                "{} should cause an error",
                case
            );
        }
    }

    #[test]
    fn from_index() {
        for i in 0..81 {
            assert!(Square::from_index(i).is_some());
        }

        assert!(Square::from_index(82).is_none());
    }

    #[test]
    fn to_sfen() {
        let cases = [
            ("9a", 8, 0),
            ("1a", 0, 0),
            ("5e", 4, 4),
            ("9i", 8, 8),
            ("1i", 0, 8),
        ];

        for case in cases.iter() {
            let sq = Square::new(case.1, case.2).unwrap();
            assert_eq!(case.0, sq.to_string());
        }
    }

    #[test]
    fn shift() {
        let sq = consts::SQ_5E;

        let ok_cases = [
            (-4, -4, 0, 0),
            (-4, 0, 0, 4),
            (0, -4, 4, 0),
            (0, 0, 4, 4),
            (4, 0, 8, 4),
            (0, 4, 4, 8),
            (4, 4, 8, 8),
        ];

        let ng_cases = [(-5, -4), (-4, -5), (5, 0), (0, 5)];

        for case in ok_cases.iter() {
            let shifted = sq.shift(case.0, case.1).unwrap();
            assert_eq!(case.2, shifted.file());
            assert_eq!(case.3, shifted.rank());
        }

        for case in ng_cases.iter() {
            assert!(sq.shift(case.0, case.1).is_none());
        }
    }

    #[test]
    fn relative_rank() {
        let cases = [
            (0, 0, 0, 8),
            (0, 1, 1, 7),
            (0, 2, 2, 6),
            (0, 3, 3, 5),
            (0, 4, 4, 4),
            (0, 5, 5, 3),
            (0, 6, 6, 2),
            (0, 7, 7, 1),
            (0, 8, 8, 0),
        ];

        for case in cases.iter() {
            let sq = Square::new(case.0, case.1).unwrap();
            assert_eq!(case.2, sq.relative_rank(Color::Black));
            assert_eq!(case.3, sq.relative_rank(Color::White));
        }
    }

    #[test]
    fn in_promotion_zone() {
        let cases = [
            (0, 0, true, false),
            (0, 1, true, false),
            (0, 2, true, false),
            (0, 3, false, false),
            (0, 4, false, false),
            (0, 5, false, false),
            (0, 6, false, true),
            (0, 7, false, true),
            (0, 8, false, true),
        ];

        for case in cases.iter() {
            let sq = Square::new(case.0, case.1).unwrap();
            assert_eq!(case.2, sq.in_promotion_zone(Color::Black));
            assert_eq!(case.3, sq.in_promotion_zone(Color::White));
        }
    }

    #[test]
    fn consts() {
        for (i, sq) in Square::iter().enumerate() {
            assert_eq!((i / 9) as u8, sq.file());
            assert_eq!((i % 9) as u8, sq.rank());
        }
    }
}
<commit_msg>fix: use range expressions<commit_after>use crate::Color;
use std::fmt;
use std::iter;

const ASCII_1: u8 = b'1';
const ASCII_9: u8 = b'9';
const ASCII_LOWER_A: u8 = b'a';
const ASCII_LOWER_I: u8 = b'i';

/// Represents a position of each cell in the game board.
///
/// # Examples
///
/// ```
/// use shogi::Square;
///
/// let sq = Square::new(4, 4).unwrap();
/// assert_eq!("5e", sq.to_string());
/// ```
///
/// `Square` can be created by parsing a SFEN formatted string as well.
///
/// ```
/// use shogi::Square;
///
/// let sq = Square::from_sfen("5e").unwrap();
/// assert_eq!(4, sq.file());
/// assert_eq!(4, sq.rank());
/// ```
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct Square {
    inner: u8,
}

impl Square {
    /// Creates a new instance of `Square`.
    ///
    /// `file` can take a value from 0('1') to 8('9'), while `rank` is from 0('a') to 9('i').
    pub fn new(file: u8, rank: u8) -> Option<Square> {
        if file > 8 || rank > 8 {
            return None;
        }

        Some(Square {
            inner: file * 9 + rank,
        })
    }

    /// Creates a new instance of `Square` from SFEN formatted string.
    pub fn from_sfen(s: &str) -> Option<Square> {
        let bytes: &[u8] = s.as_bytes();

        if bytes.len() != 2
            || bytes[0] < ASCII_1
            || bytes[0] > ASCII_9
            || bytes[1] < ASCII_LOWER_A
            || bytes[1] > ASCII_LOWER_I
        {
            return None;
        }

        let file = bytes[0] - ASCII_1;
        let rank = bytes[1] - ASCII_LOWER_A;

        debug_assert!(
            file < 9 && rank < 9,
            "{} parsed as (file: {}, rank: {})",
            s,
            file,
            rank
        );

        Some(Square {
            inner: file * 9 + rank,
        })
    }

    /// Creates a new instance of `Square` with the given index value.
    pub fn from_index(index: u8) -> Option<Square> {
        if index >= 81 {
            return None;
        }

        Some(Square { inner: index })
    }

    /// Returns an iterator of all variants.
    pub fn iter() -> SquareIter {
        SquareIter { current: 0 }
    }

    /// Returns a file of the square.
    pub fn file(self) -> u8 {
        self.inner / 9
    }

    /// Returns a rank of the square.
    pub fn rank(self) -> u8 {
        self.inner % 9
    }

    /// Returns a new `Square` instance by moving the file and the rank values.
    ///
    /// # Examples
    ///
    /// ```
    /// use shogi::square::consts::*;
    ///
    /// let sq = SQ_2B;
    /// let shifted = sq.shift(2, 3).unwrap();
    ///
    /// assert_eq!(3, shifted.file());
    /// assert_eq!(4, shifted.rank());
    /// ```
    pub fn shift(self, df: i8, dr: i8) -> Option<Square> {
        let f = self.file() as i8 + df;
        let r = self.rank() as i8 + dr;

        if !(0..9).contains(&f) || !(0..9).contains(&r) {
            return None;
        }

        Some(Square {
            inner: (f * 9 + r) as u8,
        })
    }

    /// Returns a relative rank as if the specified color is black.
    ///
    /// # Examples
    ///
    /// ```
    /// use shogi::Color;
    /// use shogi::square::consts::*;
    ///
    /// let sq = SQ_1G;
    ///
    /// assert_eq!(6, sq.relative_rank(Color::Black));
    /// assert_eq!(2, sq.relative_rank(Color::White));
    /// ```
    pub fn relative_rank(self, c: Color) -> u8 {
        if c == Color::Black {
            self.rank()
        } else {
            8 - self.rank()
        }
    }

    /// Tests if the square is in a promotion zone.
    pub fn in_promotion_zone(self, c: Color) -> bool {
        self.relative_rank(c) < 3
    }

    /// Converts the instance into the unique number for array indexing purpose.
    #[inline(always)]
    pub fn index(self) -> usize {
        self.inner as usize
    }
}

impl fmt::Display for Square {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        debug_assert!(
            self.file() < 9 && self.rank() < 9,
            "trying to stringify an invalid square: {:?}",
            self
        );
        write!(
            f,
            "{}{}",
            (self.file() + ASCII_1) as char,
            (self.rank() + ASCII_LOWER_A) as char
        )
    }
}

pub mod consts {
    use super::Square;

    macro_rules! make_square {
        {0, $t:ident $($ts:ident)+} => {
            pub const $t: Square = Square { inner: 0 };
            make_square!{1, $($ts)*}
        };
        {$n:expr, $t:ident $($ts:ident)+} => {
            pub const $t: Square = Square { inner: $n };
            make_square!{($n + 1), $($ts)*}
        };
        {$n:expr, $t:ident} => {
            pub const $t: Square = Square { inner: $n };
        };
    }

    make_square! {0, SQ_1A SQ_1B SQ_1C SQ_1D SQ_1E SQ_1F SQ_1G SQ_1H SQ_1I
    SQ_2A SQ_2B SQ_2C SQ_2D SQ_2E SQ_2F SQ_2G SQ_2H SQ_2I
    SQ_3A SQ_3B SQ_3C SQ_3D SQ_3E SQ_3F SQ_3G SQ_3H SQ_3I
    SQ_4A SQ_4B SQ_4C SQ_4D SQ_4E SQ_4F SQ_4G SQ_4H SQ_4I
    SQ_5A SQ_5B SQ_5C SQ_5D SQ_5E SQ_5F SQ_5G SQ_5H SQ_5I
    SQ_6A SQ_6B SQ_6C SQ_6D SQ_6E SQ_6F SQ_6G SQ_6H SQ_6I
    SQ_7A SQ_7B SQ_7C SQ_7D SQ_7E SQ_7F SQ_7G SQ_7H SQ_7I
    SQ_8A SQ_8B SQ_8C SQ_8D SQ_8E SQ_8F SQ_8G SQ_8H SQ_8I
    SQ_9A SQ_9B SQ_9C SQ_9D SQ_9E SQ_9F SQ_9G SQ_9H SQ_9I}
}

/// This struct is created by the [`iter`] method on [`Square`].
///
/// [`iter`]: ./struct.Square.html#method.iter
/// [`Square`]: struct.Square.html
pub struct SquareIter {
    current: u8,
}

impl iter::Iterator for SquareIter {
    type Item = Square;

    fn next(&mut self) -> Option<Self::Item> {
        let cur = self.current;

        if cur >= 81 {
            return None;
        }

        self.current += 1;

        Some(Square { inner: cur })
    }
}

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

    #[test]
    fn new() {
        for file in 0..9 {
            for rank in 0..9 {
                let sq = Square::new(file, rank).unwrap();
                assert_eq!(file, sq.file());
                assert_eq!(rank, sq.rank());
            }
        }

        assert_eq!(None, Square::new(10, 0));
        assert_eq!(None, Square::new(0, 10));
        assert_eq!(None, Square::new(10, 10));
    }

    #[test]
    fn from_sfen() {
        let ok_cases = [
            ("9a", 8, 0),
            ("1a", 0, 0),
            ("5e", 4, 4),
            ("9i", 8, 8),
            ("1i", 0, 8),
        ];
        let ng_cases = ["", "9j", "_a", "a9", "9 ", " a", "9", "foo"];

        for case in ok_cases.iter() {
            let sq = Square::from_sfen(case.0);
            assert!(sq.is_some());
            assert_eq!(case.1, sq.unwrap().file());
            assert_eq!(case.2, sq.unwrap().rank());
        }

        for case in ng_cases.iter() {
            assert!(
                Square::from_sfen(case).is_none(),
                "{} should cause an error",
                case
            );
        }
    }

    #[test]
    fn from_index() {
        for i in 0..81 {
            assert!(Square::from_index(i).is_some());
        }

        assert!(Square::from_index(82).is_none());
    }

    #[test]
    fn to_sfen() {
        let cases = [
            ("9a", 8, 0),
            ("1a", 0, 0),
            ("5e", 4, 4),
            ("9i", 8, 8),
            ("1i", 0, 8),
        ];

        for case in cases.iter() {
            let sq = Square::new(case.1, case.2).unwrap();
            assert_eq!(case.0, sq.to_string());
        }
    }

    #[test]
    fn shift() {
        let sq = consts::SQ_5E;

        let ok_cases = [
            (-4, -4, 0, 0),
            (-4, 0, 0, 4),
            (0, -4, 4, 0),
            (0, 0, 4, 4),
            (4, 0, 8, 4),
            (0, 4, 4, 8),
            (4, 4, 8, 8),
        ];

        let ng_cases = [(-5, -4), (-4, -5), (5, 0), (0, 5)];

        for case in ok_cases.iter() {
            let shifted = sq.shift(case.0, case.1).unwrap();
            assert_eq!(case.2, shifted.file());
            assert_eq!(case.3, shifted.rank());
        }

        for case in ng_cases.iter() {
            assert!(sq.shift(case.0, case.1).is_none());
        }
    }

    #[test]
    fn relative_rank() {
        let cases = [
            (0, 0, 0, 8),
            (0, 1, 1, 7),
            (0, 2, 2, 6),
            (0, 3, 3, 5),
            (0, 4, 4, 4),
            (0, 5, 5, 3),
            (0, 6, 6, 2),
            (0, 7, 7, 1),
            (0, 8, 8, 0),
        ];

        for case in cases.iter() {
            let sq = Square::new(case.0, case.1).unwrap();
            assert_eq!(case.2, sq.relative_rank(Color::Black));
            assert_eq!(case.3, sq.relative_rank(Color::White));
        }
    }

    #[test]
    fn in_promotion_zone() {
        let cases = [
            (0, 0, true, false),
            (0, 1, true, false),
            (0, 2, true, false),
            (0, 3, false, false),
            (0, 4, false, false),
            (0, 5, false, false),
            (0, 6, false, true),
            (0, 7, false, true),
            (0, 8, false, true),
        ];

        for case in cases.iter() {
            let sq = Square::new(case.0, case.1).unwrap();
            assert_eq!(case.2, sq.in_promotion_zone(Color::Black));
            assert_eq!(case.3, sq.in_promotion_zone(Color::White));
        }
    }

    #[test]
    fn consts() {
        for (i, sq) in Square::iter().enumerate() {
            assert_eq!((i / 9) as u8, sq.file());
            assert_eq!((i % 9) as u8, sq.rank());
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Reader, Writer, IoErrorKind, InvalidInput};
use std::string::{String};

/// The maximum line size as specified by RFC 5321.
static MAX_LINE_SIZE: uint = 512;

/// A stream specially made for reading SMTP commands.
///
/// It reads lines of input delimited by the <CRLF> sequence and with a maximum
/// size of 512 bytes, including the command word and the <CRLF> sequence. If
/// the input is not UTF8, non-UTF8 characters are replaced with `U+FFFD
/// REPLACEMENT CHARACTER` but no error is returned.
///
/// Returns `EndOfFile` if no line is found within 512 bytes of input.
pub struct SmtpStream<S> {
    stream: S,
    vec: Vec<u8>
}

impl<S> SmtpStream<S> {
    /// Create a new `SmtpStream` from another stream.
    pub fn new(inner: S) -> SmtpStream<S> {
        SmtpStream {
            stream: inner,
            vec: Vec::with_capacity(MAX_LINE_SIZE)
        }
    }

    /// Read the data section of an email. Ends with "<CRLF>.<CRLF>".
    pub fn read_data(&mut self) -> Result<String, IoErrorKind> {
        Ok("Hello world!".into_string())
    }
}

impl<R: Reader> SmtpStream<R> {

    /// Read one line of input.
    pub fn read_line(&mut self) -> Result<String, IoErrorKind> {
        self.vec.clear();
        loop {
            // If we have previously read 512 bytes and have not found a line,
            // stop here.
            if self.vec.len() == 512 {
                return Err(InvalidInput)
            }

            // Try to read one more byte and see if a line is formed.
            let byte_res = self.stream.read_byte();
            match byte_res {
                Ok(b) => {
                    self.vec.push(b);
                    // A line ends with \r\n (or 13/10 in decimal), so we
                    // check for these bytes at the end of our buffer.
                    let len = self.vec.len();
                    if len >= 2 {
                        if self.vec[len - 2] == 13 && self.vec[len - 1] == 10 {
                            return Ok(String::from_utf8_lossy(
                                self.vec.slice_to(len - 2)
                            ).into_string());
                        }
                    }
                },
                Err(e) => return Err(e.kind)
            }
        }
    }

}

impl<W: Writer> SmtpStream<W> {
    /// Write a line ended with CRLF.
    pub fn write_line(&mut self, s: &str) -> Result<(), ()> {
        match self.stream.write_str(format!("{}\r\n", s).as_slice()) {
            Ok(_) => Ok(()),
            Err(_) => Err(())
        }
    }
}

#[test]
fn test_reader() {
    let mut path: Path;
    let mut file: super::std::io::fs::File;
    let mut stream: SmtpStream<super::std::io::fs::File>;
    let mut expected: String;

    path = Path::new("tests/stream/0line1");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/0line2");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/0line3");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/1line1");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert_eq!(stream.read_line().unwrap().as_slice(), "hello world!");
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/1line2");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert_eq!(stream.read_line().unwrap().as_slice(), "hello world!");
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/2lines1");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert_eq!(stream.read_line().unwrap().as_slice(), "hello world!");
    assert_eq!(stream.read_line().unwrap().as_slice(), "bye bye world!");
    assert!(!stream.read_line().is_ok());

    expected = String::from_char(62, 'x');
    path = Path::new("tests/stream/xlines1");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert!(!stream.read_line().is_ok());
}
<commit_msg>added github hint in DATA command<commit_after>use std::io::{Reader, Writer, IoErrorKind, InvalidInput};
use std::string::{String};

/// The maximum line size as specified by RFC 5321.
static MAX_LINE_SIZE: uint = 512;

/// A stream specially made for reading SMTP commands.
///
/// It reads lines of input delimited by the <CRLF> sequence and with a maximum
/// size of 512 bytes, including the command word and the <CRLF> sequence. If
/// the input is not UTF8, non-UTF8 characters are replaced with `U+FFFD
/// REPLACEMENT CHARACTER` but no error is returned.
///
/// Returns `EndOfFile` if no line is found within 512 bytes of input.
pub struct SmtpStream<S> {
    stream: S,
    vec: Vec<u8>
}

impl<S> SmtpStream<S> {
    /// Create a new `SmtpStream` from another stream.
    pub fn new(inner: S) -> SmtpStream<S> {
        SmtpStream {
            stream: inner,
            vec: Vec::with_capacity(MAX_LINE_SIZE)
        }
    }

    /// Read the data section of an email. Ends with "<CRLF>.<CRLF>".
    pub fn read_data(&mut self) -> Result<String, IoErrorKind> {
        println!("At the moment, the DATA command is fake. Wanna help us out?");
        println!("https://github.com/conradkleinespel/rustastic-smtp");
        Ok("Hello world!".into_string())
    }
}

impl<R: Reader> SmtpStream<R> {

    /// Read one line of input.
    pub fn read_line(&mut self) -> Result<String, IoErrorKind> {
        self.vec.clear();
        loop {
            // If we have previously read 512 bytes and have not found a line,
            // stop here.
            if self.vec.len() == 512 {
                return Err(InvalidInput)
            }

            // Try to read one more byte and see if a line is formed.
            let byte_res = self.stream.read_byte();
            match byte_res {
                Ok(b) => {
                    self.vec.push(b);
                    // A line ends with \r\n (or 13/10 in decimal), so we
                    // check for these bytes at the end of our buffer.
                    let len = self.vec.len();
                    if len >= 2 {
                        if self.vec[len - 2] == 13 && self.vec[len - 1] == 10 {
                            return Ok(String::from_utf8_lossy(
                                self.vec.slice_to(len - 2)
                            ).into_string());
                        }
                    }
                },
                Err(e) => return Err(e.kind)
            }
        }
    }

}

impl<W: Writer> SmtpStream<W> {
    /// Write a line ended with CRLF.
    pub fn write_line(&mut self, s: &str) -> Result<(), ()> {
        match self.stream.write_str(format!("{}\r\n", s).as_slice()) {
            Ok(_) => Ok(()),
            Err(_) => Err(())
        }
    }
}

#[test]
fn test_reader() {
    let mut path: Path;
    let mut file: super::std::io::fs::File;
    let mut stream: SmtpStream<super::std::io::fs::File>;
    let mut expected: String;

    path = Path::new("tests/stream/0line1");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/0line2");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/0line3");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/1line1");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert_eq!(stream.read_line().unwrap().as_slice(), "hello world!");
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/1line2");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert_eq!(stream.read_line().unwrap().as_slice(), "hello world!");
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/2lines1");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert_eq!(stream.read_line().unwrap().as_slice(), "hello world!");
    assert_eq!(stream.read_line().unwrap().as_slice(), "bye bye world!");
    assert!(!stream.read_line().is_ok());

    expected = String::from_char(62, 'x');
    path = Path::new("tests/stream/xlines1");
    file = super::std::io::fs::File::open(&path).unwrap();
    stream = SmtpStream::new(file);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert_eq!(stream.read_line().unwrap(), expected);
    assert!(!stream.read_line().is_ok());
}
<|endoftext|>