<commit_before>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;

/// Object representing an HTTP response whose purpose is to be given to a `Request`.
///
/// Some headers cannot be changed. Trying to define the value
///  of one of these will have no effect:
///
///  - `Accept-Ranges`
///  - `Connection`
///  - `Content-Range`
///  - `Trailer`
///  - `Transfer-Encoding`
///  - `Upgrade`
///
/// Some headers have special behaviors:
///
///  - `Content-Encoding`: If you define this header, the library
///      will assume that the data from the `Reader` has the specified encoding
///      and will just pass-through.
///  - `Content-Length`: If you define this header to `N`, only the first `N` bytes
///      of the `Reader` will be read. If the `Reader` reaches `EOF` before `N` bytes have
///      been read, `0`s will be sent. Also, this header may not be passed to the final
///      output.
///
#[experimental]
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    data_length: Option<uint>,
}

/// Transfer encoding to use when sending the message.
/// Note that only *supported* encoding are listed here.
enum TransferEncoding {
    Identity,
    Chunked,
}

impl ::std::from_str::FromStr for TransferEncoding {
    fn from_str(input: &str) -> Option<TransferEncoding> {
        None
    }
}

/// Builds a Date: header with the current date.
// TODO: this is optimisable
fn build_date_header() -> Header {
    use time;
    let date = time::now_utc().strftime("%a, %d %b %Y %H:%M:%S GMT");
    from_str(format!("Date: {}", date).as_slice()).unwrap()
}

fn write_message_header<W: Writer>(mut writer: W, http_version: &HTTPVersion,
                                   status_code: &StatusCode, headers: &[Header])
    -> IoResult<()>
{
    // writing status line
    try!(write!(writer, "HTTP/{} {} {}\r\n",
        http_version,
        status_code.as_uint(),
        status_code.get_default_reason_phrase()
    ));

    // writing headers
    for header in headers.iter() {
        try!(write!(writer, "{}: {}\r\n", header.field, header.value));
    }

    // separator between header and data
    try!(write!(writer, "\r\n"));

    Ok(())
}

fn choose_transfer_encoding(request_headers: &[Header], http_version: &HTTPVersion,
                            entity_length: &Option<uint>)
    -> TransferEncoding
{
    use util;

    // HTTP 1.0 doesn't support other encoding
    if *http_version <= HTTPVersion(1, 0) {
        return Identity;
    }

    // parsing the request's TE header
    let user_request = request_headers.iter()
        // finding TE
        .find(|h| h.field.equiv(&"TE"))

        // getting its value
        .map(|h| h.value.as_slice())

        // getting the corresponding TransferEncoding
        .and_then(|value| {
            // getting list of requested elements
            let mut parse = util::parse_header_value(value);

            // sorting elements by most priority
            parse.sort_by(|a, b| b.val1().partial_cmp(&a.val1()).unwrap_or(Equal));

            // trying to parse each requested encoding
            for value in parse.iter() {
                match from_str::<TransferEncoding>(value.val0()) {
                    Some(te) => return Some(te),
                    _ => ()     // unrecognized/unsupported encoding
                };
            }

            // encoding not found
            None
        });

    //
    if user_request.is_some() {
        return user_request.unwrap();
    }

    // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
    let chunks_threshold = 32768;
    if entity_length.as_ref().filtered(|val| **val < chunks_threshold).is_none() {
        return Chunked;
    }

    // Identity by default
    Identity
}

impl<R: Reader> Response<R> {
    #[experimental]
    pub fn new(status_code: StatusCode, headers: Vec<Header>,
               data: R, data_length: Option<uint>) -> Response<R>
    {
        let mut response = Response {
            reader: data,
            status_code: status_code,
            headers: Vec::new(),
            data_length: data_length,
        };

        for h in headers.move_iter() {
            response.add_header(h)
        }

        response
    }

    /// Adds a header to the list.
    /// Does all the checks.
    #[experimental]
    pub fn add_header(&mut self, header: Header) {
        // ignoring forbidden headers
        if header.field.equiv(&"Accept-Ranges") ||
           header.field.equiv(&"Connection") ||
           header.field.equiv(&"Content-Range") ||
           header.field.equiv(&"Trailer") ||
           header.field.equiv(&"Transfer-Encoding") ||
           header.field.equiv(&"Upgrade")
        {
            return;
        }

        // if the header is Content-Length, setting the data length
        if header.field.equiv(&"Content-Length") {
            match from_str::<uint>(header.value.as_slice()) {
                Some(val) => self.data_length = Some(val),
                None => ()      // wrong value for content-length
            };

            return;
        }

        self.headers.push(header)
    }

    /// Returns the same request, but with an additional header.
    ///
    /// Some headers cannot be modified and some other have a
    ///  special behavior. See the documentation above.
    #[unstable]
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.add_header(header);
        self
    }

    /// Returns the same request, but with a different status code.
    #[unstable]
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Prints the HTTP response to a writer.
    ///
    /// This function is the one used to send the response to the client's socket.
    /// Therefore you shouldn't expect anything pretty-printed or even readable.
    ///
    /// The HTTP version and headers passed as arguments are used to
    ///  decide which features (most notably, encoding) to use.
    // TODO: status codes 1xx, 204 and 304 must not include a response body
    #[unstable]
    pub fn raw_print<W: Writer>(mut self, mut writer: W, http_version: HTTPVersion,
                                request_headers: &[Header]) -> IoResult<()>
    {
        let transfer_encoding = choose_transfer_encoding(request_headers,
                                    &http_version, &self.data_length);

        // add `Date` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Date")).is_none() {
            self.headers.unshift(build_date_header());
        }

        // add `Server` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                from_str("Server: tiny-http (Rust)").unwrap()
            );
        }

        // writing data
        match transfer_encoding {
            Chunked => {
                use util::ChunksEncoder;

                self.headers.push(
                    from_str("Transfer-Encoding: chunked").unwrap()
                );

                try!(write_message_header(writer.by_ref(), &http_version,
                    &self.status_code, self.headers.as_slice()));

                let mut writer = ChunksEncoder::new(writer);
                try!(util::copy(&mut self.reader, &mut writer));

                // flushing!
                try!(writer.flush());
            },

            Identity => {
                use util::EqualReader;

                assert!(self.data_length.is_some());
                let data_length = self.data_length.unwrap();

                self.headers.push(
                    from_str(format!("Content-Length: {}", data_length).as_slice()).unwrap()
                );

                try!(write_message_header(writer.by_ref(), &http_version,
                    &self.status_code, self.headers.as_slice()));

                if data_length >= 1 {
                    let (mut equ_reader, _) =
                        EqualReader::new(self.reader.by_ref(), data_length);
                    try!(util::copy(&mut equ_reader, &mut writer));
                }

                // flushing!
                try!(writer.flush());
            }
        };

        Ok(())
    }
}

impl Response<File> {
    /// Builds a new `Response` from a `File`.
    ///
    /// The `Content-Type` will **not** be automatically detected,
    ///  you must set it yourself.
    #[experimental]
    pub fn from_file(mut file: File) -> Response<File> {
        let file_size = file.stat().ok().map(|v| v.size as uint);

        Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            file_size
        )
    }
}

impl Response<MemReader> {
    #[experimental]
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            Some(data_len)
        )
    }

    #[experimental]
    pub fn from_string(data: String) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec!(
                from_str("Content-Type: text/plain; charset=UTF-8").unwrap()
            ),
            MemReader::new(data.into_bytes()),
            Some(data_len)
        )
    }
}

impl Response<NullReader> {
    /// Builds an empty `Response` with the given status code.
    #[experimental]
    pub fn new_empty(status_code: StatusCode) -> Response<NullReader> {
        Response::new(
            status_code,
            Vec::new(),
            NullReader,
            Some(0)
        )
    }
}
<commit_msg>TransferEncoding now parsed correctly<commit_after>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;

/// Object representing an HTTP response whose purpose is to be given to a `Request`.
///
/// Some headers cannot be changed. Trying to define the value
///  of one of these will have no effect:
///
///  - `Accept-Ranges`
///  - `Connection`
///  - `Content-Range`
///  - `Trailer`
///  - `Transfer-Encoding`
///  - `Upgrade`
///
/// Some headers have special behaviors:
///
///  - `Content-Encoding`: If you define this header, the library
///      will assume that the data from the `Reader` has the specified encoding
///      and will just pass-through.
///  - `Content-Length`: If you define this header to `N`, only the first `N` bytes
///      of the `Reader` will be read. If the `Reader` reaches `EOF` before `N` bytes have
///      been read, `0`s will be sent. Also, this header may not be passed to the final
///      output.
///
#[experimental]
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    data_length: Option<uint>,
}

/// Transfer encoding to use when sending the message.
/// Note that only *supported* encoding are listed here.
enum TransferEncoding {
    Identity,
    Chunked,
}

impl ::std::from_str::FromStr for TransferEncoding {
    fn from_str(input: &str) -> Option<TransferEncoding> {
        use std::ascii::StrAsciiExt;

        if input.eq_ignore_ascii_case("identity") {
            return Some(Identity);
        } else if input.eq_ignore_ascii_case("chunked") {
            return Some(Chunked);
        }

        None
    }
}

