<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]

use std::{io, cmp};
use bytes::{Bytes, BytesMut};
use futures::{Async, Poll};
use http2::{Reason, SendStream};
use http2::server::SendResponse;
use http::{Version, HttpTryFrom, Response};
use http::header::{HeaderValue, CONNECTION, TRANSFER_ENCODING, DATE, CONTENT_LENGTH};

use helpers;
use body::{Body, Binary};
use headers::ContentEncoding;
use httprequest::HttpInnerMessage;
use httpresponse::HttpResponse;
use super::encoding::ContentEncoder;
use super::shared::SharedBytes;
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};

const CHUNK_SIZE: usize = 16_384;

bitflags! {
    struct Flags: u8 {
        const STARTED = 0b0000_0001;
        const DISCONNECTED = 0b0000_0010;
        const EOF = 0b0000_0100;
        const RESERVED = 0b0000_1000;
    }
}

pub(crate) struct H2Writer {
    respond: SendResponse<Bytes>,
    stream: Option<SendStream<Bytes>>,
    encoder: ContentEncoder,
    flags: Flags,
    written: u64,
    buffer: SharedBytes,
    buffer_capacity: usize,
}

impl H2Writer {

    pub fn new(respond: SendResponse<Bytes>, buf: SharedBytes) -> H2Writer {
        H2Writer {
            respond,
            stream: None,
            encoder: ContentEncoder::empty(buf.clone()),
            flags: Flags::empty(),
            written: 0,
            buffer: buf,
            buffer_capacity: 0,
        }
    }

    pub fn reset(&mut self, reason: Reason) {
        if let Some(mut stream) = self.stream.take() {
            stream.send_reset(reason)
        }
    }
}

impl Writer for H2Writer {

    fn written(&self) -> u64 {
        self.written
    }

    fn start(&mut self,
             req: &mut HttpInnerMessage,
             msg: &mut HttpResponse,
             encoding: ContentEncoding) -> io::Result<WriterState>
    {
        // prepare response
        self.flags.insert(Flags::STARTED);
        self.encoder = ContentEncoder::for_server(self.buffer.clone(), req, msg, encoding);
        if let Body::Empty = *msg.body() {
            self.flags.insert(Flags::EOF);
        }

        // http2 specific
        msg.headers_mut().remove(CONNECTION);
        msg.headers_mut().remove(TRANSFER_ENCODING);

        // using helpers::date is quite a lot faster
        if !msg.headers().contains_key(DATE) {
            let mut bytes = BytesMut::with_capacity(29);
            helpers::date_value(&mut bytes);
            msg.headers_mut().insert(DATE, HeaderValue::try_from(bytes.freeze()).unwrap());
        }

        let body = msg.replace_body(Body::Empty);
        match body {
            Body::Binary(ref bytes) => {
                let mut val = BytesMut::new();
                helpers::convert_usize(bytes.len(), &mut val);
                let l = val.len();
                msg.headers_mut().insert(
                    CONTENT_LENGTH, HeaderValue::try_from(val.split_to(l-2).freeze()).unwrap());
            }
            Body::Empty => {
                msg.headers_mut().insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
            },
            _ => (),
        }

        let mut resp = Response::new(());
        *resp.status_mut() = msg.status();
        *resp.version_mut() = Version::HTTP_2;
        for (key, value) in msg.headers().iter() {
            resp.headers_mut().insert(key, value.clone());
        }

        match self.respond.send_response(resp, self.flags.contains(Flags::EOF)) {
            Ok(stream) =>
                self.stream = Some(stream),
            Err(_) =>
                return Err(io::Error::new(io::ErrorKind::Other, "err")),
        }

        trace!("Response: {:?}", msg);

        if let Body::Binary(bytes) = body {
            self.flags.insert(Flags::EOF);
            self.written = bytes.len() as u64;
            self.encoder.write(bytes)?;
            if let Some(ref mut stream) = self.stream {
                self.flags.insert(Flags::RESERVED);
                stream.reserve_capacity(cmp::min(self.buffer.len(), CHUNK_SIZE));
            }
            Ok(WriterState::Pause)
        } else {
            msg.replace_body(body);
            self.buffer_capacity = msg.write_buffer_capacity();
            Ok(WriterState::Done)
        }
    }

    fn write(&mut self, payload: Binary) -> io::Result<WriterState> {
        self.written = payload.len() as u64;

        if !self.flags.contains(Flags::DISCONNECTED) {
            if self.flags.contains(Flags::STARTED) {
                // TODO: add warning, write after EOF
                self.encoder.write(payload)?;
            } else {
                // might be response for EXCEPT
                self.buffer.extend_from_slice(payload.as_ref())
            }
        }

        if self.buffer.len() > self.buffer_capacity {
            Ok(WriterState::Pause)
        } else {
            Ok(WriterState::Done)
        }
    }

    fn write_eof(&mut self) -> io::Result<WriterState> {
        self.encoder.write_eof()?;

        self.flags.insert(Flags::EOF);
        if !self.encoder.is_eof() {
            Err(io::Error::new(io::ErrorKind::Other,
                               "Last payload item, but eof is not reached"))
        } else if self.buffer.len() > MAX_WRITE_BUFFER_SIZE {
            Ok(WriterState::Pause)
        } else {
            Ok(WriterState::Done)
        }
    }

    fn poll_completed(&mut self, _shutdown: bool) -> Poll<(), io::Error> {
        if !self.flags.contains(Flags::STARTED) {
            return Ok(Async::NotReady);
        }

        if let Some(ref mut stream) = self.stream {
            // reserve capacity
            if !self.flags.contains(Flags::RESERVED) && !self.buffer.is_empty() {
                self.flags.insert(Flags::RESERVED);
                stream.reserve_capacity(cmp::min(self.buffer.len(), CHUNK_SIZE));
            }

            loop {
                match stream.poll_capacity() {
                    Ok(Async::NotReady) => return Ok(Async::NotReady),
                    Ok(Async::Ready(None)) => return Ok(Async::Ready(())),
                    Ok(Async::Ready(Some(cap))) => {
                        let len = self.buffer.len();
                        let bytes = self.buffer.split_to(cmp::min(cap, len));
                        let eof = self.buffer.is_empty() && self.flags.contains(Flags::EOF);
                        self.written += bytes.len() as u64;

                        if let Err(e) = stream.send_data(bytes.freeze(), eof) {
                            return Err(io::Error::new(io::ErrorKind::Other, e))
                        } else if !self.buffer.is_empty() {
                            let cap = cmp::min(self.buffer.len(), CHUNK_SIZE);
                            stream.reserve_capacity(cap);
                        } else {
                            return Ok(Async::NotReady)
                        }
                    }
                    Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
                }
            }
        }
        return Ok(Async::NotReady)
    }
}
<commit_msg>remove reserved state for h2 write if buffer is empty<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]

use std::{io, cmp};
use bytes::{Bytes, BytesMut};
use futures::{Async, Poll};
use http2::{Reason, SendStream};
use http2::server::SendResponse;
use http::{Version, HttpTryFrom, Response};
use http::header::{HeaderValue, CONNECTION, TRANSFER_ENCODING, DATE, CONTENT_LENGTH};

use helpers;
use body::{Body, Binary};
use headers::ContentEncoding;
use httprequest::HttpInnerMessage;
use httpresponse::HttpResponse;
use super::encoding::ContentEncoder;
use super::shared::SharedBytes;
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};

const CHUNK_SIZE: usize = 16_384;

bitflags! {
    struct Flags: u8 {
        const STARTED = 0b0000_0001;
        const DISCONNECTED = 0b0000_0010;
        const EOF = 0b0000_0100;
        const RESERVED = 0b0000_1000;
    }
}

pub(crate) struct H2Writer {
    respond: SendResponse<Bytes>,
    stream: Option<SendStream<Bytes>>,
    encoder: ContentEncoder,
    flags: Flags,
    written: u64,
    buffer: SharedBytes,
    buffer_capacity: usize,
}

impl H2Writer {

    pub fn new(respond: SendResponse<Bytes>, buf: SharedBytes) -> H2Writer {
        H2Writer {
            respond,
            stream: None,
            encoder: ContentEncoder::empty(buf.clone()),
            flags: Flags::empty(),
            written: 0,
            buffer: buf,
            buffer_capacity: 0,
        }
    }

    pub fn reset(&mut self, reason: Reason) {
        if let Some(mut stream) = self.stream.take() {
            stream.send_reset(reason)
        }
    }
}

impl Writer for H2Writer {

    fn written(&self) -> u64 {
        self.written
    }

    fn start(&mut self,
             req: &mut HttpInnerMessage,
             msg: &mut HttpResponse,
             encoding: ContentEncoding) -> io::Result<WriterState>
    {
        // prepare response
        self.flags.insert(Flags::STARTED);
        self.encoder = ContentEncoder::for_server(self.buffer.clone(), req, msg, encoding);
        if let Body::Empty = *msg.body() {
            self.flags.insert(Flags::EOF);
        }

        // http2 specific
        msg.headers_mut().remove(CONNECTION);
        msg.headers_mut().remove(TRANSFER_ENCODING);

        // using helpers::date is quite a lot faster
        if !msg.headers().contains_key(DATE) {
            let mut bytes = BytesMut::with_capacity(29);
            helpers::date_value(&mut bytes);
            msg.headers_mut().insert(DATE, HeaderValue::try_from(bytes.freeze()).unwrap());
        }

        let body = msg.replace_body(Body::Empty);
        match body {
            Body::Binary(ref bytes) => {
                let mut val = BytesMut::new();
                helpers::convert_usize(bytes.len(), &mut val);
                let l = val.len();
                msg.headers_mut().insert(
                    CONTENT_LENGTH, HeaderValue::try_from(val.split_to(l-2).freeze()).unwrap());
            }
            Body::Empty => {
                msg.headers_mut().insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
            },
            _ => (),
        }

        let mut resp = Response::new(());
        *resp.status_mut() = msg.status();
        *resp.version_mut() = Version::HTTP_2;
        for (key, value) in msg.headers().iter() {
            resp.headers_mut().insert(key, value.clone());
        }

        match self.respond.send_response(resp, self.flags.contains(Flags::EOF)) {
            Ok(stream) =>
                self.stream = Some(stream),
            Err(_) =>
                return Err(io::Error::new(io::ErrorKind::Other, "err")),
        }

        trace!("Response: {:?}", msg);

        if let Body::Binary(bytes) = body {
            self.flags.insert(Flags::EOF);
            self.written = bytes.len() as u64;
            self.encoder.write(bytes)?;
            if let Some(ref mut stream) = self.stream {
                self.flags.insert(Flags::RESERVED);
                stream.reserve_capacity(cmp::min(self.buffer.len(), CHUNK_SIZE));
            }
            Ok(WriterState::Pause)
        } else {
            msg.replace_body(body);
            self.buffer_capacity = msg.write_buffer_capacity();
            Ok(WriterState::Done)
        }
    }

    fn write(&mut self, payload: Binary) -> io::Result<WriterState> {
        self.written = payload.len() as u64;

        if !self.flags.contains(Flags::DISCONNECTED) {
            if self.flags.contains(Flags::STARTED) {
                // TODO: add warning, write after EOF
                self.encoder.write(payload)?;
            } else {
                // might be response for EXCEPT
                self.buffer.extend_from_slice(payload.as_ref())
            }
        }

        if self.buffer.len() > self.buffer_capacity {
            Ok(WriterState::Pause)
        } else {
            Ok(WriterState::Done)
        }
    }