/// Builds a Date: header with the current date.
// TODO: this is optimisable
fn build_date_header() -> Header {
    use time;
    let date = time::now_utc().strftime("%a, %d %b %Y %H:%M:%S GMT");
    from_str(format!("Date: {}", date).as_slice()).unwrap()
}

fn write_message_header<W: Writer>(mut writer: W, http_version: &HTTPVersion,
                                   status_code: &StatusCode, headers: &[Header])
    -> IoResult<()>
{
    // writing status line
    try!(write!(writer, "HTTP/{} {} {}\r\n",
        http_version,
        status_code.as_uint(),
        status_code.get_default_reason_phrase()
    ));

    // writing headers
    for header in headers.iter() {
        try!(write!(writer, "{}: {}\r\n", header.field, header.value));
    }

    // separator between header and data
    try!(write!(writer, "\r\n"));

    Ok(())
}

fn choose_transfer_encoding(request_headers: &[Header], http_version: &HTTPVersion,
                            entity_length: &Option<uint>)
    -> TransferEncoding
{
    use util;

    // HTTP 1.0 doesn't support other encoding
    if *http_version <= HTTPVersion(1, 0) {
        return Identity;
    }

    // parsing the request's TE header
    let user_request = request_headers.iter()
        // finding TE
        .find(|h| h.field.equiv(&"TE"))

        // getting its value
        .map(|h| h.value.as_slice())

        // getting the corresponding TransferEncoding
        .and_then(|value| {
            // getting list of requested elements
            let mut parse = util::parse_header_value(value);

            // sorting elements by most priority
            parse.sort_by(|a, b| b.val1().partial_cmp(&a.val1()).unwrap_or(Equal));

            // trying to parse each requested encoding
            for value in parse.iter() {
                match from_str::<TransferEncoding>(value.val0()) {
                    Some(te) => return Some(te),
                    _ => ()     // unrecognized/unsupported encoding
                };
            }

            // encoding not found
            None
        });

    //
    if user_request.is_some() {
        return user_request.unwrap();
    }

    // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
    let chunks_threshold = 32768;
    if entity_length.as_ref().filtered(|val| **val < chunks_threshold).is_none() {
        return Chunked;
    }

    // Identity by default
    Identity
}

impl<R: Reader> Response<R> {
    #[experimental]
    pub fn new(status_code: StatusCode, headers: Vec<Header>,
               data: R, data_length: Option<uint>) -> Response<R>
    {
        let mut response = Response {
            reader: data,
            status_code: status_code,
            headers: Vec::new(),
            data_length: data_length,
        };

        for h in headers.move_iter() {
            response.add_header(h)
        }

        response
    }

    /// Adds a header to the list.
    /// Does all the checks.
    #[experimental]
    pub fn add_header(&mut self, header: Header) {
        // ignoring forbidden headers
        if header.field.equiv(&"Accept-Ranges") ||
           header.field.equiv(&"Connection") ||
           header.field.equiv(&"Content-Range") ||
           header.field.equiv(&"Trailer") ||
           header.field.equiv(&"Transfer-Encoding") ||
           header.field.equiv(&"Upgrade")
        {
            return;
        }

        // if the header is Content-Length, setting the data length
        if header.field.equiv(&"Content-Length") {
            match from_str::<uint>(header.value.as_slice()) {
                Some(val) => self.data_length = Some(val),
                None => ()      // wrong value for content-length
            };

            return;
        }

        self.headers.push(header)
    }

    /// Returns the same request, but with an additional header.
    ///
    /// Some headers cannot be modified and some other have a
    ///  special behavior. See the documentation above.
    #[unstable]
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.add_header(header);
        self
    }

    /// Returns the same request, but with a different status code.
    #[unstable]
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Prints the HTTP response to a writer.
    ///
    /// This function is the one used to send the response to the client's socket.
    /// Therefore you shouldn't expect anything pretty-printed or even readable.
    ///
    /// The HTTP version and headers passed as arguments are used to
    ///  decide which features (most notably, encoding) to use.
    // TODO: status codes 1xx, 204 and 304 must not include a response body
    #[unstable]
    pub fn raw_print<W: Writer>(mut self, mut writer: W, http_version: HTTPVersion,
                                request_headers: &[Header]) -> IoResult<()>
    {
        let transfer_encoding = choose_transfer_encoding(request_headers,
                                    &http_version, &self.data_length);

        // add `Date` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Date")).is_none() {
            self.headers.unshift(build_date_header());
        }

        // add `Server` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                from_str("Server: tiny-http (Rust)").unwrap()
            );
        }

        // writing data
        match transfer_encoding {
            Chunked => {
                use util::ChunksEncoder;

                self.headers.push(
                    from_str("Transfer-Encoding: chunked").unwrap()
                );

                try!(write_message_header(writer.by_ref(), &http_version,
                    &self.status_code, self.headers.as_slice()));

                let mut writer = ChunksEncoder::new(writer);
                try!(util::copy(&mut self.reader, &mut writer));

                // flushing!
                try!(writer.flush());
            },

            Identity => {
                use util::EqualReader;

                assert!(self.data_length.is_some());
                let data_length = self.data_length.unwrap();

                self.headers.push(
                    from_str(format!("Content-Length: {}", data_length).as_slice()).unwrap()
                );

                try!(write_message_header(writer.by_ref(), &http_version,
                    &self.status_code, self.headers.as_slice()));

                if data_length >= 1 {
                    let (mut equ_reader, _) =
                        EqualReader::new(self.reader.by_ref(), data_length);
                    try!(util::copy(&mut equ_reader, &mut writer));
                }

                // flushing!
                try!(writer.flush());
            }
        };

        Ok(())
    }
}

impl Response<File> {
    /// Builds a new `Response` from a `File`.
    ///
    /// The `Content-Type` will **not** be automatically detected,
    ///  you must set it yourself.
    #[experimental]
    pub fn from_file(mut file: File) -> Response<File> {
        let file_size = file.stat().ok().map(|v| v.size as uint);

        Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            file_size
        )
    }
}

impl Response<MemReader> {
    #[experimental]
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            Some(data_len)
        )
    }

    #[experimental]
    pub fn from_string(data: String) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec!(
                from_str("Content-Type: text/plain; charset=UTF-8").unwrap()
            ),
            MemReader::new(data.into_bytes()),
            Some(data_len)
        )
    }
}

impl Response<NullReader> {
    /// Builds an empty `Response` with the given status code.
    #[experimental]
    pub fn new_empty(status_code: StatusCode) -> Response<NullReader> {
        Response::new(
            status_code,
            Vec::new(),
            NullReader,
            Some(0)
        )
    }
}
<|endoftext|>


<commit_before>//! Procedurally generating the game world.

use math::*;
use world::{Chunk, ChunkIndex, ChunkProvider, HeightType, HexPillar};
use world::{CHUNK_SIZE, GroundMaterial, PILLAR_STEP_HEIGHT, PillarSection, Prop, PropType};
use rand::{Rand, Rng};
use gen::PlantGenerator;
use noise::{PermutationTable, open_simplex2, open_simplex3};
use gen::seeded_rng;

// pub const LANDSCAPE_FLAT: f32 = 0.01;
// pub const LANDSCAPE_MODERATE: f32 = 0.05;
// pub const LANDSCAPE_HILLY: f32 = 0.1125;

/// Land "fill noise" scaling in x, y, and z direction.
const LAND_NOISE_SCALE: (f32, f32, f32) = (0.03, 0.03, 0.05);

/// Main type to generate the game world. Implements the `ChunkProvider` trait
/// (TODO, see #8).
pub struct WorldGenerator {
    seed: u64,
    terrain_table: PermutationTable,
    plant_table: PermutationTable,
}

impl WorldGenerator {
    /// Creates the generator with the given seed.
    pub fn with_seed(seed: u64) -> Self {
        let mut terrain_rng = seeded_rng(seed, 0, ());
        let mut plant_rng = seeded_rng(seed, 1, ());

        WorldGenerator {
            seed: seed,
            terrain_table: PermutationTable::rand(&mut terrain_rng),
            plant_table: PermutationTable::rand(&mut plant_rng),
        }
    }

    /// Returns the seed of this world generator.
    pub fn seed(&self) -> u64 {
        self.seed
    }
}

impl ChunkProvider for WorldGenerator {
    fn load_chunk(&self, index: ChunkIndex) -> Option<Chunk> {
        const WORLDGEN_HEIGHT: usize = 256;
        // Create a 3D-Array of booleans indicating which pillar sections to fill
        // (Map height is unlimited in theory, but we'll limit worldgen to 64 height
        // units)
        let mut fill = [[[false; WORLDGEN_HEIGHT]; CHUNK_SIZE as usize]; CHUNK_SIZE as usize];

        // Chunk start position in absolute axial coords
        let chunk_start = index.0 * CHUNK_SIZE as i32;
        for q in 0..CHUNK_SIZE {
            for r in 0..CHUNK_SIZE {
                for i in 0..WORLDGEN_HEIGHT {
                    let real_pos = (chunk_start + AxialVector::new(q as i32, r as i32)).to_real();
                    let x = real_pos.x;
                    let y = real_pos.y;
                    let z = i as f32 * PILLAR_STEP_HEIGHT;
                    let fill_noise = open_simplex3::<f32>(&self.terrain_table,
                                                          &[x * LAND_NOISE_SCALE.0,
                                                            y * LAND_NOISE_SCALE.1,
                                                            z * LAND_NOISE_SCALE.2]);

                    // The noise is (theoretically) in the range -1..1
                    // Map the noise to a range of 0..1
                    let fill_noise = (fill_noise + 1.0) / 2.0;

                    // Calculate threshold to fill this "block". The lower the threshold, the more
                    // likely this voxel is filled, so it should increase with height.
                    let height_pct = i as f32 / WORLDGEN_HEIGHT as f32;

                    // The threshold is calculated using a sigmoid function. These are the
                    // parameters used:

                    /// Minimum threshold to prevent threshold to reach 0,
                    /// needed to have any caves at all
                    const MIN_THRESH: f32 = 0.6;
                    /// "Steepness" of the sigmoid function.
                    const THRESH_STEEPNESS: f32 = 30.0;
                    /// Threshold at half value (max. steepness, avg. terrain
                    /// height)
                    const THRESH_MID: f32 = 0.5;

                    let sig_thresh =
                        1.0 / (1.0 + f32::exp(-THRESH_STEEPNESS * (height_pct - THRESH_MID)));

                    let threshold = (sig_thresh + MIN_THRESH) / (1.0 + MIN_THRESH);

                    fill[q as usize][r as usize][i as usize] = fill_noise > threshold;
                }
            }
        }

        Some(Chunk::with_pillars(index, |pos| {
            let real_pos = pos.to_real();
            let x = real_pos.x;
            let y = real_pos.y;

            // Pillar pos relative to first pillar
            let rel_pos = pos - index.0 * CHUNK_SIZE as i32;
            let column = &fill[rel_pos.q as usize][rel_pos.r as usize];

            // Create sections for all connected `true`s in the array
            let mut sections = Vec::new();
            let mut low = 0;
            let mut height = None;
            for i in 0..WORLDGEN_HEIGHT {
                match (height, column[i]) {
                    (Some(h), true) => {
                        // Next one's still solid, increase section height
                        height = Some(h + 1);
                    }
                    (Some(h), false) => {
                        // Create a section of height `h` and start over
                        sections.push(PillarSection::new(GroundMaterial::Dirt,
                                                         HeightType::from_units(low),
                                                         HeightType::from_units(low + h)));
                        height = None;
                    }
                    (None, true) => {
                        low = i as u16;
                        height = Some(1);
                    }
                    (None, false) => {}
                };
            }

            if let Some(h) = height {
                // Create the topmost pillar
                sections.push(PillarSection::new(GroundMaterial::Dirt,
                                                 HeightType::from_units(low),
                                                 HeightType::from_units(low + h)));
            }

            let mut props = Vec::new();

            let plant_noise = open_simplex2::<f32>(&self.plant_table,
                                                   &[(x as f32) * 0.08, (y as f32) * 0.08]);

            // Place a test plant every few blocks
            if plant_noise > 0.4 {
                let mut rng = super::seeded_rng(self.seed, "TREE", (pos.q, pos.r));
                if rng.next_f32() < plant_noise {
                    let gen = PlantGenerator::rand(&mut rng);

                    // put the tree at the highest position
                    let height = match sections.last() {
                        Some(section) => section.top,
                        None => HeightType::from_units(0),
                    };

                    props.push(Prop {
                        baseline: height,
                        prop: PropType::Plant(gen.generate(&mut rng)),
                    });
                }
            }

            HexPillar::new(sections, props)
        }))
    }

    fn is_chunk_loadable(&self, _: ChunkIndex) -> bool {
        // All chunks can be generated from nothing
        true
    }
}
<commit_msg>add a layer of solid ground at the bottom<commit_after>//! Procedurally generating the game world.

use math::*;
use world::{Chunk, ChunkIndex, ChunkProvider, HeightType, HexPillar};
use world::{CHUNK_SIZE, GroundMaterial, PILLAR_STEP_HEIGHT, PillarSection, Prop, PropType};
use rand::{Rand, Rng};
use gen::PlantGenerator;
use noise::{PermutationTable, open_simplex2, open_simplex3};
use gen::seeded_rng;

// pub const LANDSCAPE_FLAT: f32 = 0.01;
// pub const LANDSCAPE_MODERATE: f32 = 0.05;
// pub const LANDSCAPE_HILLY: f32 = 0.1125;

/// Land "fill noise" scaling in x, y, and z direction.
const LAND_NOISE_SCALE: (f32, f32, f32) = (0.03, 0.03, 0.05);

/// Main type to generate the game world. Implements the `ChunkProvider` trait
/// (TODO, see #8).
pub struct WorldGenerator {
    seed: u64,
    terrain_table: PermutationTable,
    plant_table: PermutationTable,
}

impl WorldGenerator {
    /// Creates the generator with the given seed.
    pub fn with_seed(seed: u64) -> Self {
        let mut terrain_rng = seeded_rng(seed, 0, ());
        let mut plant_rng = seeded_rng(seed, 1, ());

        WorldGenerator {
            seed: seed,
            terrain_table: PermutationTable::rand(&mut terrain_rng),
            plant_table: PermutationTable::rand(&mut plant_rng),
        }
    }

    /// Returns the seed of this world generator.
    pub fn seed(&self) -> u64 {
        self.seed
    }
}

impl ChunkProvider for WorldGenerator {
    fn load_chunk(&self, index: ChunkIndex) -> Option<Chunk> {
        const WORLDGEN_HEIGHT: usize = 256;
        // Create a 3D-Array of booleans indicating which pillar sections to fill
        // (Map height is unlimited in theory, but we'll limit worldgen to 64 height
        // units)
        let mut fill = [[[false; WORLDGEN_HEIGHT]; CHUNK_SIZE as usize]; CHUNK_SIZE as usize];

        // Chunk start position in absolute axial coords
        let chunk_start = index.0 * CHUNK_SIZE as i32;
        for q in 0..CHUNK_SIZE {
            for r in 0..CHUNK_SIZE {
                for i in 0..WORLDGEN_HEIGHT {
                    if i == 0 {
                        fill[q as usize][r as usize][i as usize] = true;
                        continue;
                    }

                    let real_pos = (chunk_start + AxialVector::new(q as i32, r as i32)).to_real();
                    let x = real_pos.x;
                    let y = real_pos.y;
                    let z = i as f32 * PILLAR_STEP_HEIGHT;
                    let fill_noise = open_simplex3::<f32>(&self.terrain_table,
                                                          &[x * LAND_NOISE_SCALE.0,
                                                            y * LAND_NOISE_SCALE.1,
                                                            z * LAND_NOISE_SCALE.2]);

                    // The noise is (theoretically) in the range -1..1
                    // Map the noise to a range of 0..1
                    let fill_noise = (fill_noise + 1.0) / 2.0;

                    // Calculate threshold to fill this "block". The lower the threshold, the more
                    // likely this voxel is filled, so it should increase with height.
                    let height_pct = i as f32 / WORLDGEN_HEIGHT as f32;

                    // The threshold is calculated using a sigmoid function. These are the
                    // parameters used:

                    /// Minimum threshold to prevent threshold to reach 0,
                    /// needed to have any caves at all
                    const MIN_THRESH: f32 = 0.6;
                    /// "Steepness" of the sigmoid function.
                    const THRESH_STEEPNESS: f32 = 30.0;
                    /// Threshold at half value (max. steepness, avg. terrain
                    /// height)
                    const THRESH_MID: f32 = 0.5;

                    let sig_thresh =
                        1.0 / (1.0 + f32::exp(-THRESH_STEEPNESS * (height_pct - THRESH_MID)));

                    let threshold = (sig_thresh + MIN_THRESH) / (1.0 + MIN_THRESH);

                    fill[q as usize][r as usize][i as usize] = fill_noise > threshold;
                }
            }
        }

        Some(Chunk::with_pillars(index, |pos| {
            let real_pos = pos.to_real();
            let x = real_pos.x;
            let y = real_pos.y;

            // Pillar pos relative to first pillar
            let rel_pos = pos - index.0 * CHUNK_SIZE as i32;
            let column = &fill[rel_pos.q as usize][rel_pos.r as usize];

            // Create sections for all connected `true`s in the array
            let mut sections = Vec::new();
            let mut low = 0;
            let mut height = None;
            for i in 0..WORLDGEN_HEIGHT {
                match (height, column[i]) {
                    (Some(h), true) => {
                        // Next one's still solid, increase section height
                        height = Some(h + 1);
                    }
                    (Some(h), false) => {
                        // Create a section of height `h` and start over
                        sections.push(PillarSection::new(GroundMaterial::Dirt,
                                                         HeightType::from_units(low),
                                                         HeightType::from_units(low + h)));
                        height = None;
                    }
                    (None, true) => {
                        low = i as u16;
                        height = Some(1);
                    }
                    (None, false) => {}
                };
            }

            if let Some(h) = height {
                // Create the topmost pillar
                sections.push(PillarSection::new(GroundMaterial::Dirt,
                                                 HeightType::from_units(low),
                                                 HeightType::from_units(low + h)));
            }

            let mut props = Vec::new();

            let plant_noise = open_simplex2::<f32>(&self.plant_table,
                                                   &[(x as f32) * 0.08, (y as f32) * 0.08]);

            // Place a test plant every few blocks
            if plant_noise > 0.4 {
                let mut rng = super::seeded_rng(self.seed, "TREE", (pos.q, pos.r));
                if rng.next_f32() < plant_noise {
                    let gen = PlantGenerator::rand(&mut rng);

                    // put the tree at the highest position
                    let height = match sections.last() {
                        Some(section) => section.top,
                        None => HeightType::from_units(0),
                    };

                    props.push(Prop {
                        baseline: height,
                        prop: PropType::Plant(gen.generate(&mut rng)),
                    });
                }
            }

            HexPillar::new(sections, props)
        }))
    }