    fn write_eof(&mut self) -> io::Result<WriterState> {
        self.encoder.write_eof()?;

        self.flags.insert(Flags::EOF);
        if !self.encoder.is_eof() {
            Err(io::Error::new(io::ErrorKind::Other,
                               "Last payload item, but eof is not reached"))
        } else if self.buffer.len() > MAX_WRITE_BUFFER_SIZE {
            Ok(WriterState::Pause)
        } else {
            Ok(WriterState::Done)
        }
    }

    fn poll_completed(&mut self, _shutdown: bool) -> Poll<(), io::Error> {
        if !self.flags.contains(Flags::STARTED) {
            return Ok(Async::NotReady);
        }

        if let Some(ref mut stream) = self.stream {
            // reserve capacity
            if !self.flags.contains(Flags::RESERVED) && !self.buffer.is_empty() {
                self.flags.insert(Flags::RESERVED);
                stream.reserve_capacity(cmp::min(self.buffer.len(), CHUNK_SIZE));
            }

            loop {
                match stream.poll_capacity() {
                    Ok(Async::NotReady) => return Ok(Async::NotReady),
                    Ok(Async::Ready(None)) => return Ok(Async::Ready(())),
                    Ok(Async::Ready(Some(cap))) => {
                        let len = self.buffer.len();
                        let bytes = self.buffer.split_to(cmp::min(cap, len));
                        let eof = self.buffer.is_empty() && self.flags.contains(Flags::EOF);
                        self.written += bytes.len() as u64;

                        if let Err(e) = stream.send_data(bytes.freeze(), eof) {
                            return Err(io::Error::new(io::ErrorKind::Other, e))
                        } else if !self.buffer.is_empty() {
                            let cap = cmp::min(self.buffer.len(), CHUNK_SIZE);
                            stream.reserve_capacity(cap);
                        } else {
                            self.flags.remove(Flags::RESERVED);
                            return Ok(Async::NotReady)
                        }
                    }
                    Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
                }
            }
        }
        return Ok(Async::NotReady)
    }
}
<|endoftext|>


<commit_before>use super::Vector;
use super::Vector2;

pub struct Vector2f {
    pub x: f32,
    pub y: f32,
}

impl Default for Vector2f {
    fn default() -> Vector2f {
        Vector2f {
            x: 0f32,
            y: 0f32,
        }
    }
}

impl Vector<Vector2f, f32> for Vector2f {
    fn add(&mut self, v: &Vector2f) -> &mut Self {
        self.x += v.x;
        self.y += v.y;
        self
    }

    fn add_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x + v.x;
        dest.y = self.y + v.y;
    }

    fn angle(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn angle_cos(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance(&self, v: &Vector2f) -> f32 {
        self.distance_squared(v).sqrt()
    }

    fn distance_squared(&self, v: &Vector2f) -> f32 {
        let dx = self.x - v.x;
        let dy = self.y - v.y;
        (dx * dx) + (dy * dy)
    }

    fn dot(&self, v: &Vector2f) -> f32 {
        (self.x * v.x) + (self.y * v.y)
    }

    fn fma_scalar(&mut self, a: f32, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_scalar_into(&self, a: f32, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn fma_vector(&mut self, a: &Vector2f, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_vector_into(&self, a: &Vector2f, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn length(&self) -> f32 {
        self.length_squared().sqrt()
    }

    fn length_squared(&self) -> f32 {
        (self.x * self.x) + (self.y * self.y)
    }

    fn lerp(&mut self, other: &Vector2f, t: f32) -> &mut Self {
        unimplemented!()
    }

    fn lerp_into(&self, other: &Vector2f, t: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_scalar(&mut self, s: f32) -> &mut Self {
        self.x *= s;
        self.y *= s;
        self
    }

    fn mul_scalar_into(&self, s: f32, dest: &mut Vector2f) {
        dest.x = self.x * s;
        dest.y = self.y * s;
    }

    fn mul_vector(&mut self, v: &Vector2f) -> &mut Self {
        self.x *= v.x;
        self.y *= v.y;
        self
    }

    fn mul_vector_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x * v.x;
        dest.y = self.y * v.y;
    }

    fn negate(&mut self) -> &mut Self {
        self.x = -self.x;
        self.y = -self.y;
        self
    }

    fn negate_into(&self, dest: &mut Vector2f) {
        dest.x = -self.x;
        dest.y = -self.y;
    }

    fn normalize(&mut self) -> &mut Self {
        let inv_length = 1f32 / self.length();
        self.x *= inv_length;
        self.y *= inv_length;
        self
    }

    fn normalize_into(&self, dest: &mut Vector2f) {
        let inv_length = 1f32 / self.length();
        dest.x = self.x * inv_length;
        dest.y = self.y * inv_length;
    }

    fn set(&mut self, v: &Vector2f) -> &mut Self {
        self.x = v.x;
        self.y = v.y;
        self
    }

    fn sub(&mut self, v: &Vector2f) -> &mut Self {
        self.x -= v.x;
        self.y -= v.y;
        self
    }

    fn sub_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x - v.x;
        dest.y = self.y - v.y;
    }

    fn zero(&mut self) -> &mut Self {
        self.x = 0f32;
        self.y = 0f32;
        self
    }
}

impl Vector2<Vector2f, f32> for Vector2f {
    fn new(x: f32, y: f32) -> Self {
        Vector2f {
            x: x,
            y: y,
        }
    }

    fn add_components(&mut self, x: f32, y: f32) -> &mut Self {
        unimplemented!()
    }

    fn add_components_into(&self, x: f32, y: f32, dest: &mut Vector2f) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::super::Vector;
    use super::super::Vector2;
    use super::Vector2f;

    use std;

    #[test]
    fn test_new() {
        let a = Vector2f::new(1f32, 2f32);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add() {
        let mut a = Vector2f::default();
        let b = Vector2f::new(1f32, 2f32);

        a.add(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add_into() {
        let a = Vector2f::new(1f32, 1f32);
        let b = Vector2f::new(1f32, 2f32);
        let mut c = Vector2f::default();

        a.add_into(&b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 3f32);
    }

    #[test]
    fn test_distance() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(0f32, 1f32);

        let target_distance = 2f32;
        let distance = a.distance(&b);

        assert_eq!(target_distance, distance);
    }

    #[test]
    fn test_distance_squared() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(0f32, 1f32);

        let target_distance_sq = 4f32; //distance is 2
        let distance_sq = a.distance_squared(&b);

        assert_eq!(target_distance_sq, distance_sq);
    }

    #[test]
    fn test_dot() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(1f32, 1f32);

        let target_dot = 3f32;
        let dot = a.dot(&b);

        assert_eq!(target_dot, dot);
    }

    #[test]
    fn test_length() {
        let a = Vector2f::new(3f32, 4f32);

        let target_length = 5f32; //length should be 5 because of the 3:4:5 triangle
        let length = a.length();

        assert_eq!(target_length, length);
    }

    #[test]
    fn test_length_squared() {
        let a = Vector2f::new(3f32, 4f32);

        let target_length_sq = 25f32; //length should be 5 because of the 3:4:5 triangle
        let length_sq = a.length_squared();

        assert_eq!(target_length_sq, length_sq);
    }

    #[test]
    fn test_mul_scalar() {
        let mut a = Vector2f::new(1f32, 2f32);
        let b = 2f32;

        a.mul_scalar(b);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 4f32);
    }

    #[test]
    fn test_mul_scalar_into() {
        let a = Vector2f::new(1f32, 2f32);
        let b = 2f32;
        let mut c = Vector2::new(0f32, 0f32);

        a.mul_scalar_into(b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 4f32);
    }

    #[test]
    fn test_mul_vector() {
        let mut a = Vector2f::new(1f32, 2f32);
        let b = Vector2f::new(2f32, 3f32);

        a.mul_vector(&b);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 6f32);
    }

    #[test]
    fn test_mul_vector_into() {
        let a = Vector2f::new(1f32, 2f32);
        let b = Vector2f::new(2f32, 3f32);
        let mut c = Vector2::new(0f32, 0f32);

        a.mul_vector_into(&b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 6f32);
    }

    #[test]
    fn test_negate() {
        let mut a = Vector2f::new(1f32, 2f32);

        a.negate();

        assert_eq!(a.x, -1f32);
        assert_eq!(a.y, -2f32);
    }

    #[test]
    fn test_negate_into() {
        let a = Vector2f::new(1f32, 2f32);
        let mut b = Vector2f::new(0f32, 0f32);

        a.negate_into(&mut b);

        assert_eq!(b.x, -1f32);
        assert_eq!(b.y, -2f32);
    }

    #[test]
    fn test_normalize() {
        let mut a = Vector2f::new(1f32, 2f32);

        a.normalize();

        assert!((1f32 - a.length()).abs() < std::f32::EPSILON);
    }

    #[test]
    fn test_normalize_into() {
        let a = Vector2f::new(1f32, 2f32);
        let mut b = Vector2f::new(0f32, 0f32);

        a.normalize_into(&mut b);

        assert!((1f32 - b.length()).abs() < std::f32::EPSILON);
    }

    #[test]
    fn test_set() {
        let mut a = Vector2f::new(0f32, 0f32);
        let b = Vector2f::new(1f32, 2f32);

        a.set(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_sub() {
        let mut a = Vector2f::new(2f32, 5f32);
        let b = Vector2f::new(1f32, 2f32);

        a.sub(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 3f32);
    }

    #[test]
    fn test_sub_into() {
        let a = Vector2f::new(2f32, 5f32);
        let b = Vector2f::new(1f32, 2f32);
        let mut c = Vector2f::new(0f32, 0f32);

        a.sub_into(&b, &mut c);

        assert_eq!(c.x, 1f32);
        assert_eq!(c.y, 3f32);
    }

    #[test]
    fn test_zero() {
        let mut a = Vector2f::new(1f32, 2f32);

        a.zero();

        assert_eq!(a.x, 0f32);
        assert_eq!(a.y, 0f32);
    }
}
<commit_msg>add fma impls<commit_after>use super::Vector;
use super::Vector2;

pub struct Vector2f {
    pub x: f32,
    pub y: f32,
}

impl Default for Vector2f {
    fn default() -> Vector2f {
        Vector2f {
            x: 0f32,
            y: 0f32,
        }
    }
}

impl Vector<Vector2f, f32> for Vector2f {
    fn add(&mut self, v: &Vector2f) -> &mut Self {
        self.x += v.x;
        self.y += v.y;
        self
    }

    fn add_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x + v.x;
        dest.y = self.y + v.y;
    }

    fn angle(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn angle_cos(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance(&self, v: &Vector2f) -> f32 {
        self.distance_squared(v).sqrt()
    }

    fn distance_squared(&self, v: &Vector2f) -> f32 {
        let dx = self.x - v.x;
        let dy = self.y - v.y;
        (dx * dx) + (dy * dy)
    }

    fn dot(&self, v: &Vector2f) -> f32 {
        (self.x * v.x) + (self.y * v.y)
    }

    fn fma_scalar(&mut self, a: f32, b: &Vector2f) -> &mut Self {
        self.x += a * b.x;
        self.y += a * b.y;
        self
    }

    fn fma_scalar_into(&self, a: f32, b: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x + (a * b.x);
        dest.y = self.y + (a * b.y);
    }

    fn fma_vector(&mut self, a: &Vector2f, b: &Vector2f) -> &mut Self {
        self.x += a.x * b.x;
        self.y += a.y * b.y;
        self
    }

    fn fma_vector_into(&self, a: &Vector2f, b: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x + (a.x * b.x);
        dest.y = self.y + (a.y * b.y);
    }

    fn length(&self) -> f32 {
        self.length_squared().sqrt()
    }

    fn length_squared(&self) -> f32 {
        (self.x * self.x) + (self.y * self.y)
    }

    fn lerp(&mut self, other: &Vector2f, t: f32) -> &mut Self {
        unimplemented!()
    }

    fn lerp_into(&self, other: &Vector2f, t: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_scalar(&mut self, s: f32) -> &mut Self {
        self.x *= s;
        self.y *= s;
        self
    }

    fn mul_scalar_into(&self, s: f32, dest: &mut Vector2f) {
        dest.x = self.x * s;
        dest.y = self.y * s;
    }

    fn mul_vector(&mut self, v: &Vector2f) -> &mut Self {
        self.x *= v.x;
        self.y *= v.y;
        self
    }

    fn mul_vector_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x * v.x;
        dest.y = self.y * v.y;
    }

    fn negate(&mut self) -> &mut Self {
        self.x = -self.x;
        self.y = -self.y;
        self
    }

    fn negate_into(&self, dest: &mut Vector2f) {
        dest.x = -self.x;
        dest.y = -self.y;
    }

    fn normalize(&mut self) -> &mut Self {
        let inv_length = 1f32 / self.length();
        self.x *= inv_length;
        self.y *= inv_length;
        self
    }

    fn normalize_into(&self, dest: &mut Vector2f) {
        let inv_length = 1f32 / self.length();
        dest.x = self.x * inv_length;
        dest.y = self.y * inv_length;
    }

    fn set(&mut self, v: &Vector2f) -> &mut Self {
        self.x = v.x;
        self.y = v.y;
        self
    }

    fn sub(&mut self, v: &Vector2f) -> &mut Self {
        self.x -= v.x;
        self.y -= v.y;
        self
    }

    fn sub_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x - v.x;
        dest.y = self.y - v.y;
    }

    fn zero(&mut self) -> &mut Self {
        self.x = 0f32;
        self.y = 0f32;
        self
    }
}

impl Vector2<Vector2f, f32> for Vector2f {
    fn new(x: f32, y: f32) -> Self {
        Vector2f {
            x: x,
            y: y,
        }
    }

    fn add_components(&mut self, x: f32, y: f32) -> &mut Self {
        unimplemented!()
    }

    fn add_components_into(&self, x: f32, y: f32, dest: &mut Vector2f) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::super::Vector;
    use super::super::Vector2;
    use super::Vector2f;

    use std;

    #[test]
    fn test_new() {
        let a = Vector2f::new(1f32, 2f32);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add() {
        let mut a = Vector2f::default();
        let b = Vector2f::new(1f32, 2f32);

        a.add(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add_into() {
        let a = Vector2f::new(1f32, 1f32);
        let b = Vector2f::new(1f32, 2f32);
        let mut c = Vector2f::default();

        a.add_into(&b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 3f32);
    }

    #[test]
    fn test_distance() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(0f32, 1f32);

        let target_distance = 2f32;
        let distance = a.distance(&b);

        assert_eq!(target_distance, distance);
    }

    #[test]
    fn test_distance_squared() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(0f32, 1f32);

        let target_distance_sq = 4f32; //distance is 2
        let distance_sq = a.distance_squared(&b);

        assert_eq!(target_distance_sq, distance_sq);
    }

    #[test]
    fn test_dot() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(1f32, 1f32);

        let target_dot = 3f32;
        let dot = a.dot(&b);

        assert_eq!(target_dot, dot);
    }

    #[test]
    fn test_fma_scalar() {
        let mut a = Vector2f::new(1f32, 1f32);
        let b = 2f32;
        let c = Vector2f::new(2f32, 3f32);

        a.fma_scalar(b, &c);

        assert_eq!(a.x, 5f32);
        assert_eq!(a.y, 7f32);
    }

    #[test]
    fn test_fma_scalar_into() {
        let a = Vector2f::new(1f32, 1f32);
        let b = 2f32;
        let c = Vector2f::new(2f32, 3f32);
        let mut d = Vector2f::new(0f32, 0f32);

        a.fma_scalar_into(b, &c, &mut d);

        assert_eq!(d.x, 5f32);
        assert_eq!(d.y, 7f32);
    }

    #[test]
    fn test_fma_vector() {
        let mut a = Vector2f::new(1f32, 1f32);
        let b = Vector2f::new(2f32, 3f32);
        let c = Vector2f::new(2f32, 3f32);

        a.fma_vector(&b, &c);

        assert_eq!(a.x, 5f32);
        assert_eq!(a.y, 10f32);
    }

    #[test]
    fn test_fma_vector_into() {
        let a = Vector2f::new(1f32, 1f32);
        let b = Vector2f::new(2f32, 3f32);
        let c = Vector2f::new(2f32, 3f32);
        let mut d = Vector2f::new(0f32, 0f32);

        a.fma_vector_into(&b, &c, &mut d);

        assert_eq!(d.x, 5f32);
        assert_eq!(d.y, 10f32);
    }

    #[test]
    fn test_length() {
        let a = Vector2f::new(3f32, 4f32);

        let target_length = 5f32; //length should be 5 because of the 3:4:5 triangle
        let length = a.length();

        assert_eq!(target_length, length);
    }

    #[test]
    fn test_length_squared() {
        let a = Vector2f::new(3f32, 4f32);

        let target_length_sq = 25f32; //length should be 5 because of the 3:4:5 triangle
        let length_sq = a.length_squared();

        assert_eq!(target_length_sq, length_sq);
    }

    #[test]
    fn test_mul_scalar() {
        let mut a = Vector2f::new(1f32, 2f32);
        let b = 2f32;

        a.mul_scalar(b);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 4f32);
    }

    #[test]
    fn test_mul_scalar_into() {
        let a = Vector2f::new(1f32, 2f32);
        let b = 2f32;
        let mut c = Vector2::new(0f32, 0f32);

        a.mul_scalar_into(b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 4f32);
    }

    #[test]
    fn test_mul_vector() {
        let mut a = Vector2f::new(1f32, 2f32);
        let b = Vector2f::new(2f32, 3f32);

        a.mul_vector(&b);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 6f32);
    }

    #[test]
    fn test_mul_vector_into() {
        let a = Vector2f::new(1f32, 2f32);
        let b = Vector2f::new(2f32, 3f32);
        let mut c = Vector2::new(0f32, 0f32);

        a.mul_vector_into(&b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 6f32);
    }

    #[test]
    fn test_negate() {
        let mut a = Vector2f::new(1f32, 2f32);

        a.negate();

        assert_eq!(a.x, -1f32);
        assert_eq!(a.y, -2f32);
    }

    #[test]
    fn test_negate_into() {
        let a = Vector2f::new(1f32, 2f32);
        let mut b = Vector2f::new(0f32, 0f32);

        a.negate_into(&mut b);

        assert_eq!(b.x, -1f32);
        assert_eq!(b.y, -2f32);
    }

    #[test]
    fn test_normalize() {
        let mut a = Vector2f::new(1f32, 2f32);

        a.normalize();

        assert!((1f32 - a.length()).abs() < std::f32::EPSILON);
    }

    #[test]
    fn test_normalize_into() {
        let a = Vector2f::new(1f32, 2f32);
        let mut b = Vector2f::new(0f32, 0f32);

        a.normalize_into(&mut b);

        assert!((1f32 - b.length()).abs() < std::f32::EPSILON);
    }

    #[test]
    fn test_set() {
        let mut a = Vector2f::new(0f32, 0f32);
        let b = Vector2f::new(1f32, 2f32);

        a.set(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_sub() {
        let mut a = Vector2f::new(2f32, 5f32);
        let b = Vector2f::new(1f32, 2f32);

        a.sub(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 3f32);
    }

    #[test]
    fn test_sub_into() {
        let a = Vector2f::new(2f32, 5f32);
        let b = Vector2f::new(1f32, 2f32);
        let mut c = Vector2f::new(0f32, 0f32);

        a.sub_into(&b, &mut c);

        assert_eq!(c.x, 1f32);
        assert_eq!(c.y, 3f32);
    }

    #[test]
    fn test_zero() {
        let mut a = Vector2f::new(1f32, 2f32);

        a.zero();

        assert_eq!(a.x, 0f32);
        assert_eq!(a.y, 0f32);
    }
}
<|endoftext|>


<commit_before>extern mod std;

#[deriving(Eq)]
#[deriving(Clone)]
pub enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

#[inline]
fn isws(c: char) -> bool {
	c == ' ' || c == '\t' || c == '\n'
}

fn read_nows(input: &str, start: uint) -> Option<char> {
	input.iter().skip(start).skip_while(|&c| isws(c)).next()
}

fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| isws(c) || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None if read_nows(input, i) == Some(')') => return Some((~List(list), i)),
			None => return None
		}
	}
}

fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| !isws(c) && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len()) {
		return None
	}

	match input[start] as char {
		c if isws(c) => read_value(input, start+1), // ignore whitespace
		'(' => read_list(input, start+1),
		')' => None,
		c if c.is_digit() || c == '.' => read_number(input, start),
		_ => read_atom(input, start)
	}
}

pub fn from_str(input: &str) -> Option<Value> {
	match read_value(input, 0) {
		Some((v,_)) => Some(*v),
		None => None
	}
}

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

	fn parse_some(input: &str, expr: Value) {
		match from_str(input) {
			Some(ref p) if p == &expr => {}
			Some(ref p) => {
				if(p != &expr) {
					fail!("Expected %?, not %?, for %?", expr, *p, input)
				}
			}
			None => fail!("Got None for %?", input)
		}
	}

	#[test]
	fn test_sexpr() {
		assert_eq!(from_str(""), None);
		parse_some("123", Num(123.0));
		parse_some("()", List(~[]));
		parse_some("3.14159265358", Num(3.14159265358));
		parse_some("(hi)", List(~[Atom(~"hi")]));
		parse_some("(1)", List(~[Num(1.0)]));
		parse_some("(hi there)", List(~[Atom(~"hi"), Atom(~"there")]));
		parse_some("(hi (there))", List(~[Atom(~"hi"), List(~[Atom(~"there")])]));
		parse_some("(hi 123456)", List(~[Atom(~"hi"), Num(123456.0)]));
		parse_some("(())", List(~[List(~[])]));
		parse_some("(hi (there (fellow (human-bot!))))",
			List(~[Atom(~"hi"),
				List(~[Atom(~"there"),
					List(~[Atom(~"fellow"),
						List(~[Atom(~"human-bot!")])])])])
		);
	}

	#[test]
	fn test_whitespace() {
		// spaces
		parse_some("  (  1  )  ", List(~[Num(1.0)]));
		parse_some("  (  (  )  )  )", List(~[List(~[])]));

		// newlines
		parse_some("\n\n( \n\n )\n\n", List(~[]));
		parse_some("\n\n(\n\n123\n\n)\n\n", List(~[Num(123.0)]));
	}
}<commit_msg>add string literal reader and tests<commit_after>extern mod std;

#[deriving(Eq)]
#[deriving(Clone)]
pub enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

#[inline]
fn isws(c: char) -> bool {
	c == ' ' || c == '\t' || c == '\n'
}

/// Reads a character after skipping whitespace
fn read_nows(input: &str, start: uint) -> Option<char> {
	input.iter().skip(start).skip_while(|&c| isws(c)).next()
}

/// Reads a numeric literal (integers or floats)
fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| isws(c) || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

/// Reads a string literal
fn read_string(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut acc = ~"";
	let mut was_escape = false;
	for i in range(start+1, input.len()) {
		match(input[i] as char) {
			'"' if !was_escape =>
				return Some((~Str(acc), i+1)), // got closing quote
			'\\' if !was_escape => {
				// escape codes
				was_escape = true;
				match input[i+1] as char {
					'\\' => acc.push_char('\\'),
					'"' => acc.push_char('"'),
					't' => acc.push_char('\t'),
					'n' => acc.push_char('\n'),
					c => fail!("unknown escape code: \\%c", c)
				}
			}
			c if !was_escape => acc.push_char(c),
			_ => { was_escape = false }
		}
	}

	// we didn't hit the end " so there must be a parse error
	None
}