    fn is_chunk_loadable(&self, _: ChunkIndex) -> bool {
        // All chunks can be generated from nothing
        true
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

//! # Serde code generator
//!
//! '''bash
//! cargo run --bin serdegen -- --help
//! '''

use serde_generate::{
    cpp, dart, golang, java, python3, rust, typescript, CodeGeneratorConfig, Encoding,
    SourceInstaller,
};
use serde_reflection::Registry;
use std::path::PathBuf;
use structopt::{clap::arg_enum, StructOpt};

arg_enum! {
#[derive(Debug, StructOpt)]
enum Language {
    Python3,
    Cpp,
    Rust,
    Java,
    Go,
    TypeScript,
    CSharp,
}
}

arg_enum! {
#[derive(Debug, StructOpt, PartialEq, Eq, PartialOrd, Ord)]
enum Runtime {
    Serde,
    Bincode,
    Bcs,
}
}

#[derive(Debug, StructOpt)]
#[structopt(
    name = "Serde code generator",
    about = "Generate code for Serde containers"
)]
struct Options {
    /// Path to the YAML-encoded Serde formats.
    #[structopt(parse(from_os_str))]
    input: Option<PathBuf>,

    /// Language for code generation.
    #[structopt(long, possible_values = &Language::variants(), case_insensitive = true, default_value = "Python3")]
    language: Language,

    /// Directory where to write generated modules (otherwise print code on stdout).
    #[structopt(long)]
    target_source_dir: Option<PathBuf>,

    /// Optional runtimes to install in the `target_source_dir` (if applicable).
    /// Also triggers the generation of specialized methods for each runtime.
    #[structopt(long, possible_values = &Runtime::variants(), case_insensitive = true)]
    with_runtimes: Vec<Runtime>,

    /// Module name for the Serde formats installed in the `target_source_dir`.
    /// Rust crates may contain a version number separated with a colon, e.g. "test:1.2.0".
    /// (By default, the installer will use version "0.1.0".)
    #[structopt(long)]
    module_name: Option<String>,

    /// Optional package name (Python) or module path (Go) where to find Serde runtime dependencies.
    #[structopt(long)]
    serde_package_name: Option<String>,

    /// Translate enums without variant data (c-style enums) into their equivalent in the target language,
    /// if the target language and the generator code support them.
    #[structopt(long)]
    use_c_style_enums: bool,
}

fn get_codegen_config<'a, I>(name: String, runtimes: I, c_style_enums: bool) -> CodeGeneratorConfig
where
    I: IntoIterator<Item = &'a Runtime>,
{
    let mut encodings = Vec::new();
    for runtime in runtimes {
        match runtime {
            Runtime::Bincode => {
                encodings.push(Encoding::Bincode);
            }
            Runtime::Bcs => {
                encodings.push(Encoding::Bcs);
            }
            _ => (),
        }
    }
    CodeGeneratorConfig::new(name)
        .with_encodings(encodings)
        .with_c_style_enums(c_style_enums)
}

fn main() {
    let options = Options::from_args();
    let serde_package_name_opt = options.serde_package_name.clone();
    let named_registry_opt = match &options.input {
        None => None,
        Some(input) => {
            let name = options.module_name.clone().unwrap_or_else(|| {
                input
                    .file_stem()
                    .expect("failed to deduce module name from input path")
                    .to_string_lossy()
                    .into_owned()
            });
            let content = std::fs::read_to_string(input).expect("input file must be readable");
            let registry = serde_yaml::from_str::<Registry>(content.as_str()).unwrap();
            Some((registry, name))
        }
    };
    let runtimes: std::collections::BTreeSet<_> = options.with_runtimes.into_iter().collect();

    match options.target_source_dir {
        None => {
            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes, options.use_c_style_enums);

                let stdout = std::io::stdout();
                let mut out = stdout.lock();
                match options.language {
                    Language::Python3 => python3::CodeGenerator::new(&config)
                        .with_serde_package_name(serde_package_name_opt)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Rust => rust::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Cpp => cpp::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Go => golang::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Java => {
                        panic!("Code generation in Java requires `--target-source-dir`")
                    }
                    Language::TypeScript => typescript::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::CSharp => {
                        panic!("Code generation in C# requires `--target-source-dir`")
                    }
                }
            }
        }

        Some(install_dir) => {
            let installer: Box<dyn SourceInstaller<Error = Box<dyn std::error::Error>>> =
                match options.language {
                    Language::Python3 => {
                        Box::new(python3::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::Rust => Box::new(rust::Installer::new(install_dir)),
                    Language::Cpp => Box::new(cpp::Installer::new(install_dir)),
                    Language::Java => Box::new(java::Installer::new(install_dir)),
                    Language::Go => {
                        Box::new(golang::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::Dart => Box::new(dart::Installer::new(install_dir)),
                    Language::TypeScript => Box::new(typescript::Installer::new(install_dir)),
                    Language::CSharp => Box::new(csharp::Installer::new(install_dir)),
                };

            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes, options.use_c_style_enums);
                installer.install_module(&config, &registry).unwrap();
            }

            for runtime in runtimes {
                match runtime {
                    Runtime::Serde => installer.install_serde_runtime().unwrap(),
                    Runtime::Bincode => installer.install_bincode_runtime().unwrap(),
                    Runtime::Bcs => installer.install_bcs_runtime().unwrap(),
                }
            }
        }
    }
}
<commit_msg>format code<commit_after>// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

//! # Serde code generator
//!
//! '''bash
//! cargo run --bin serdegen -- --help
//! '''

use serde_generate::{
    cpp, csharp, dart, golang, java, python3, rust, typescript, CodeGeneratorConfig, Encoding,
    SourceInstaller,
};
use serde_reflection::Registry;
use std::path::PathBuf;
use structopt::{clap::arg_enum, StructOpt};

arg_enum! {
#[derive(Debug, StructOpt)]
enum Language {
    Python3,
    Cpp,
    Rust,
    Java,
    Go,
    TypeScript,
    CSharp,
}
}

arg_enum! {
#[derive(Debug, StructOpt, PartialEq, Eq, PartialOrd, Ord)]
enum Runtime {
    Serde,
    Bincode,
    Bcs,
}
}

#[derive(Debug, StructOpt)]
#[structopt(
    name = "Serde code generator",
    about = "Generate code for Serde containers"
)]
struct Options {
    /// Path to the YAML-encoded Serde formats.
    #[structopt(parse(from_os_str))]
    input: Option<PathBuf>,

    /// Language for code generation.
    #[structopt(long, possible_values = &Language::variants(), case_insensitive = true, default_value = "Python3")]
    language: Language,

    /// Directory where to write generated modules (otherwise print code on stdout).
    #[structopt(long)]
    target_source_dir: Option<PathBuf>,

    /// Optional runtimes to install in the `target_source_dir` (if applicable).
    /// Also triggers the generation of specialized methods for each runtime.
    #[structopt(long, possible_values = &Runtime::variants(), case_insensitive = true)]
    with_runtimes: Vec<Runtime>,

    /// Module name for the Serde formats installed in the `target_source_dir`.
    /// Rust crates may contain a version number separated with a colon, e.g. "test:1.2.0".
    /// (By default, the installer will use version "0.1.0".)
    #[structopt(long)]
    module_name: Option<String>,

    /// Optional package name (Python) or module path (Go) where to find Serde runtime dependencies.
    #[structopt(long)]
    serde_package_name: Option<String>,

    /// Translate enums without variant data (c-style enums) into their equivalent in the target language,
    /// if the target language and the generator code support them.
    #[structopt(long)]
    use_c_style_enums: bool,
}

fn get_codegen_config<'a, I>(name: String, runtimes: I, c_style_enums: bool) -> CodeGeneratorConfig
where
    I: IntoIterator<Item = &'a Runtime>,
{
    let mut encodings = Vec::new();
    for runtime in runtimes {
        match runtime {
            Runtime::Bincode => {
                encodings.push(Encoding::Bincode);
            }
            Runtime::Bcs => {
                encodings.push(Encoding::Bcs);
            }
            _ => (),
        }
    }
    CodeGeneratorConfig::new(name)
        .with_encodings(encodings)
        .with_c_style_enums(c_style_enums)
}

fn main() {
    let options = Options::from_args();
    let serde_package_name_opt = options.serde_package_name.clone();
    let named_registry_opt = match &options.input {
        None => None,
        Some(input) => {
            let name = options.module_name.clone().unwrap_or_else(|| {
                input
                    .file_stem()
                    .expect("failed to deduce module name from input path")
                    .to_string_lossy()
                    .into_owned()
            });
            let content = std::fs::read_to_string(input).expect("input file must be readable");
            let registry = serde_yaml::from_str::<Registry>(content.as_str()).unwrap();
            Some((registry, name))
        }
    };
    let runtimes: std::collections::BTreeSet<_> = options.with_runtimes.into_iter().collect();

    match options.target_source_dir {
        None => {
            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes, options.use_c_style_enums);

                let stdout = std::io::stdout();
                let mut out = stdout.lock();
                match options.language {
                    Language::Python3 => python3::CodeGenerator::new(&config)
                        .with_serde_package_name(serde_package_name_opt)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Rust => rust::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Cpp => cpp::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Go => golang::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Java => {
                        panic!("Code generation in Java requires `--target-source-dir`")
                    }
                    Language::TypeScript => typescript::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::CSharp => {
                        panic!("Code generation in C# requires `--target-source-dir`")
                    }
                }
            }
        }

        Some(install_dir) => {
            let installer: Box<dyn SourceInstaller<Error = Box<dyn std::error::Error>>> =
                match options.language {
                    Language::Python3 => {
                        Box::new(python3::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::Rust => Box::new(rust::Installer::new(install_dir)),
                    Language::Cpp => Box::new(cpp::Installer::new(install_dir)),
                    Language::Java => Box::new(java::Installer::new(install_dir)),
                    Language::Go => {
                        Box::new(golang::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::Dart => Box::new(dart::Installer::new(install_dir)),
                    Language::TypeScript => Box::new(typescript::Installer::new(install_dir)),
                    Language::CSharp => Box::new(csharp::Installer::new(install_dir)),
                };

            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes, options.use_c_style_enums);
                installer.install_module(&config, &registry).unwrap();
            }

            for runtime in runtimes {
                match runtime {
                    Runtime::Serde => installer.install_serde_runtime().unwrap(),
                    Runtime::Bincode => installer.install_bincode_runtime().unwrap(),
                    Runtime::Bcs => installer.install_bcs_runtime().unwrap(),
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// FIXME: stolen from cargo. Should be extracted into a common crate.

//! Job management (mostly for Windows)
//!
//! Most of the time when you're running cargo you expect Ctrl-C to actually
//! terminate the entire tree of processes in play, not just the one at the top
//! (cago). This currently works "by default" on Unix platforms because Ctrl-C
//! actually sends a signal to the *process group* rather than the parent
//! process, so everything will get torn down. On Windows, however, this does
//! not happen and Ctrl-C just kills cargo.
//!
//! To achieve the same semantics on Windows we use Job Objects to ensure that
//! all processes die at the same time. Job objects have a mode of operation
//! where when all handles to the object are closed it causes all child
//! processes associated with the object to be terminated immediately.
//! Conveniently whenever a process in the job object spawns a new process the
//! child will be associated with the job object as well. This means if we add
//! ourselves to the job object we create then everything will get torn down!

#![allow(clippy::missing_safety_doc)]

pub(crate) use self::imp::Setup;

pub(crate) fn setup() -> Option<Setup> {
    unsafe { imp::setup() }
}

#[cfg(unix)]
mod imp {
    pub(crate) type Setup = ();

    pub(crate) unsafe fn setup() -> Option<()> {
        Some(())
    }
}

#[cfg(windows)]
mod imp {
    use std::io;
    use std::mem;
    use std::ptr;

    use winapi::shared::minwindef::*;
    use winapi::um::handleapi::*;
    use winapi::um::jobapi2::*;
    use winapi::um::processthreadsapi::*;
    use winapi::um::winnt::HANDLE;
    use winapi::um::winnt::*;

    pub(crate) struct Setup {
        job: Handle,
    }

    pub(crate) struct Handle {
        inner: HANDLE,
    }

    fn last_err() -> io::Error {
        io::Error::last_os_error()
    }

    pub(crate) unsafe fn setup() -> Option<Setup> {
        // Creates a new job object for us to use and then adds ourselves to it.
        // Note that all errors are basically ignored in this function,
        // intentionally. Job objects are "relatively new" in Windows,
        // particularly the ability to support nested job objects. Older
        // Windows installs don't support this ability. We probably don't want
        // to force Cargo to abort in this situation or force others to *not*
        // use job objects, so we instead just ignore errors and assume that
        // we're otherwise part of someone else's job object in this case.

        let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
        if job.is_null() {
            return None;
        }
        let job = Handle { inner: job };

        // Indicate that when all handles to the job object are gone that all
        // process in the object should be killed. Note that this includes our
        // entire process tree by default because we've added ourselves and
        // our children will reside in the job once we spawn a process.
        let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
        info = mem::zeroed();
        info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
        let r = SetInformationJobObject(
            job.inner,
            JobObjectExtendedLimitInformation,
            &mut info as *mut _ as LPVOID,
            mem::size_of_val(&info) as DWORD,
        );
        if r == 0 {
            return None;
        }

        // Assign our process to this job object, meaning that our children will
        // now live or die based on our existence.
        let me = GetCurrentProcess();
        let r = AssignProcessToJobObject(job.inner, me);
        if r == 0 {
            return None;
        }

        Some(Setup { job })
    }

    impl Drop for Setup {
        fn drop(&mut self) {
            // On normal exits (not ctrl-c), we don't want to kill any child
            // processes. The destructor here configures our job object to
            // *not* kill everything on close, then closes the job object.
            unsafe {
                let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
                info = mem::zeroed();
                let r = SetInformationJobObject(
                    self.job.inner,
                    JobObjectExtendedLimitInformation,
                    &mut info as *mut _ as LPVOID,
                    mem::size_of_val(&info) as DWORD,
                );
                if r == 0 {
                    info!("failed to configure job object to defaults: {}", last_err());
                }
            }
        }
    }

    impl Drop for Handle {
        fn drop(&mut self) {
            unsafe {
                CloseHandle(self.inner);
            }
        }
    }
}
<commit_msg>Fix typo in job.rs cago->cargo<commit_after>// FIXME: stolen from cargo. Should be extracted into a common crate.

//! Job management (mostly for Windows)
//!
//! Most of the time when you're running cargo you expect Ctrl-C to actually
//! terminate the entire tree of processes in play, not just the one at the top
//! (cargo). This currently works "by default" on Unix platforms because Ctrl-C
//! actually sends a signal to the *process group* rather than the parent
//! process, so everything will get torn down. On Windows, however, this does
//! not happen and Ctrl-C just kills cargo.
//!
//! To achieve the same semantics on Windows we use Job Objects to ensure that
//! all processes die at the same time. Job objects have a mode of operation
//! where when all handles to the object are closed it causes all child
//! processes associated with the object to be terminated immediately.
//! Conveniently whenever a process in the job object spawns a new process the
//! child will be associated with the job object as well. This means if we add
//! ourselves to the job object we create then everything will get torn down!

#![allow(clippy::missing_safety_doc)]

pub(crate) use self::imp::Setup;

pub(crate) fn setup() -> Option<Setup> {
    unsafe { imp::setup() }
}

#[cfg(unix)]
mod imp {
    pub(crate) type Setup = ();

    pub(crate) unsafe fn setup() -> Option<()> {
        Some(())
    }
}

#[cfg(windows)]
mod imp {
    use std::io;
    use std::mem;
    use std::ptr;

    use winapi::shared::minwindef::*;
    use winapi::um::handleapi::*;
    use winapi::um::jobapi2::*;
    use winapi::um::processthreadsapi::*;
    use winapi::um::winnt::HANDLE;
    use winapi::um::winnt::*;

    pub(crate) struct Setup {
        job: Handle,
    }

    pub(crate) struct Handle {
        inner: HANDLE,
    }

    fn last_err() -> io::Error {
        io::Error::last_os_error()
    }

    pub(crate) unsafe fn setup() -> Option<Setup> {
        // Creates a new job object for us to use and then adds ourselves to it.
        // Note that all errors are basically ignored in this function,
        // intentionally. Job objects are "relatively new" in Windows,
        // particularly the ability to support nested job objects. Older
        // Windows installs don't support this ability. We probably don't want
        // to force Cargo to abort in this situation or force others to *not*
        // use job objects, so we instead just ignore errors and assume that
        // we're otherwise part of someone else's job object in this case.

        let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
        if job.is_null() {
            return None;
        }
        let job = Handle { inner: job };

        // Indicate that when all handles to the job object are gone that all
        // process in the object should be killed. Note that this includes our
        // entire process tree by default because we've added ourselves and
        // our children will reside in the job once we spawn a process.
        let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
        info = mem::zeroed();
        info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
        let r = SetInformationJobObject(
            job.inner,
            JobObjectExtendedLimitInformation,
            &mut info as *mut _ as LPVOID,
            mem::size_of_val(&info) as DWORD,
        );
        if r == 0 {
            return None;
        }

        // Assign our process to this job object, meaning that our children will
        // now live or die based on our existence.
        let me = GetCurrentProcess();
        let r = AssignProcessToJobObject(job.inner, me);
        if r == 0 {
            return None;
        }

        Some(Setup { job })
    }

    impl Drop for Setup {
        fn drop(&mut self) {
            // On normal exits (not ctrl-c), we don't want to kill any child
            // processes. The destructor here configures our job object to
            // *not* kill everything on close, then closes the job object.
            unsafe {
                let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
                info = mem::zeroed();
                let r = SetInformationJobObject(
                    self.job.inner,
                    JobObjectExtendedLimitInformation,
                    &mut info as *mut _ as LPVOID,
                    mem::size_of_val(&info) as DWORD,
                );
                if r == 0 {
                    info!("failed to configure job object to defaults: {}", last_err());
                }
            }
        }
    }

    impl Drop for Handle {
        fn drop(&mut self) {
            unsafe {
                CloseHandle(self.inner);
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::{CompileError, is_truthy};
use super::scope::CowScope;
use super::identifier::IdMap;
use std::num::Float;
use std::f32::consts;

#[cfg(test)]
use super::lexer;
#[cfg(test)]
use super::{TRUE, FALSE};

/// Something that can be called with arguments given in the scope
pub trait Function {
	fn call(&self, scope: CowScope, idmap: &IdMap) -> Result<f32, CompileError>;
}

macro_rules! bind_function(
	( $name:ident, $func:ident ( $($arg:ident = $val:expr),* ) ) => {
		#[derive(Copy)]
		pub struct $name;
		impl $name {
			pub fn new() -> $name {
				$name
			}
		}
		impl Function for $name {
			#[allow(unused_variables)] // Compiler complains that scope is not used on functions with no args.
			fn call(&self, scope: CowScope, idmap: &IdMap) -> Result<f32, CompileError> {
				Ok($func($(
					// Insert each argument from the scope
					match scope.get_var(idmap.id(stringify!($arg))) {
						Some(val) => val,

						None => match $val {
							Some(val) => val,
							None => return Err(CompileError::new(format!("function `{}` requires argument `{}` but it is not defined in scope", stringify!($func), stringify!($arg)))),
						}
					}
				),*))
			}
		}
	};
);

fn sin(freq: f32, amp: f32, phase: f32, time: f32) -> f32 {
	(freq*time*consts::PI_2 + phase).sin()*amp
}

fn sqrt(x: f32) -> f32 {
	x.sqrt()
}

fn abs(x: f32) -> f32 {
	x.abs()
}

bind_function!(SinFunction, sin(freq=None, amp=Some(1_f32), phase=Some(0_f32), time=None));
bind_function!(SqrtFunction, sqrt(x=None));
bind_function!(AbsFunction, abs(x=None));

/// Always returns a specific constant
#[derive(Copy)]
pub struct ConstFunction {
	val: f32,
}
impl ConstFunction {
	pub fn new(val: f32) -> ConstFunction {
		ConstFunction {
			val: val,
		}
	}
}
impl Function for ConstFunction {
	fn call(&self, _: CowScope, _: &IdMap) -> Result<f32, CompileError> {
		Ok(self.val)
	}
}

/// Returns the result of calling the function if the condition is truthy, else 0
pub struct CondFunction<'a> {
	cond: &'a (Function + 'a),
	func: &'a (Function + 'a),
}
impl<'a> CondFunction<'a> {
	pub fn new(cond: &'a Function, func: &'a Function) -> CondFunction<'a> {
		CondFunction {
			cond: cond,
			func: func,
		}
	}
}
impl<'a> Function for CondFunction<'a> {
	fn call(&self, scope: CowScope, idmap: &IdMap) -> Result<f32, CompileError> {
		if is_truthy(try!(self.cond.call(scope.clone(), idmap))) {
			self.func.call(scope, idmap)
		} else {
			Ok(0_f32)
		}
	}
}

#[test]
fn const_function_test() {
	let f = ConstFunction::new(42_f32);
	assert_eq!(f.call(&Scope::new()).unwrap(), 42_f32);
}

#[test]
fn sin_test() {
	let mut s = Scope::new();
	s.define_var("freq", 440_f32);
	s.define_var("time", 0_f32);
	s.define_var("amp", 0.5_f32);
	let f = SinFunction::new();
	assert_eq!(f.call(&s).unwrap(), 0_f32);
}

#[test]
fn cond_test() {
	let cond_truthy = ConstFunction::new(TRUE);
	let cond_falsey = ConstFunction::new(FALSE);
	let expr = ConstFunction::new(42_f32);
	let f_truthy = CondFunction::new(&cond_truthy, &expr);
	let f_falsey = CondFunction::new(&cond_falsey, &expr);
	let s = Scope::new();
	assert_eq!(f_truthy.call(&s).unwrap(), 42_f32);
	assert_eq!(f_falsey.call(&s).unwrap(), 0_f32);
}
<commit_msg>remove old broken tests<commit_after>use super::{CompileError, is_truthy};
use super::scope::CowScope;
use super::identifier::IdMap;
use std::num::Float;
use std::f32::consts;

/// Something that can be called with arguments given in the scope
pub trait Function {
	fn call(&self, scope: CowScope, idmap: &IdMap) -> Result<f32, CompileError>;
}

macro_rules! bind_function(
	( $name:ident, $func:ident ( $($arg:ident = $val:expr),* ) ) => {
		#[derive(Copy)]
		pub struct $name;
		impl $name {
			pub fn new() -> $name {
				$name
			}
		}
		impl Function for $name {
			#[allow(unused_variables)] // Compiler complains that scope is not used on functions with no args.
			fn call(&self, scope: CowScope, idmap: &IdMap) -> Result<f32, CompileError> {
				Ok($func($(
					// Insert each argument from the scope
					match scope.get_var(idmap.id(stringify!($arg))) {
						Some(val) => val,

						None => match $val {
							Some(val) => val,
							None => return Err(CompileError::new(format!("function `{}` requires argument `{}` but it is not defined in scope", stringify!($func), stringify!($arg)))),
						}
					}
				),*))
			}
		}
	};
);

fn sin(freq: f32, amp: f32, phase: f32, time: f32) -> f32 {
	(freq*time*consts::PI_2 + phase).sin()*amp
}

fn sqrt(x: f32) -> f32 {
	x.sqrt()
}

fn abs(x: f32) -> f32 {
	x.abs()
}

bind_function!(SinFunction, sin(freq=None, amp=Some(1_f32), phase=Some(0_f32), time=None));
bind_function!(SqrtFunction, sqrt(x=None));
bind_function!(AbsFunction, abs(x=None));

/// Always returns a specific constant
#[derive(Copy)]
pub struct ConstFunction {
	val: f32,
}
impl ConstFunction {
	pub fn new(val: f32) -> ConstFunction {
		ConstFunction {
			val: val,
		}
	}
}
impl Function for ConstFunction {
	fn call(&self, _: CowScope, _: &IdMap) -> Result<f32, CompileError> {
		Ok(self.val)
	}
}

/// Returns the result of calling the function if the condition is truthy, else 0
pub struct CondFunction<'a> {
	cond: &'a (Function + 'a),
	func: &'a (Function + 'a),
}
impl<'a> CondFunction<'a> {
	pub fn new(cond: &'a Function, func: &'a Function) -> CondFunction<'a> {
		CondFunction {
			cond: cond,
			func: func,
		}
	}
}
impl<'a> Function for CondFunction<'a> {
	fn call(&self, scope: CowScope, idmap: &IdMap) -> Result<f32, CompileError> {
		if is_truthy(try!(self.cond.call(scope.clone(), idmap))) {
			self.func.call(scope, idmap)
		} else {
			Ok(0_f32)
		}
	}
}
<|endoftext|>


<commit_before>//! Utility routines for pretty-printing error messages.

use ir;
use ir::entities::Inst;
use ir::function::Function;
use isa::{RegInfo, TargetIsa};
use result::CodegenError;
use std::boxed::Box;
use std::fmt;
use std::fmt::Write;
use std::string::{String, ToString};
use verifier::{VerifierError, VerifierErrors};
use write::{decorate_function, FuncWriter, PlainWriter};

/// Pretty-print a verifier error.
pub fn pretty_verifier_error<'a>(
    func: &ir::Function,
    isa: Option<&TargetIsa>,
    func_w: Option<Box<FuncWriter + 'a>>,
    errors: VerifierErrors,
) -> String {
    let mut errors = errors.0;
    let mut w = String::new();

    // TODO: Use drain_filter here when it gets stabilized
    let mut i = 0;

    while i != errors.len() {
        if let ir::entities::AnyEntity::Inst(_) = errors[i].location {
            let err = errors.remove(i);

            writeln!(w, "Miscellaneous error: {}\n", err).unwrap()
        } else {
            i += 1;
        }
    }

    decorate_function(
        &mut PrettyVerifierError(func_w.unwrap_or(Box::new(PlainWriter)), &mut errors),
        &mut w,
        func,
        isa,
    ).unwrap();
    w
}