/// Reads a list
fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None if read_nows(input, i) == Some(')') => return Some((~List(list), i)),
			None => return None
		}
	}
}

/// Reads an atom (symbol/identifier)
fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| !isws(c) && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

/// Reads any S-expression value
fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len()) {
		return None
	}

	match input[start] as char {
		c if isws(c) => read_value(input, start+1), // ignore whitespace
		'(' => read_list(input, start+1),
		')' => None,
		'"' => read_string(input, start),
		c if c.is_digit() || c == '.' => read_number(input, start),
		_ => read_atom(input, start)
	}
}

/// Public function for parsing a value from a string
pub fn from_str(input: &str) -> Option<Value> {
	match read_value(input, 0) {
		Some((v,_)) => Some(*v),
		None => None
	}
}

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

	fn parse_some(input: &str, expr: Value) {
		match from_str(input) {
			Some(ref p) if p == &expr => {}
			Some(ref p) => {
				if(p != &expr) {
					fail!("Expected %?, not %?, for %?", expr, *p, input)
				}
			}
			None => fail!("Got None for %?", input)
		}
	}

	#[test]
	fn test_sexpr() {
		assert_eq!(from_str(""), None);
		parse_some("123", Num(123.0));
		parse_some("()", List(~[]));
		parse_some("3.14159265358", Num(3.14159265358));
		parse_some("(hi)", List(~[Atom(~"hi")]));
		parse_some("(1)", List(~[Num(1.0)]));
		parse_some("(hi there)", List(~[Atom(~"hi"), Atom(~"there")]));
		parse_some("(hi (there))", List(~[Atom(~"hi"), List(~[Atom(~"there")])]));
		parse_some("(hi 123456)", List(~[Atom(~"hi"), Num(123456.0)]));
		parse_some("(())", List(~[List(~[])]));
		parse_some("(hi (there (fellow (human-bot!))))",
			List(~[Atom(~"hi"),
				List(~[Atom(~"there"),
					List(~[Atom(~"fellow"),
						List(~[Atom(~"human-bot!")])])])])
		);
	}

	#[test]
	fn test_string() {
		parse_some("\"\"", Str(~""));
		parse_some("\"string\"", Str(~"string"));
		parse_some("\"hi\tthere\n\"", Str(~"hi\tthere\n"));
		parse_some("\"a\\\\b\"", Str(~"a\\b"));
		parse_some("(\"hello\" \"world\")", List(~[Str(~"hello"), Str(~"world")]));
	}

	#[test]
	fn test_whitespace() {
		// spaces
		parse_some("  (  1  )  ", List(~[Num(1.0)]));
		parse_some("  (  (  )  )  )", List(~[List(~[])]));

		// newlines
		parse_some("\n\n( \n\n )\n\n", List(~[]));
		parse_some("\n\n(\n\n123\n\n)\n\n", List(~[Num(123.0)]));
	}
}<|endoftext|>


<commit_before>use lazy_static::lazy_static;

use super::{week2, year1, Manufacturer, Matcher, MatcherDef, Year};

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HexInverter {
    pub manufacturer: Option<Manufacturer>,
    pub chip_type: Option<String>,
    pub year: Option<Year>,
    pub week: Option<u8>,
}

/// ```
/// # use gbhwdb_backend::parser::parse_hex_inverter;
/// assert!(parse_hex_inverter("LVX 04 8 45").is_some());
/// ```
fn tc74lvx04ft() -> MatcherDef<HexInverter> {
    MatcherDef(
        r#"^LVX\ 04\ ([0-9])\ ([0-9]{2})$"#,
        move |c| {
            Ok(HexInverter {
                manufacturer: Some(Manufacturer::Toshiba),
                chip_type: Some("TC74LVX04FT".to_owned()),
                year: Some(year1(&c[1])?),
                week: Some(week2(&c[2])?),
            })
        },
    )
}

pub fn parse_hex_inverter(text: &str) -> Option<HexInverter> {
    lazy_static! {
        static ref MATCHER: Matcher<HexInverter> = tc74lvx04ft().into();
    }
    MATCHER.apply(text)
}
<commit_msg>Reformat<commit_after>use lazy_static::lazy_static;

use super::{week2, year1, Manufacturer, Matcher, MatcherDef, Year};

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HexInverter {
    pub manufacturer: Option<Manufacturer>,
    pub chip_type: Option<String>,
    pub year: Option<Year>,
    pub week: Option<u8>,
}

/// ```
/// # use gbhwdb_backend::parser::parse_hex_inverter;
/// assert!(parse_hex_inverter("LVX 04 8 45").is_some());
/// ```
fn tc74lvx04ft() -> MatcherDef<HexInverter> {
    MatcherDef(r#"^LVX\ 04\ ([0-9])\ ([0-9]{2})$"#, move |c| {
        Ok(HexInverter {
            manufacturer: Some(Manufacturer::Toshiba),
            chip_type: Some("TC74LVX04FT".to_owned()),
            year: Some(year1(&c[1])?),
            week: Some(week2(&c[2])?),
        })
    })
}

pub fn parse_hex_inverter(text: &str) -> Option<HexInverter> {
    lazy_static! {
        static ref MATCHER: Matcher<HexInverter> = tc74lvx04ft().into();
    }
    MATCHER.apply(text)
}
<|endoftext|>


<commit_before>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
// Packages required:
//
// - OpenGLES
// - GLFW
// - cgmath
//
//============================================================================

#[license = "BSD"];

#[allow(deprecated_owned_vector)];
#[allow(dead_code)];

extern crate native;
extern crate num;

extern crate opengles;
extern crate glfw;
extern crate cgmath;

use opengles::gl2;

use cgmath::vector::Vec3;
use cgmath::aabb::Aabb3;

use num::complex::{Cmplx, Complex64};

use std::num::{sin};

type Vec3f = Vec3<f32>;
type AABB3f = Aabb3<f32>;

//----------------------------------------------------------------------------

static vertex_shader_source: &'static str = "

#version 150

in vec2 position;
in vec3 color;

out vec3 Color;

void main()
{
    Color = color;
    gl_Position = vec4(position, 0.0, 1.0);
}
";

static fragment_shader_source: &'static str = "

#version 150

in vec3 Color;
out vec4 outColor;

void main()
{
    outColor = vec4(Color, 1.0);
}
";

//----------------------------------------------------------------------------

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
    fn call(&self, _: glfw::Error, description: ~str) {
        println!("GLFW Error: {:s}", description);
    }
}

//----------------------------------------------------------------------------

struct WindowController<'a> {
    window: &'a glfw::Window,
    vertices: ~[f32],
    vao: ~[gl2::GLuint],
    vbo: ~[gl2::GLuint],
    vertex_shader: gl2::GLuint,
    fragment_shader: gl2::GLuint,
    shader_program: gl2::GLuint,
    uni_color: gl2::GLint,
}

impl<'a> WindowController<'a> {
    fn new(window: &'a glfw::Window) -> WindowController<'a> {
        let mut wc = WindowController { window: window,
                                        vao: ~[0],
                                        vbo: ~[0],
                                        vertices: ~[],
                                        vertex_shader: 0,
                                        fragment_shader: 0,
                                        shader_program: 0,
                                        uni_color: 0,
        };

        let (width, height) =  wc.window.get_framebuffer_size();

        gl2::viewport(0, 0, width as i32, height as i32);

        println!("Viewport: {} x {}", width, height);

        wc.vertices = ~[
            0.0,  0.5, 1.0, 0.0, 0.0,
            0.5, -0.5, 0.0, 1.0, 0.0,
            -0.5, -0.5, 0.0, 0.0, 1.0,
            ];

        // VAO

        wc.vao = gl2::gen_vertex_arrays(1);
        gl2::bind_vertex_array(wc.vao[0]);

        // VBO

        wc.vbo = gl2::gen_buffers(1);
        gl2::bind_buffer(gl2::ARRAY_BUFFER, wc.vbo[0]);
        gl2::buffer_data(gl2::ARRAY_BUFFER, wc.vertices, gl2::STATIC_DRAW);

        // Vertex Shader

        wc.vertex_shader = gl2::create_shader(gl2::VERTEX_SHADER);

        if wc.vertex_shader == 0 {
            fail!("Create v.shader failed");
        }

        gl2::shader_source(wc.vertex_shader, [vertex_shader_source.to_owned().as_bytes()]);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glShaderSource.v err 0x{:x}", err);
        }

        gl2::compile_shader(wc.vertex_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glCompileShader.f err 0x{:x}", err);
        }

        let status = gl2::get_shader_iv(wc.vertex_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.vertex_shader);
            fail!("glCompileShader.v err 0x{:x}: {}", status, log);
        }

        // Fragment Shader

        wc.fragment_shader = gl2::create_shader(gl2::FRAGMENT_SHADER);

        if wc.vertex_shader == 0 {
            fail!("Create f.shader failed");
        }