struct PrettyVerifierError<'a>(Box<FuncWriter + 'a>, &'a mut Vec<VerifierError>);

impl<'a> FuncWriter for PrettyVerifierError<'a> {
    fn write_instruction(
        &mut self,
        w: &mut Write,
        func: &Function,
        isa: Option<&TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        pretty_function_error(w, func, isa, inst, indent, &mut *self.0, self.1)
    }

    fn write_preamble(
        &mut self,
        w: &mut Write,
        func: &Function,
        regs: Option<&RegInfo>,
    ) -> Result<bool, fmt::Error> {
        self.0.write_preamble(w, func, regs)
    }
}

/// Pretty-print a function verifier error.
fn pretty_function_error(
    w: &mut Write,
    func: &Function,
    isa: Option<&TargetIsa>,
    cur_inst: Inst,
    indent: usize,
    func_w: &mut FuncWriter,
    errors: &mut Vec<VerifierError>,
) -> fmt::Result {
    // TODO: Use drain_filter here when it gets stabilized
    let mut i = 0;

    while i != errors.len() {
        match errors[i].location {
            ir::entities::AnyEntity::Inst(inst) if inst == cur_inst => {
                let err = errors.remove(i);

                func_w.write_instruction(w, func, isa, cur_inst, indent)?;
                write!(w, "{1:0$}^", indent, "")?;
                for _c in cur_inst.to_string().chars() {
                    write!(w, "~")?;
                }
                writeln!(w, " verifier {}\n", err.to_string())?;
            }
            ir::entities::AnyEntity::Inst(_) => i += 1,
            _ => unreachable!(),
        }
    }

    Ok(())
}