        gl2::shader_source(wc.fragment_shader, [fragment_shader_source.to_owned().as_bytes()]);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glShaderSource.f -> 0x{:x}", err);
        }

        gl2::compile_shader(wc.fragment_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glCompileShader.v err 0x{:x}", err);
        }

        let status = gl2::get_shader_iv(wc.fragment_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.fragment_shader);
            fail!("glCompileShader.f err 0x{:x}: {}", status, log);
        }

        // Link

        wc.shader_program = gl2::create_program();

        if wc.shader_program == 0 {
            fail!("glCreateProgram failed");
        }

        gl2::attach_shader(wc.shader_program, wc.vertex_shader);
        gl2::attach_shader(wc.shader_program, wc.fragment_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glAttachShader err 0x{:x}", err);
        }

        gl2::link_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glLinkProgram err 0x{:x}", err);
        }

        let status = gl2::get_program_iv(wc.shader_program, gl2::LINK_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.shader_program);
            fail!("glLinkProgram err {}: {}", status, log);
        }

        gl2::use_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            let log = gl2::get_program_info_log(wc.shader_program);
            fail!("glUseProgram error: {}", log);
        }

        // Attributes

        let pos_attrib = gl2::get_attrib_location(wc.shader_program, "position");
        gl2::enable_vertex_attrib_array(pos_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(pos_attrib as gl2::GLuint, 2, false, 5*4, 0);

        let col_attrib = gl2::get_attrib_location(wc.shader_program, "color");
        gl2::enable_vertex_attrib_array(col_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(col_attrib as gl2::GLuint, 3, false, 5*4, 2*4);

        // Uniforms

        wc.uni_color = gl2::get_uniform_location(wc.shader_program, "triangleColor");

        let err = gl2::get_error();
        if err != 0 {
            fail!("attrib err = {:x}", err);
        }

        wc
    }

    fn draw(&self) {

        // Clear

        gl2::clear_color(0.4, 0.4, 0.4, 1.0);
        gl2::clear(gl2::COLOR_BUFFER_BIT);

        // Animate

        let time = glfw::get_time();
        gl2::uniform_3f(self.uni_color, (sin(time * 4.0f32 as f64) as f32 + 1.0f32) / 2.0f32, 0.0f32, 0.0f32);

        // Draw!

        gl2::draw_arrays(gl2::TRIANGLES, 0, 3);

        let err = gl2::get_error();
        if err != 0 {
            println!("draw err = 0x{:x}", err);
        }

        self.window.swap_buffers();
    }

    fn uninit(&mut self) {

        // Cleanup

        gl2::delete_program(self.shader_program);
        gl2::delete_shader(self.fragment_shader);
        gl2::delete_shader(self.vertex_shader);

        gl2::delete_buffers(self.vbo);

        // @todo Missing from bindings
        //gl2::delete_vertex_arrays(vao);
    }

    fn handle_window_event(&self, window: &glfw::Window, (time, event): (f64, glfw::WindowEvent)) {
        match event {

            glfw::CloseEvent => println!("Time: {}, Window close requested.", time),

            glfw::KeyEvent(key, scancode, action, mods) => {
                println!("Time: {}, Key: {}, ScanCode: {}, Action: {}, Modifiers: [{}]", time, key, scancode, action, mods);
                match (key, action) {
                    (glfw::KeyEscape, glfw::Press) => window.set_should_close(true),
                    (glfw::KeyR, glfw::Press) => {
                        // Resize should cause the window to "refresh"
                        let (window_width, window_height) = window.get_size();
                        window.set_size(window_width + 1, window_height);
                        window.set_size(window_width, window_height);
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

//----------------------------------------------------------------------------

struct MandelEngine {
    re0: f32,
    re1: f32,
    im0: f32,
    im1: f32,
    delta: f32,
}

impl MandelEngine {

    fn new() -> MandelEngine {
        MandelEngine { re0: -2.0, re1: 2.0, im0: -2.0, im1: 2.0, delta: 0.1 }
    }

    // Evalute entire region
    fn process(&self) {
        println!("+++ process: re: {}..{} im: {}..{}", self.re0, self.re1, self.im0, self.im1);
        // @todo range_step doesn't work for floats :( It needs CheckedAdd for f32. So we do loops manually.
        let mut re = self.re0;
        while re < self.re1 {
            let mut im = self.im0;
            while im < self.im1 {
                let z = Cmplx::new(re as f64, im as f64);
                println!("z={}+{}i, c={}", re, im, self.mandel(z));
                im += self.delta;
            }
            re += self.delta;
        }
        println!("--- process");
    }

    // Evaluate a single point
    fn mandel(&self, z: Complex64) -> uint {
        let maxiter: uint = 80;
        let mut c: Complex64 = z;
        for n in range(0, maxiter) {
            if c.norm() > 2.0 {
                return n;
            }
            c = c*c+z;
        }
        return maxiter;
    }
}

//----------------------------------------------------------------------------

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

fn main() {

    println!("GLFW version: {:s}", glfw::get_version_string());

    glfw::start(proc() {

        glfw::window_hint::context_version_major(3);
        glfw::window_hint::context_version_minor(2);
        glfw::window_hint::opengl_forward_compat(true);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);
        glfw::window_hint::resizable(false);

        let window = glfw::Window::create(640, 480,
                                          "MandelRust",
                                          glfw::Windowed)
            .expect("Failed to create GLFW window.");

        window.make_context_current();

        let win_ctrl = ~WindowController::new(&window);

        let engine = MandelEngine::new();
        native::task::spawn( proc() { engine.process(); });

        while !window.should_close() {
            glfw::poll_events();
            for event in window.flush_events() {
                win_ctrl.handle_window_event(&window, event);
            }
        }
    });
}
<commit_msg>Add render to event loop<commit_after>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
// Packages required:
//
// - OpenGLES
// - GLFW
// - cgmath
//
//============================================================================

#[license = "BSD"];

#[allow(deprecated_owned_vector)];
#[allow(dead_code)];

extern crate native;
extern crate num;

extern crate opengles;
extern crate glfw;
extern crate cgmath;

use opengles::gl2;

use cgmath::vector::Vec3;
use cgmath::aabb::Aabb3;

use num::complex::{Cmplx, Complex64};

use std::num::{sin};

type Vec3f = Vec3<f32>;
type AABB3f = Aabb3<f32>;

//----------------------------------------------------------------------------

static vertex_shader_source: &'static str = "

#version 150

in vec2 position;
in vec3 color;

out vec3 Color;

void main()
{
    Color = color;
    gl_Position = vec4(position, 0.0, 1.0);
}
";

static fragment_shader_source: &'static str = "

#version 150

in vec3 Color;
out vec4 outColor;

void main()
{
    outColor = vec4(Color, 1.0);
}
";

//----------------------------------------------------------------------------

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
    fn call(&self, _: glfw::Error, description: ~str) {
        println!("GLFW Error: {:s}", description);
    }
}

//----------------------------------------------------------------------------

struct WindowController<'a> {
    window: &'a glfw::Window,
    vertices: ~[f32],
    vao: ~[gl2::GLuint],
    vbo: ~[gl2::GLuint],
    vertex_shader: gl2::GLuint,
    fragment_shader: gl2::GLuint,
    shader_program: gl2::GLuint,
    uni_color: gl2::GLint,
}

impl<'a> WindowController<'a> {
    fn new(window: &'a glfw::Window) -> WindowController<'a> {
        let mut wc = WindowController { window: window,
                                        vao: ~[0],
                                        vbo: ~[0],
                                        vertices: ~[],
                                        vertex_shader: 0,
                                        fragment_shader: 0,
                                        shader_program: 0,
                                        uni_color: 0,
        };

        let (width, height) =  wc.window.get_framebuffer_size();

        gl2::viewport(0, 0, width as i32, height as i32);

        println!("Viewport: {} x {}", width, height);

        wc.vertices = ~[
            0.0,  0.5, 1.0, 0.0, 0.0,
            0.5, -0.5, 0.0, 1.0, 0.0,
            -0.5, -0.5, 0.0, 0.0, 1.0,
            ];

        // VAO

        wc.vao = gl2::gen_vertex_arrays(1);
        gl2::bind_vertex_array(wc.vao[0]);

        // VBO

        wc.vbo = gl2::gen_buffers(1);
        gl2::bind_buffer(gl2::ARRAY_BUFFER, wc.vbo[0]);
        gl2::buffer_data(gl2::ARRAY_BUFFER, wc.vertices, gl2::STATIC_DRAW);

        // Vertex Shader

        wc.vertex_shader = gl2::create_shader(gl2::VERTEX_SHADER);

        if wc.vertex_shader == 0 {
            fail!("Create v.shader failed");
        }

        gl2::shader_source(wc.vertex_shader, [vertex_shader_source.to_owned().as_bytes()]);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glShaderSource.v err 0x{:x}", err);
        }

        gl2::compile_shader(wc.vertex_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glCompileShader.f err 0x{:x}", err);
        }

        let status = gl2::get_shader_iv(wc.vertex_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.vertex_shader);
            fail!("glCompileShader.v err 0x{:x}: {}", status, log);
        }

        // Fragment Shader

        wc.fragment_shader = gl2::create_shader(gl2::FRAGMENT_SHADER);

        if wc.vertex_shader == 0 {
            fail!("Create f.shader failed");
        }

        gl2::shader_source(wc.fragment_shader, [fragment_shader_source.to_owned().as_bytes()]);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glShaderSource.f -> 0x{:x}", err);
        }

        gl2::compile_shader(wc.fragment_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glCompileShader.v err 0x{:x}", err);
        }

        let status = gl2::get_shader_iv(wc.fragment_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.fragment_shader);
            fail!("glCompileShader.f err 0x{:x}: {}", status, log);
        }

        // Link

        wc.shader_program = gl2::create_program();

        if wc.shader_program == 0 {
            fail!("glCreateProgram failed");
        }

        gl2::attach_shader(wc.shader_program, wc.vertex_shader);
        gl2::attach_shader(wc.shader_program, wc.fragment_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glAttachShader err 0x{:x}", err);
        }

        gl2::link_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glLinkProgram err 0x{:x}", err);
        }

        let status = gl2::get_program_iv(wc.shader_program, gl2::LINK_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.shader_program);
            fail!("glLinkProgram err {}: {}", status, log);
        }

        gl2::use_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            let log = gl2::get_program_info_log(wc.shader_program);
            fail!("glUseProgram error: {}", log);
        }

        // Attributes

        let pos_attrib = gl2::get_attrib_location(wc.shader_program, "position");
        gl2::enable_vertex_attrib_array(pos_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(pos_attrib as gl2::GLuint, 2, false, 5*4, 0);

        let col_attrib = gl2::get_attrib_location(wc.shader_program, "color");
        gl2::enable_vertex_attrib_array(col_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(col_attrib as gl2::GLuint, 3, false, 5*4, 2*4);

        // Uniforms

        wc.uni_color = gl2::get_uniform_location(wc.shader_program, "triangleColor");

        let err = gl2::get_error();
        if err != 0 {
            fail!("attrib err = {:x}", err);
        }

        wc
    }

    fn draw(&self) {

        // Clear

        gl2::clear_color(0.4, 0.4, 0.4, 1.0);
        gl2::clear(gl2::COLOR_BUFFER_BIT);

        // Animate

        let time = glfw::get_time();
        gl2::uniform_3f(self.uni_color, (sin(time * 4.0f32 as f64) as f32 + 1.0f32) / 2.0f32, 0.0f32, 0.0f32);

        // Draw!

        gl2::draw_arrays(gl2::TRIANGLES, 0, 3);

        let err = gl2::get_error();
        if err != 0 {
            println!("draw err = 0x{:x}", err);
        }

        self.window.swap_buffers();
    }

    fn uninit(&mut self) {

        // Cleanup

        gl2::delete_program(self.shader_program);
        gl2::delete_shader(self.fragment_shader);
        gl2::delete_shader(self.vertex_shader);

        gl2::delete_buffers(self.vbo);

        // @todo Missing from bindings
        //gl2::delete_vertex_arrays(vao);
    }

    fn handle_window_event(&self, window: &glfw::Window, (time, event): (f64, glfw::WindowEvent)) {
        match event {

            glfw::CloseEvent => println!("Time: {}, Window close requested.", time),

            glfw::KeyEvent(key, scancode, action, mods) => {
                println!("Time: {}, Key: {}, ScanCode: {}, Action: {}, Modifiers: [{}]", time, key, scancode, action, mods);
                match (key, action) {
                    (glfw::KeyEscape, glfw::Press) => window.set_should_close(true),
                    (glfw::KeyR, glfw::Press) => {
                        // Resize should cause the window to "refresh"
                        let (window_width, window_height) = window.get_size();
                        window.set_size(window_width + 1, window_height);
                        window.set_size(window_width, window_height);
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

//----------------------------------------------------------------------------

struct MandelEngine {
    re0: f32,
    re1: f32,
    im0: f32,
    im1: f32,
    delta: f32,
}

impl MandelEngine {

    fn new() -> MandelEngine {
        MandelEngine { re0: -2.0, re1: 2.0, im0: -2.0, im1: 2.0, delta: 0.1 }
    }

    // Evalute entire region
    fn process(&self) {
        println!("+++ process: re: {}..{} im: {}..{}", self.re0, self.re1, self.im0, self.im1);
        // @todo range_step doesn't work for floats :( It needs CheckedAdd for f32. So we do loops manually.
        let mut re = self.re0;
        while re < self.re1 {
            let mut im = self.im0;
            while im < self.im1 {
                let z = Cmplx::new(re as f64, im as f64);
                println!("z={}+{}i, c={}", re, im, self.mandel(z));
                im += self.delta;
            }
            re += self.delta;
        }
        println!("--- process");
    }

    // Evaluate a single point
    fn mandel(&self, z: Complex64) -> uint {
        let maxiter: uint = 80;
        let mut c: Complex64 = z;
        for n in range(0, maxiter) {
            if c.norm() > 2.0 {
                return n;
            }
            c = c*c+z;
        }
        return maxiter;
    }
}

//----------------------------------------------------------------------------

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

fn main() {

    println!("GLFW version: {:s}", glfw::get_version_string());

    glfw::start(proc() {

        glfw::window_hint::context_version_major(3);
        glfw::window_hint::context_version_minor(2);
        glfw::window_hint::opengl_forward_compat(true);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);
        glfw::window_hint::resizable(false);

        let window = glfw::Window::create(640, 480,
                                          "MandelRust",
                                          glfw::Windowed)
            .expect("Failed to create GLFW window.");

        window.make_context_current();

        let win_ctrl = ~WindowController::new(&window);

        let engine = MandelEngine::new();
        native::task::spawn( proc() { engine.process(); });

        while !window.should_close() {
            glfw::poll_events();
            for event in window.flush_events() {
                win_ctrl.handle_window_event(&window, event);
            }
            win_ctrl.draw();
        }
    });
}
<|endoftext|>


<commit_before>use std;
use std::boxed::Box;
use std::cell::Cell;
use std::os::raw::c_void;
use neon_runtime;
use neon_runtime::raw;
use neon_runtime::scope::Root;
use types::{JsObject, JsValue};
use handle::{Handle, Managed};
use object::class::ClassMap;
use result::{JsResult, NeonResult};
use super::ModuleContext;

#[cfg(feature = "legacy-runtime")]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Env(raw::Isolate);

#[cfg(feature = "napi-runtime")]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Env(raw::Env);

extern "C" fn drop_class_map(map: Box<ClassMap>) {
    std::mem::drop(map);
}

impl Env {
    #[cfg(feature = "legacy-runtime")]
    pub(crate) fn to_raw(self) -> raw::Isolate {
        let Self(ptr) = self;
        ptr
    }

    #[cfg(feature = "napi-runtime")]
    pub(crate) fn to_raw(self) -> raw::Env {
        let Self(ptr) = self;
        ptr
    }

    pub(crate) fn class_map(&mut self) -> &mut ClassMap {
        let mut ptr: *mut c_void = unsafe { neon_runtime::class::get_class_map(self.to_raw()) };
        if ptr.is_null() {
            let b: Box<ClassMap> = Box::new(ClassMap::new());
            let raw = Box::into_raw(b);
            ptr = unsafe { std::mem::transmute(raw) };
            let free_map: *mut c_void = unsafe { std::mem::transmute(drop_class_map as usize) };
            unsafe {
                neon_runtime::class::set_class_map(self.to_raw(), ptr, free_map);
            }
        }
        unsafe { std::mem::transmute(ptr) }
    }

    #[cfg(feature = "napi-runtime")]
    pub(crate) fn current() -> Env {
        panic!("Context::current() will not implemented with n-api")
    }

    #[cfg(feature = "legacy-runtime")]
    pub(crate) fn current() -> Env {
        unsafe {
            std::mem::transmute(neon_runtime::call::current_isolate())
        }
    }
}

pub struct ScopeMetadata {
    env: Env,
    active: Cell<bool>
}

pub struct Scope<'a, R: Root + 'static> {
    pub metadata: ScopeMetadata,
    pub handle_scope: &'a mut R
}

impl<'a, R: Root + 'static> Scope<'a, R> {
    pub fn with<T, F: for<'b> FnOnce(Scope<'b, R>) -> T>(env: Env, f: F) -> T {
        let mut handle_scope: R = unsafe { R::allocate() };
        unsafe {
            handle_scope.enter(env.to_raw());
        }
        let result = {
            let scope = Scope {
                metadata: ScopeMetadata {
                    env,
                    active: Cell::new(true)
                },
                handle_scope: &mut handle_scope
            };
            f(scope)
        };
        unsafe {
            handle_scope.exit(env.to_raw());
        }
        result
    }
}

pub trait ContextInternal<'a>: Sized {
    fn scope_metadata(&self) -> &ScopeMetadata;

    fn env(&self) -> Env {
        self.scope_metadata().env
    }

    fn is_active(&self) -> bool {
        self.scope_metadata().active.get()
    }

    fn check_active(&self) {
        if !self.is_active() {
            panic!("execution context is inactive");
        }
    }

    fn activate(&self) { self.scope_metadata().active.set(true); }
    fn deactivate(&self) { self.scope_metadata().active.set(false); }

    fn try_catch_internal<'b: 'a, F>(&mut self, f: F) -> Result<Handle<'a, JsValue>, Handle<'a, JsValue>>
        where F: FnOnce(&mut Self) -> JsResult<'b, JsValue>
    {
        let p = Box::into_raw(Box::new(f)) as *mut c_void;
        let mut local: raw::Local = unsafe { std::mem::zeroed() };
        let threw = unsafe { neon_runtime::try_catch::with(try_catch_glue::<Self, F>, self as *mut Self as *mut c_void, p, &mut local) };
        if threw {
            Err(JsValue::new_internal(local))
        } else {
            Ok(JsValue::new_internal(local))
        }
    }
}

extern "C" fn try_catch_glue<'a, 'b: 'a, C: ContextInternal<'a>, F>(p: *mut c_void, cx: *mut c_void, ok: *mut bool, ok_value: *mut raw::Local)
    where C: ContextInternal<'a>,
          F: FnOnce(&mut C) -> JsResult<'b, JsValue>
{
    let f: F = *unsafe { Box::from_raw(p as *mut F) };

    // FIXME: convert_panics(f)
    match f(unsafe { std::mem::transmute(cx) }) {
        Ok(result) => unsafe {
            *ok = true;
            *ok_value = result.to_raw();
        }
        Err(_) => unsafe {
            *ok = false;
        }
    }
}

#[cfg(feature = "legacy-runtime")]
pub fn initialize_module(exports: Handle<JsObject>, init: fn(ModuleContext) -> NeonResult<()>) {
    let env = Env::current();

    ModuleContext::with(env, exports, |cx| {
        let _ = init(cx);
    });
}

#[cfg(feature = "napi-runtime")]
pub fn initialize_module(env: raw::Env, exports: Handle<JsObject>, init: fn(ModuleContext) -> NeonResult<()>) {
    ModuleContext::with(Env(env), exports, |cx| {
        let _ = init(cx);
    });
}
<commit_msg>Use `MaybeUninit` instead of raw pointers.<commit_after>use std;
use std::boxed::Box;
use std::cell::Cell;
use std::mem::MaybeUninit;
use std::os::raw::c_void;
use neon_runtime;
use neon_runtime::raw;
use neon_runtime::scope::Root;
use types::{JsObject, JsValue};
use handle::{Handle, Managed};
use object::class::ClassMap;
use result::{JsResult, NeonResult};
use super::ModuleContext;

#[cfg(feature = "legacy-runtime")]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Env(raw::Isolate);

#[cfg(feature = "napi-runtime")]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Env(raw::Env);

extern "C" fn drop_class_map(map: Box<ClassMap>) {
    std::mem::drop(map);
}

impl Env {
    #[cfg(feature = "legacy-runtime")]
    pub(crate) fn to_raw(self) -> raw::Isolate {
        let Self(ptr) = self;
        ptr
    }

    #[cfg(feature = "napi-runtime")]
    pub(crate) fn to_raw(self) -> raw::Env {
        let Self(ptr) = self;
        ptr
    }

    pub(crate) fn class_map(&mut self) -> &mut ClassMap {
        let mut ptr: *mut c_void = unsafe { neon_runtime::class::get_class_map(self.to_raw()) };
        if ptr.is_null() {
            let b: Box<ClassMap> = Box::new(ClassMap::new());
            let raw = Box::into_raw(b);
            ptr = unsafe { std::mem::transmute(raw) };
            let free_map: *mut c_void = unsafe { std::mem::transmute(drop_class_map as usize) };
            unsafe {
                neon_runtime::class::set_class_map(self.to_raw(), ptr, free_map);
            }
        }
        unsafe { std::mem::transmute(ptr) }
    }

    #[cfg(feature = "napi-runtime")]
    pub(crate) fn current() -> Env {
        panic!("Context::current() will not implemented with n-api")
    }

    #[cfg(feature = "legacy-runtime")]
    pub(crate) fn current() -> Env {
        unsafe {
            std::mem::transmute(neon_runtime::call::current_isolate())
        }
    }
}

pub struct ScopeMetadata {
    env: Env,
    active: Cell<bool>
}

pub struct Scope<'a, R: Root + 'static> {
    pub metadata: ScopeMetadata,
    pub handle_scope: &'a mut R
}

impl<'a, R: Root + 'static> Scope<'a, R> {
    pub fn with<T, F: for<'b> FnOnce(Scope<'b, R>) -> T>(env: Env, f: F) -> T {
        let mut handle_scope: R = unsafe { R::allocate() };
        unsafe {
            handle_scope.enter(env.to_raw());
        }
        let result = {
            let scope = Scope {
                metadata: ScopeMetadata {
                    env,
                    active: Cell::new(true)
                },
                handle_scope: &mut handle_scope
            };
            f(scope)
        };
        unsafe {
            handle_scope.exit(env.to_raw());
        }
        result
    }
}

pub trait ContextInternal<'a>: Sized {
    fn scope_metadata(&self) -> &ScopeMetadata;

    fn env(&self) -> Env {
        self.scope_metadata().env
    }

    fn is_active(&self) -> bool {
        self.scope_metadata().active.get()
    }

    fn check_active(&self) {
        if !self.is_active() {
            panic!("execution context is inactive");
        }
    }

    fn activate(&self) { self.scope_metadata().active.set(true); }
    fn deactivate(&self) { self.scope_metadata().active.set(false); }

    fn try_catch_internal<'b: 'a, F>(&mut self, f: F) -> Result<Handle<'a, JsValue>, Handle<'a, JsValue>>
        where F: FnOnce(&mut Self) -> JsResult<'b, JsValue>
    {
        let p = Box::into_raw(Box::new(f)) as *mut c_void;
        let mut local: MaybeUninit<raw::Local> = MaybeUninit::zeroed();
        let threw = unsafe { neon_runtime::try_catch::with(try_catch_glue::<Self, F>, self as *mut Self as *mut c_void, p, &mut *local.as_mut_ptr()) };
        let local = unsafe { local.assume_init() };
        if threw {
            Err(JsValue::new_internal(local))
        } else {
            Ok(JsValue::new_internal(local))
        }
    }
}

extern "C" fn try_catch_glue<'a, 'b: 'a, C: ContextInternal<'a>, F>(p: *mut c_void, cx: *mut c_void, ok: *mut bool, ok_value: *mut raw::Local)
    where C: ContextInternal<'a>,
          F: FnOnce(&mut C) -> JsResult<'b, JsValue>
{
    let f: F = *unsafe { Box::from_raw(p as *mut F) };

    // FIXME: convert_panics(f)
    match f(unsafe { std::mem::transmute(cx) }) {
        Ok(result) => unsafe {
            *ok = true;
            *ok_value = result.to_raw();
        }
        Err(_) => unsafe {
            *ok = false;
        }
    }
}

#[cfg(feature = "legacy-runtime")]
pub fn initialize_module(exports: Handle<JsObject>, init: fn(ModuleContext) -> NeonResult<()>) {
    let env = Env::current();

    ModuleContext::with(env, exports, |cx| {
        let _ = init(cx);
    });
}