/// Pretty-print a Cranelift error.
pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CodegenError) -> String {
    if let CodegenError::Verifier(e) = err {
        pretty_verifier_error(func, isa, None, e)
    } else {
        err.to_string()
    }
}
<commit_msg>Fix a few declarations for the `no_std` build.<commit_after>//! Utility routines for pretty-printing error messages.

use ir;
use ir::entities::Inst;
use ir::function::Function;
use isa::{RegInfo, TargetIsa};
use result::CodegenError;
use std::boxed::Box;
use std::fmt;
use std::fmt::Write;
use std::string::{String, ToString};
use std::vec::Vec;
use verifier::{VerifierError, VerifierErrors};
use write::{decorate_function, FuncWriter, PlainWriter};

/// Pretty-print a verifier error.
pub fn pretty_verifier_error<'a>(
    func: &ir::Function,
    isa: Option<&TargetIsa>,
    func_w: Option<Box<FuncWriter + 'a>>,
    errors: VerifierErrors,
) -> String {
    let mut errors = errors.0;
    let mut w = String::new();

    // TODO: Use drain_filter here when it gets stabilized
    let mut i = 0;

    while i != errors.len() {
        if let ir::entities::AnyEntity::Inst(_) = errors[i].location {
            let err = errors.remove(i);

            writeln!(w, "Miscellaneous error: {}\n", err).unwrap()
        } else {
            i += 1;
        }
    }

    decorate_function(
        &mut PrettyVerifierError(func_w.unwrap_or(Box::new(PlainWriter)), &mut errors),
        &mut w,
        func,
        isa,
    ).unwrap();
    w
}

struct PrettyVerifierError<'a>(Box<FuncWriter + 'a>, &'a mut Vec<VerifierError>);

impl<'a> FuncWriter for PrettyVerifierError<'a> {
    fn write_instruction(
        &mut self,
        w: &mut Write,
        func: &Function,
        isa: Option<&TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        pretty_function_error(w, func, isa, inst, indent, &mut *self.0, self.1)
    }

    fn write_preamble(
        &mut self,
        w: &mut Write,
        func: &Function,
        regs: Option<&RegInfo>,
    ) -> Result<bool, fmt::Error> {
        self.0.write_preamble(w, func, regs)
    }
}

/// Pretty-print a function verifier error.
fn pretty_function_error(
    w: &mut Write,
    func: &Function,
    isa: Option<&TargetIsa>,
    cur_inst: Inst,
    indent: usize,
    func_w: &mut FuncWriter,
    errors: &mut Vec<VerifierError>,
) -> fmt::Result {
    // TODO: Use drain_filter here when it gets stabilized
    let mut i = 0;

    while i != errors.len() {
        match errors[i].location {
            ir::entities::AnyEntity::Inst(inst) if inst == cur_inst => {
                let err = errors.remove(i);

                func_w.write_instruction(w, func, isa, cur_inst, indent)?;
                write!(w, "{1:0$}^", indent, "")?;
                for _c in cur_inst.to_string().chars() {
                    write!(w, "~")?;
                }
                writeln!(w, " verifier {}\n", err.to_string())?;
            }
            ir::entities::AnyEntity::Inst(_) => i += 1,
            _ => unreachable!(),
        }
    }

    Ok(())
}

/// Pretty-print a Cranelift error.
pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CodegenError) -> String {
    if let CodegenError::Verifier(e) = err {
        pretty_verifier_error(func, isa, None, e)
    } else {
        err.to_string()
    }
}
<|endoftext|>


<commit_before>extern crate chrono;

use chrono::prelude::*;
use regex::{Regex, Captures};

#[derive(Debug)]
pub enum Command {
    BadCommand,
    OneTimeEvent(OneTimeEventImpl),
}

#[derive(Debug)]
pub struct OneTimeEventImpl{
    pub event_time : DateTime<Utc>,
    pub event_text : String,
}

// const MOMENT_REGEX: &str =
//     r"(?P<day>[\d]*)(?:-(?P<month>[\d]*))?(?:-(?P<year>[\d]*))? (?P<hour>[\d]*).(?P<minute>[\d]*)";

// const DURATION_REGEX: &str =
//     r"";

pub fn parse_command(command_line : String) -> Command {
    let command_line = String::from(command_line.trim());
    debug!("parse incoming text: {}", command_line);

    let mut result;
    result = try_parse_for(&command_line);
    if result.is_some() {
        return result.unwrap();
    }

    result = try_parse_at(&command_line);
    if result.is_some() {
        return result.unwrap();
    }

    warn!("parse_command: line {} doesn't match any regex", command_line);
    Command::BadCommand
}

fn try_parse_at(command_line : &String) -> Option<Command>{
    let time_format = Regex::new(r"[at|в]\s*(?P<day>[\d]*)(?:-(?P<month>[\d]*))?(?:-(?P<year>[\d]*))? (?P<hour>[\d]*).(?P<minute>[\d]*) (?P<main_text>.*)").unwrap();

    let date_captures = time_format.captures(command_line);
    if date_captures.is_none() {

        return None;
    }
    let date_captures = date_captures.unwrap();
    let text = date_captures.name("main_text").unwrap().as_str();

    const DEFAULT_TZ : i64 = -3;
    let dt = chrono::Duration::seconds(DEFAULT_TZ * 60 * 60);
    let d = get_datetime_from_capture(&date_captures) + dt;

    Some(Command::OneTimeEvent
            (OneTimeEventImpl
                { event_text : String::from(text)
                , event_time : d }
            ))
}

fn try_parse_for(command_line : &String) -> Option<Command>{
    let reg_main    = Regex::new(r"(?P<spec>[\d\w]*)(?P<divider> )(?P<main_text>.*)").unwrap();

    let reg_day     = r"(?P<days>[\d]*)[D|d|Д|д]";
    let reg_hour    = r"(?P<hours>[\d]*)[H|h|Ч|ч]";
    let reg_min     = r"(?P<minuts>[\d]*)[M|m|М|м]";
    let reg_sec     = r"(?P<seconds>[\d]*)[S|s|С|с]";

    let caps = reg_main.captures(command_line);
    if caps.is_none() {
        return None;
    }
    let caps = caps.unwrap();
    let spec = caps.name("spec").unwrap().as_str();
    let text = caps.name("main_text").unwrap().as_str();

    let days    = get_first_regex_group_as_u32(reg_day,  spec);
    let hours   = get_first_regex_group_as_u32(reg_hour, spec);
    let minutes = get_first_regex_group_as_u32(reg_min,  spec);
    let seconds = get_first_regex_group_as_u32(reg_sec,  spec);

    if days == 0 && hours == 0 && minutes == 0 && seconds == 0 {
        return None;
    }

    // TODO: should we a better way to do this
    let dt = chrono::Duration::seconds((days as i64) * (60*60*24)
                                    + (hours as i64) * (60*60)
                                    + (minutes as i64) * 60
                                    + (seconds as i64)
                                    );

    let event_time = Utc::now() + dt;

    Some(Command::OneTimeEvent(OneTimeEventImpl
            { event_text : String::from(text)
            , event_time : event_time }
        ))
}

fn get_first_regex_group_as_u32(reg : &str, text : &str) -> u32{
    let reg = Regex::new(reg).expect("get_first_regex_group_as_u32: wrong regex string");
    let number = match reg.captures(text){
        None => "0",
        Some(d) => d.get(1)
            .expect("get_first_regex_group_as_u32: expect regex string with at least 1 group")
            .as_str(),
    };
    number.parse().unwrap_or(0)
}

fn get_datetime_from_capture(cap: &Captures) -> DateTime<Utc>{
    let day = cap.name("day").unwrap().as_str().parse().unwrap();
    let hour = cap.name("hour").unwrap().as_str().parse().unwrap();
    let minute = cap.name("minute").unwrap().as_str().parse().unwrap();

    let now = Utc::now();

    let month = match cap.name("month"){
        None => now.month(),
        Some(m) => m.as_str().parse().unwrap(),
    };

    let year = match cap.name("year"){
        None => now.year(),
        Some(m) => m.as_str().parse().unwrap(),
    };

    Utc.ymd(year, month, day).and_hms(hour, minute, 0)
}

//-------- TESTS ---------------------------------------------------------------

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

    #[test]
    fn parse_for_tests() {
        {
            let command = String::from("1d2h3m4s");
            let text = "some text";
            let command_text = command + " " + text;
            let dt = chrono::Duration::seconds((1 as i64) * (60*60*24)  // days
                                            + (2 as i64) * (60*60)      // hours
                                            + (3 as i64) * 60           // minutes
                                            + (4 as i64)                // seconds
                                            );
            let result = try_parse_for(&command_text);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert!(time_moment_eq(res.event_time, Utc::now() + dt));
                },
                _ => panic!("Wrong command type")
            };

        }
    }

    #[test]
    fn parse_at_tests() {
        {
            let command = String::from("24-10 18:30");
            let text = "some text";
            let mut command_text = command + " " + text;
            command_text.insert_str(0, "at");
            let t = Utc.ymd(2017, 10, 24).and_hms(18-3, 30, 0);

            let result = try_parse_at(&command_text);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }
    }

    fn time_moment_eq(t1: DateTime<Utc>, t2: DateTime<Utc>) -> bool{
        t1.signed_duration_since(t2).num_milliseconds().abs() < 100
    }
}<commit_msg>Add some test<commit_after>extern crate chrono;

use chrono::prelude::*;
use regex::{Regex, Captures};

#[derive(Debug)]
pub enum Command {
    BadCommand,
    OneTimeEvent(OneTimeEventImpl),
}

#[derive(Debug)]
pub struct OneTimeEventImpl{
    pub event_time : DateTime<Utc>,
    pub event_text : String,
}

// const MOMENT_REGEX: &str =
//     r"(?P<day>[\d]*)(?:-(?P<month>[\d]*))?(?:-(?P<year>[\d]*))? (?P<hour>[\d]*).(?P<minute>[\d]*)";

// const DURATION_REGEX: &str =
//     r"";

pub fn parse_command(command_line : String) -> Command {
    let command_line = String::from(command_line.trim());
    debug!("parse incoming text: {}", command_line);

    let mut result;
    result = try_parse_for(&command_line);
    if result.is_some() {
        return result.unwrap();
    }

    result = try_parse_at(&command_line);
    if result.is_some() {
        return result.unwrap();
    }

    warn!("parse_command: line {} doesn't match any regex", command_line);
    Command::BadCommand
}

fn try_parse_at(command_line : &String) -> Option<Command>{
    let time_format = Regex::new(r"[at|в]\s*(?P<day>[\d]*)(?:-(?P<month>[\d]*))?(?:-(?P<year>[\d]*))? (?P<hour>[\d]*).(?P<minute>[\d]*) (?P<main_text>.*)").unwrap();

    let date_captures = time_format.captures(command_line);
    if date_captures.is_none() {

        return None;
    }
    let date_captures = date_captures.unwrap();
    let text = date_captures.name("main_text").unwrap().as_str();

    const DEFAULT_TZ : i64 = -3;
    let dt = chrono::Duration::seconds(DEFAULT_TZ * 60 * 60);
    let d = get_datetime_from_capture(&date_captures) + dt;

    Some(Command::OneTimeEvent
            (OneTimeEventImpl
                { event_text : String::from(text)
                , event_time : d }
            ))
}

fn try_parse_for(command_line : &String) -> Option<Command>{
    let reg_main    = Regex::new(r"(?P<spec>[\d\w]*)(?P<divider> )(?P<main_text>.*)").unwrap();

    let reg_day     = r"(?P<days>[\d]*)[D|d|Д|д]";
    let reg_hour    = r"(?P<hours>[\d]*)[H|h|Ч|ч]";
    let reg_min     = r"(?P<minuts>[\d]*)[M|m|М|м]";
    let reg_sec     = r"(?P<seconds>[\d]*)[S|s|С|с]";

    let caps = reg_main.captures(command_line);
    if caps.is_none() {
        return None;
    }
    let caps = caps.unwrap();
    let spec = caps.name("spec").unwrap().as_str();
    let text = caps.name("main_text").unwrap().as_str();

    let days    = get_first_regex_group_as_u32(reg_day,  spec);
    let hours   = get_first_regex_group_as_u32(reg_hour, spec);
    let minutes = get_first_regex_group_as_u32(reg_min,  spec);
    let seconds = get_first_regex_group_as_u32(reg_sec,  spec);

    if days == 0 && hours == 0 && minutes == 0 && seconds == 0 {
        return None;
    }

    // TODO: should we a better way to do this
    let dt = chrono::Duration::seconds((days as i64) * (60*60*24)
                                    + (hours as i64) * (60*60)
                                    + (minutes as i64) * 60
                                    + (seconds as i64)
                                    );

    let event_time = Utc::now() + dt;

    Some(Command::OneTimeEvent(OneTimeEventImpl
            { event_text : String::from(text)
            , event_time : event_time }
        ))
}

fn get_first_regex_group_as_u32(reg : &str, text : &str) -> u32{
    let reg = Regex::new(reg).expect("get_first_regex_group_as_u32: wrong regex string");
    let number = match reg.captures(text){
        None => "0",
        Some(d) => d.get(1)
            .expect("get_first_regex_group_as_u32: expect regex string with at least 1 group")
            .as_str(),
    };
    number.parse().unwrap_or(0)
}

fn get_datetime_from_capture(cap: &Captures) -> DateTime<Utc>{
    let day = cap.name("day").unwrap().as_str().parse().unwrap();
    let hour = cap.name("hour").unwrap().as_str().parse().unwrap();
    let minute = cap.name("minute").unwrap().as_str().parse().unwrap();

    let now = Utc::now();

    let month = match cap.name("month"){
        None => now.month(),
        Some(m) => m.as_str().parse().unwrap(),
    };

    let year = match cap.name("year"){
        None => now.year(),
        Some(m) => m.as_str().parse().unwrap(),
    };

    Utc.ymd(year, month, day).and_hms(hour, minute, 0)
}

//-------- TESTS ---------------------------------------------------------------

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

    #[test]
    fn parse_for_general() {
        let command = String::from("1d2h3m4s");
        let text = "some text";
        let command_text = command + " " + text;
        let dt = chrono::Duration::seconds((1 as i64) * (60*60*24)  // days
                                        + (2 as i64) * (60*60)      // hours
                                        + (3 as i64) * 60           // minutes
                                        + (4 as i64)                // seconds
                                        );
        let result = try_parse_for(&command_text);
        assert!(result.is_some());
        match result.unwrap(){
            OneTimeEvent(res) => {
                assert_eq!(res.event_text, text);
                assert!(time_moment_eq(res.event_time, Utc::now() + dt));
            },
            _ => panic!("Wrong command type")
        };
    }

    #[test]
    fn parse_for_hm() {
        let command = String::from("2h30m");
        let text = "some text";
        let command_text = command + " " + text;
        let dt = chrono::Duration::seconds((0 as i64) * (60*60*24)  // days
                                        + (2 as i64) * (60*60)      // hours
                                        + (30 as i64) * 60           // minutes
                                        + (0 as i64)                // seconds
                                        );
        let result = try_parse_for(&command_text);
        assert!(result.is_some());
        match result.unwrap(){
            OneTimeEvent(res) => {
                assert_eq!(res.event_text, text);
                assert!(time_moment_eq(res.event_time, Utc::now() + dt));
            },
            _ => panic!("Wrong command type")
        };
    }

    #[test]
    #[ignore]
    fn parse_for_negative() {
        let command = String::from("1d-2h3m4s");
        let text = "some text";
        let command_text = command + " " + text;
        let result = try_parse_for(&command_text);
        assert!(result.is_some());
        match result.unwrap(){
            BadCommand => {},
            _ => panic!("Wrong command type")
        };
    }

    #[test]
    #[ignore]
    fn parse_for_misspell() {
        let command = String::from("1d2j3m4s");
        let text = "some text";
        let command_text = command + " " + text;
        let result = try_parse_for(&command_text);
        assert!(result.is_some());
        match result.unwrap(){
            BadCommand => {},
            _ => panic!("Wrong command type")
        };
    }

    #[test]
    fn parse_at_tests() {
        {
            let command = String::from("24-10 18:30");
            let text = "some text";
            let mut command_text = command + " " + text;
            command_text.insert_str(0, "at");
            let t = Utc.ymd(2017, 10, 24).and_hms(18-3, 30, 0);

            let result = try_parse_at(&command_text);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }

        {
            let command = String::from("24 18:30");
            let text = "some text";
            let mut command_text = command + " " + text;
            command_text.insert_str(0, "at");
            let t = Utc.ymd(2017, 9, 24).and_hms(18-3, 30, 0);

            let result = try_parse_at(&command_text);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }
    }

    fn time_moment_eq(t1: DateTime<Utc>, t2: DateTime<Utc>) -> bool{
        t1.signed_duration_since(t2).num_milliseconds().abs() < 100
    }
}<|endoftext|>


<commit_before>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;

pub enum Scheme {
    Http,
    Https
}

pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

pub enum Method<'a> {
    Get,
    Post,
    Put,
    Patch,
    Delete,
    Other(&'a str)
}

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method<'a>(&'a self) -> Method<'a>;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader + Send;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, String>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

pub type Handler = fn(&mut Request) -> Response;
<commit_msg>Remove inappropriate Send<commit_after>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;

pub enum Scheme {
    Http,
    Https
}

pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

pub enum Method<'a> {
    Get,
    Post,
    Put,
    Patch,
    Delete,
    Other(&'a str)
}

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method<'a>(&'a self) -> Method<'a>;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, String>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

pub type Handler = fn(&mut Request) -> Response;
<|endoftext|>