#[cfg(feature = "napi-runtime")]
pub fn initialize_module(env: raw::Env, exports: Handle<JsObject>, init: fn(ModuleContext) -> NeonResult<()>) {
    ModuleContext::with(Env(env), exports, |cx| {
        let _ = init(cx);
    });
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Write;

fn main() {
    const PI: f64 = 3.14;
    let mut radius: String = String::new();

    print!("Enter radius of circle: ");
    io::stdout().flush().unwrap();

    io::stdin().read_line(&mut radius)
        .expect("Failed to read");

    let radius: f64 = radius.trim().parse()
        .expect("Please input a number");

    let area: f64 = PI * radius * radius;
    let circumference: f64 = PI * 2.0 * radius;

    println!("Area of circle: {}", area);
    println!("Circumference of circle: {}", circumference);
}
<commit_msg>Add comment in program to explain why I do this<commit_after>use std::io;
use std::io::Write; // This is used for flushing

fn main() {
    const PI: f64 = 3.14;
    let mut radius: String = String::new();

    print!("Enter radius of circle: ");
    io::stdout().flush().unwrap(); // macro print cannot autoflush

    io::stdin().read_line(&mut radius)
        .expect("Failed to read");

    let radius: f64 = radius.trim().parse()
        .expect("Please input a number"); // Don't forget except while parsing

    let area: f64 = PI * radius * radius;
    let circumference: f64 = PI * 2.0 * radius;

    println!("Area of circle: {}", area);
    println!("Circumference of circle: {}", circumference);
}
<|endoftext|>


<commit_before>pub mod client;
pub mod lsm;
pub mod sm;
mod trees;

#[cfg(test)]
mod tests {
    use super::lsm::btree::storage;
    use super::lsm::btree::Ordering;
    use super::*;
    use crate::client::*;
    use crate::index::ranged::lsm::btree;
    use crate::index::EntryKey;
    use crate::ram::cell::*;
    use crate::ram::schema::*;
    use crate::ram::types::Id;
    use crate::ram::types::*;
    use crate::server::*;
    use futures::stream::FuturesUnordered;
    use itertools::Itertools;
    use rand::seq::SliceRandom;
    use std::sync::Arc;
    use std::time::Duration;
    use tokio_stream::StreamExt;

    // #[ignore]
    #[tokio::test(flavor = "multi_thread")]
    async fn general() {
        let _ = env_logger::try_init();
        let server_group = "ranged_index_test";
        let server_addr = String::from("127.0.0.1:5711");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 32 * 1024 * 1024 * 1024, // G
                backup_storage: None,
                wal_storage: None,
                services: vec![Service::Cell, Service::RangedIndexer],
            },
            &server_addr,
            server_group,
        )
        .await;
        let client = Arc::new(
            AsyncClient::new(
                &server.rpc,
                &server.membership,
                &vec![server_addr],
                server_group,
            )
            .await
            .unwrap(),
        );
        let index_client = Arc::new(
            client::RangedQueryClient::new(&server.consh, &server.raft_client, &client).await,
        );
        client.new_schema_with_id(schema()).await.unwrap().unwrap();
        let test_capacity = btree::ideal_capacity_from_node_size(btree::level::LEVEL_1) * 3;
        let mut futs = FuturesUnordered::new();
        info!(
            "Testing ranged indexer preesure test with {} items",
            test_capacity
        );
        debug!("Generating test set");
        let mut rng = rand::thread_rng();
        let mut nums = (0..test_capacity).collect_vec();
        let mut nums_2 = nums.clone();
        nums.as_mut_slice().shuffle(&mut rng);
        nums_2.as_mut_slice().shuffle(&mut rng);
        debug!("Adding insertion tasks");
        for i in nums {
            let index_client = index_client.clone();
            let client = client.clone();
            futs.push(tokio::spawn(async move {
                let id = Id::new(1, i as u64);
                let key = EntryKey::from_id(&id);
                let mut data_map = Map::new();
                data_map.insert("data", Value::U64(i as u64));
                let cell = Cell::new_with_id(11, &id, Value::Map(data_map));
                client.write_cell(cell).await.unwrap().unwrap();
                index_client.insert(&key).await
            }));
        }
        info!("All tasks queued, waiting for finish");
        while let Some(result) = futs.next().await {
            assert!(result.unwrap().unwrap(), "Insertion return false");
        }
        info!("All keys inserted. The background task should merging trees. Doing searches.");
        let mut futs = FuturesUnordered::new();
        for (i, num) in nums_2.into_iter().enumerate() {
            let index_client = index_client.clone();
            futs.push(tokio::spawn(async move {
                trace!("Seeking Id at {}, index {}", num, i);
                let id = Id::new(1, num as u64);
                let key = EntryKey::from_id(&id);
                let rt_cursor =
                    client::RangedQueryClient::seek(&index_client, &key, Ordering::Forward)
                        .await
                        .unwrap()
                        .unwrap();
                assert_eq!(id, rt_cursor.current().unwrap().0, "at {}", i);
                trace!("Id at {}, index {} have been checked", num, i);
            }));
        }
        while let Some(_) = futs.next().await {}
        debug!("Selection check pased, waiting for 10 secs");
        tokio::time::sleep(Duration::from_secs(10)).await;
        info!("Waiting tree storage");
        storage::wait_until_updated().await;
        info!(
            "Total cells {}, Tree stat {:?}",
            client.count().await.unwrap(),
            index_client.tree_stats().await.unwrap()
        );

        info!("Scanning forward...");
        let mut rt_cursor = client::RangedQueryClient::seek(
            &index_client,
            &EntryKey::from_id(&Id::new(1, 0)),
            Ordering::Forward,
        )
        .await
        .unwrap()
        .unwrap();
        for num in 0..test_capacity {
            let id = Id::new(1, num as u64);
            let current = rt_cursor.current().unwrap().0;
            assert_eq!(id, current);
            let _ = rt_cursor.next().await.unwrap();
            if num % (test_capacity / 128) == 0 {
                debug!("Scanned {} of {}", num, test_capacity);
            }
        }
        info!("Scan finished");
        let end_of_list = rt_cursor.next().await.unwrap();
        assert!(
            end_of_list.is_none(),
            "End of the list have id {:?}",
            end_of_list.unwrap().0
        );
        assert!(
            end_of_list.is_none(),
            "After end of the list have id {:?}",
            end_of_list.unwrap().0
        );
        info!(
            "Total cells {}, Tree stat {:?}",
            client.count().await.unwrap(),
            index_client.tree_stats().await.unwrap()
        );
        panic!("Explicit panic for error discovery");
    }

    fn schema() -> Schema {
        Schema {
            id: 11,
            name: String::from("test"),
            key_field: None,
            str_key_field: None,
            fields: Field::new(
                "*",
                0,
                false,
                false,
                Some(vec![Field::new("data", 10, false, false, None, vec![])]),
                vec![],
            ),
            is_dynamic: false,
        }
    }
}
<commit_msg>cell verifier<commit_after>pub mod client;
pub mod lsm;
pub mod sm;
mod trees;

#[cfg(test)]
mod tests {
    use super::lsm::btree::storage;
    use super::lsm::btree::Ordering;
    use super::*;
    use crate::client::*;
    use crate::index::ranged::lsm::btree;
    use crate::index::EntryKey;
    use crate::ram::cell::*;
    use crate::ram::schema::*;
    use crate::ram::types::Id;
    use crate::ram::types::*;
    use crate::server::*;
    use futures::stream::FuturesUnordered;
    use itertools::Itertools;
    use rand::seq::SliceRandom;
    use std::sync::Arc;
    use std::time::Duration;
    use tokio_stream::StreamExt;

    // #[ignore]
    #[tokio::test(flavor = "multi_thread")]
    async fn general() {
        let _ = env_logger::try_init();
        let server_group = "ranged_index_test";
        let server_addr = String::from("127.0.0.1:5711");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 32 * 1024 * 1024 * 1024, // G
                backup_storage: None,
                wal_storage: None,
                services: vec![Service::Cell, Service::RangedIndexer],
            },
            &server_addr,
            server_group,
        )
        .await;
        let client = Arc::new(
            AsyncClient::new(
                &server.rpc,
                &server.membership,
                &vec![server_addr],
                server_group,
            )
            .await
            .unwrap(),
        );
        let index_client = Arc::new(
            client::RangedQueryClient::new(&server.consh, &server.raft_client, &client).await,
        );
        client.new_schema_with_id(schema()).await.unwrap().unwrap();
        let test_capacity = btree::ideal_capacity_from_node_size(btree::level::LEVEL_1) * 3;
        let mut futs = FuturesUnordered::new();
        info!(
            "Testing ranged indexer preesure test with {} items",
            test_capacity
        );
        info!("Generating test set");
        let mut rng = rand::thread_rng();
        let mut nums = (0..test_capacity).collect_vec();
        let mut nums_2 = nums.clone();
        let mut nums_3 = nums.clone();
        nums.as_mut_slice().shuffle(&mut rng);
        nums_2.as_mut_slice().shuffle(&mut rng);
        nums_3.as_mut_slice().shuffle(&mut rng);
        info!("Adding insertion tasks");
        for i in nums_2 {
            let index_client = index_client.clone();
            let client = client.clone();
            futs.push(tokio::spawn(async move {
                let id = Id::new(1, i as u64);
                let key = EntryKey::from_id(&id);
                let mut data_map = Map::new();
                data_map.insert("data", Value::U64(i as u64));
                let cell = Cell::new_with_id(11, &id, Value::Map(data_map));
                client.write_cell(cell).await.unwrap().unwrap();
                index_client.insert(&key).await
            }));
        }
        info!("All tasks queued, waiting for finish");
        while let Some(result) = futs.next().await {
            assert!(result.unwrap().unwrap(), "Insertion return false");
        }
        info!("Verifiying insertion");
        for i in &nums {
            let id = Id::new(1, *i as u64);
            let cell_res = client.read_cell(id).await.unwrap();
            match cell_res {
                Ok(cell) => {
                    assert_eq!(*cell.data["data"].U64().unwrap(), *i as u64);
                },
                Err(e) => {
                    panic!("Expecting cell, found error {:?}", e);
                }
            }
        }
        info!("All keys inserted. The background task should merging trees. Doing searches.");
        let mut futs = FuturesUnordered::new();
        for (i, num) in nums_3.into_iter().enumerate() {
            let index_client = index_client.clone();
            futs.push(tokio::spawn(async move {
                trace!("Seeking Id at {}, index {}", num, i);
                let id = Id::new(1, num as u64);
                let key = EntryKey::from_id(&id);
                let rt_cursor =
                    client::RangedQueryClient::seek(&index_client, &key, Ordering::Forward)
                        .await
                        .unwrap()
                        .unwrap();
                assert_eq!(id, rt_cursor.current().unwrap().0, "at {}", i);
                trace!("Id at {}, index {} have been checked", num, i);
            }));
        }
        while let Some(_) = futs.next().await {}
        debug!("Selection check pased, waiting for 10 secs");
        tokio::time::sleep(Duration::from_secs(10)).await;
        info!("Waiting tree storage");
        storage::wait_until_updated().await;
        info!(
            "Total cells {}, Tree stat {:?}",
            client.count().await.unwrap(),
            index_client.tree_stats().await.unwrap()
        );
        info!("Verifiying insertion round 2");
        for i in &nums {
            let id = Id::new(1, *i as u64);
            let cell_res = client.read_cell(id).await.unwrap();
            match cell_res {
                Ok(cell) => {
                    assert_eq!(*cell.data["data"].U64().unwrap(), *i as u64);
                },
                Err(e) => {
                    panic!("Expecting cell at round 2, found error {:?}", e);
                }
            }
        }
        info!("Scanning forward...");
        let mut rt_cursor = client::RangedQueryClient::seek(
            &index_client,
            &EntryKey::from_id(&Id::new(1, 0)),
            Ordering::Forward,
        )
        .await
        .unwrap()
        .unwrap();
        for num in &nums {
            let id = Id::new(1, *num as u64);
            let current = rt_cursor.current().unwrap().0;
            assert_eq!(id, current);
            let _ = rt_cursor.next().await.unwrap();
            if num % (test_capacity / 128) == 0 {
                debug!("Scanned {} of {}", num, test_capacity);
            }
        }
        info!("Scan finished");
        let end_of_list = rt_cursor.next().await.unwrap();
        assert!(
            end_of_list.is_none(),
            "End of the list have id {:?}",
            end_of_list.unwrap().0
        );
        assert!(
            end_of_list.is_none(),
            "After end of the list have id {:?}",
            end_of_list.unwrap().0
        );
        info!(
            "Total cells {}, Tree stat {:?}",
            client.count().await.unwrap(),
            index_client.tree_stats().await.unwrap()
        );
        panic!("Explicit panic for error discovery");
    }

    fn schema() -> Schema {
        Schema {
            id: 11,
            name: String::from("test"),
            key_field: None,
            str_key_field: None,
            fields: Field::new(
                "*",
                0,
                false,
                false,
                Some(vec![Field::new("data", 10, false, false, None, vec![])]),
                vec![],
            ),
            is_dynamic: false,
        }
    }
}
<|endoftext|>


<commit_before>use hyper::*;
use hyper::client::Response;
use hyper::header::Headers;
use std::io::Read;

pub fn delete(path: &'static str, token: Option<String>) -> (Response, String) {
    let mut response = Client::new()
        .delete(&url(path))
        .headers(headers(token))
        .send()
        .unwrap();

    let mut content = String::new();
    response.read_to_string(&mut content).unwrap();

    (response, content)
}

pub fn get(path: &'static str, token: Option<String>) -> (Response, String) {
    let mut response = Client::new()
        .get(&url(path))
        .headers(headers(token))
        .send()
        .unwrap();

    let mut result = String::new();
    response.read_to_string(&mut result).unwrap();

    (response, result)
}

pub fn post(path: &'static str, body: Option<String>, token: Option<String>) -> (Response, String) {
    let client = Client::new();

    let mut request = client.post(&url(path))
        .headers(headers(token));

    request = match body {
        Some(ref body) => request.body(body),
        None => request,
    };

    let mut response = request.send().unwrap();

    let mut content = String::new();
    response.read_to_string(&mut content).unwrap();

    (response, content)
}

pub fn valid_token() -> Option<String> {
    Some("goodtokenfortests".to_string())
}

fn headers(token: Option<String>) -> Headers {
    use hyper::header::{Authorization, Bearer, ContentType, Headers};
    use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

    let mut headers = Headers::new();

    if let Some(token) = token {
        headers.set(Authorization(Bearer { token: token }))
    }

    headers.set(
        ContentType(
            Mime(
                TopLevel::Application,
                SubLevel::Json,
                vec![(Attr::Charset, Value::Utf8)]
            )
        )
    );

    headers
}

fn url(path: &'static str) -> String {
    use dotenv::dotenv;
    use std::env;

    dotenv().ok();

    let hostname = env::var("LUGH_BIND")
        .expect("LUGH_BIND must be set");

    "http://".to_string() + hostname.as_str() + path
}
<commit_msg>Add has_happened_now() helper for tests<commit_after>use hyper::*;
use hyper::client::Response;
use hyper::header::Headers;
use std::io::Read;

pub fn delete(path: &'static str, token: Option<String>) -> (Response, String) {
    let mut response = Client::new()
        .delete(&url(path))
        .headers(headers(token))
        .send()
        .unwrap();

    let mut content = String::new();
    response.read_to_string(&mut content).unwrap();

    (response, content)
}

pub fn get(path: &'static str, token: Option<String>) -> (Response, String) {
    let mut response = Client::new()
        .get(&url(path))
        .headers(headers(token))
        .send()
        .unwrap();

    let mut result = String::new();
    response.read_to_string(&mut result).unwrap();

    (response, result)
}

pub fn post(path: &'static str, body: Option<String>, token: Option<String>) -> (Response, String) {
    let client = Client::new();

    let mut request = client.post(&url(path))
        .headers(headers(token));

    request = match body {
        Some(ref body) => request.body(body),
        None => request,
    };

    let mut response = request.send().unwrap();

    let mut content = String::new();
    response.read_to_string(&mut content).unwrap();

    (response, content)
}

pub fn valid_token() -> Option<String> {
    Some("goodtokenfortests".to_string())
}

pub fn has_happened_now(time_str: &str) -> bool {
    use time::{Duration, now_utc, strptime};

    let time = strptime(time_str, "%F %T").unwrap();
    let now = now_utc();
    let min = now - Duration::seconds(1);

    time > min && time <= now
}

fn headers(token: Option<String>) -> Headers {
    use hyper::header::{Authorization, Bearer, ContentType, Headers};
    use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

    let mut headers = Headers::new();

    if let Some(token) = token {
        headers.set(Authorization(Bearer { token: token }))
    }

    headers.set(
        ContentType(
            Mime(
                TopLevel::Application,
                SubLevel::Json,
                vec![(Attr::Charset, Value::Utf8)]
            )
        )
    );

    headers
}

fn url(path: &'static str) -> String {
    use dotenv::dotenv;
    use std::env;

    dotenv().ok();

    let hostname = env::var("LUGH_BIND")
        .expect("LUGH_BIND must be set");

    "http://".to_string() + hostname.as_str() + path
}
<|endoftext|>


<commit_before>extern crate concurrent;

#[cfg(test)]
mod semaphore_prim {

    use super::concurrent::primitives::Semaphore;

    use std::thread;

    #[test]
    fn it_should_not_acquired_more_than_semaphore_contains_with_try_acquire() {
        let mut s = Semaphore::new(3);

        let res1 = s.try_acquire();
        let res2 = s.try_acquire();
        let res3 = s.try_acquire();
        let res4 = s.try_acquire();

        assert_eq!(res1, Some(3));
        assert_eq!(res2, Some(2));
        assert_eq!(res3, Some(1));
        assert_eq!(res4, None);
    }

    #[test]
    fn thread_should_try_to_acquire_resource() {
        let mut s = Semaphore::new(1);

        let res = s.acquire();
        thread::spawn(
            move || {
                let try_res = s.try_acquire();
                assert_eq!(try_res, None);
            }
        );
        assert_eq!(res, Some(1));
    }

    #[test]
    fn it_should_acquire_each_time_new_resource() {
        let mut s = Semaphore::new(3);

        let res3 = s.acquire();
        let res2 = s.acquire();

        assert_eq!(res3, Some(3));
        assert_eq!(res2, Some(2));
    }

    #[test]
    fn acquire_released_resource() {
        let mut s = Semaphore::new(3);

        let res = s.acquire();
        assert_eq!(res, Some(3));
        s.release();

        let reacquired_res = s.acquire();
        assert_eq!(reacquired_res, Some(3));
    }

    #[test]
    fn acquire_update_release_acquire_resource_with_new_value() {
        let mut s = Semaphore::new(1);
        let res_index = s.acquire();

        update_and_released(&mut s, 10, res_index.unwrap());

        let res_index = s.acquire();
        let res_val = s.get(res_index.unwrap());

        assert_eq!(res_val, Some(10));
    }

    fn update_and_released(semaphore: &mut Semaphore, update_to: usize, index: usize) {
        semaphore.update(index, update_to);
        semaphore.release();
    }

    #[test]
    fn acquire_update_released_multiple_resources() {
        let mut s = Semaphore::new(3);
        let res_index3 = s.acquire();
        let res_index2 = s.acquire();
        let res_index1 = s.acquire();

        update_and_released(&mut s, 10, res_index3.unwrap());
        update_and_released(&mut s, 20, res_index2.unwrap());
        update_and_released(&mut s, 30, res_index1.unwrap());

        let res_index3 = s.acquire();
        let res_index2 = s.acquire();
        let res_index1 = s.acquire();

        assert_eq!(s.get(res_index3.unwrap()), Some(10));
        assert_eq!(s.get(res_index2.unwrap()), Some(20));
        assert_eq!(s.get(res_index1.unwrap()), Some(30));
    }

    #[test]
    fn it_should_not_modify_semaphore_resource_when_modify_local_value_only() {
        let mut s = Semaphore::new(1);
        let index = s.acquire();

        let res = s.get(index.unwrap());
        let res = res.map(|v| v + 10);

        assert_eq!(res, Some(10));
        assert_eq!(s.get(index.unwrap()), Some(0));
    }

    //find a way how to prevent use resource when thread release it
    //test for locking thread on acquire method if there is no free resources semaphore has
}<commit_msg>todo list<commit_after>extern crate concurrent;

#[cfg(test)]
mod semaphore_prim {

    use super::concurrent::primitives::Semaphore;

    use std::thread;

    #[test]
    fn it_should_not_acquired_more_than_semaphore_contains_with_try_acquire() {
        let mut s = Semaphore::new(3);

        let res1 = s.try_acquire();
        let res2 = s.try_acquire();
        let res3 = s.try_acquire();
        let res4 = s.try_acquire();

        assert_eq!(res1, Some(3));
        assert_eq!(res2, Some(2));
        assert_eq!(res3, Some(1));
        assert_eq!(res4, None);
    }

    #[test]
    fn thread_should_try_to_acquire_resource() {
        let mut s = Semaphore::new(1);

        let res = s.acquire();
        thread::spawn(
            move || {
                let try_res = s.try_acquire();
                assert_eq!(try_res, None);
            }
        );
        assert_eq!(res, Some(1));
    }

    #[test]
    fn it_should_acquire_each_time_new_resource() {
        let mut s = Semaphore::new(3);

        let res3 = s.acquire();
        let res2 = s.acquire();

        assert_eq!(res3, Some(3));
        assert_eq!(res2, Some(2));
    }

    #[test]
    fn acquire_released_resource() {
        let mut s = Semaphore::new(3);

        let res = s.acquire();
        assert_eq!(res, Some(3));
        s.release();

        let reacquired_res = s.acquire();
        assert_eq!(reacquired_res, Some(3));
    }

    #[test]
    fn acquire_update_release_acquire_resource_with_new_value() {
        let mut s = Semaphore::new(1);
        let res_index = s.acquire();

        update_and_released(&mut s, 10, res_index.unwrap());

        let res_index = s.acquire();
        let res_val = s.get(res_index.unwrap());

        assert_eq!(res_val, Some(10));
    }

    fn update_and_released(semaphore: &mut Semaphore, update_to: usize, index: usize) {
        semaphore.update(index, update_to);
        semaphore.release();
    }

    #[test]
    fn acquire_update_released_multiple_resources() {
        let mut s = Semaphore::new(3);
        let res_index3 = s.acquire();
        let res_index2 = s.acquire();
        let res_index1 = s.acquire();

        update_and_released(&mut s, 10, res_index3.unwrap());
        update_and_released(&mut s, 20, res_index2.unwrap());
        update_and_released(&mut s, 30, res_index1.unwrap());

        let res_index3 = s.acquire();
        let res_index2 = s.acquire();
        let res_index1 = s.acquire();

        assert_eq!(s.get(res_index3.unwrap()), Some(10));
        assert_eq!(s.get(res_index2.unwrap()), Some(20));
        assert_eq!(s.get(res_index1.unwrap()), Some(30));
    }

    #[test]
    fn it_should_not_modify_semaphore_resource_when_modify_local_value_only() {
        let mut s = Semaphore::new(1);
        let index = s.acquire();

        let res = s.get(index.unwrap());
        let res = res.map(|v| v + 10);

        assert_eq!(res, Some(10));
        assert_eq!(s.get(index.unwrap()), Some(0));
    }

    //todo
    //1. test when two thread modify different resources
    //2. find a way how to prevent use resource when thread release it
    //3. test for locking thread on acquire method if there is no free resources
    // optinal / specific functionality
    //4. acquire resourse which was released previously by the thread
}<|endoftext|>