<commit_before>import result::{ok, err};
import std::io;
import std::json;
import std::map;
import std::map::map;
import zmq::{context, socket, error};

import json = std::json::json;

iface transport {
    fn head(path: str) -> response::t;
    fn get(path: str) -> response::t;
    fn put(path: str, doc: map<str, json>) -> response::t;
    fn post(path: str, doc: map<str, json>) -> response::t;
    fn delete(path: str) -> response::t;
}

type client = { transport: transport };

fn mk_client(transport: transport) -> client {
    { transport: transport }
}

impl client for client {
    fn get(index: str, typ: str, id: str) -> response::t {
        let path = index + "/" + typ + "/" + id;
        self.transport.get(path)
    }
    fn prepare_index(index: str, typ: str) -> index_builder {
        mk_index_builder(self, index, typ)
    }
    fn delete(index: str, typ: str, id: str) -> response::t {
        let path = index + "/" + typ + "/" + id;
        self.transport.delete(path)
    }
}

enum consistency { CONSISTENCY_DEFAULT, ONE, QUORUM, ALL }
enum replication { REPLICATION_DEFAULT, SYNC, ASYNC }
enum op_type { CREATE, INDEX }
enum version_type { INTERNAL, EXTERNAL }

type index_builder = {
    client: client,
    index: str,
    typ: str,
    mut id: option<str>,
    mut routing: option<str>,
    mut parent: option<str>,
    mut timestamp: option<str>,
    mut ttl: option<str>,
    mut op_type: op_type,
    mut refresh: bool,
    mut version: uint,
    mut version_type: version_type,
    mut percolate: option<str>,
    mut consistency: consistency,
    mut replication: replication,
    mut source: option<map<str, json>>,
};

fn mk_index_builder(client: client, index: str, typ: str) -> index_builder {
    {
        client: client,
        index: index,
        typ: typ,
        mut id: none,
        mut routing: none,
        mut parent: none,
        mut timestamp: none,
        mut ttl: none,
        mut op_type: INDEX,
        mut refresh: false,
        mut version: 0u,
        mut version_type: INTERNAL,
        mut percolate: none,
        mut consistency: CONSISTENCY_DEFAULT,
        mut replication: REPLICATION_DEFAULT,
        mut source: none,
    }
}

impl index_builder for index_builder {
    fn set_id(id: str) -> index_builder { self.id = some(id); self }
    fn set_routing(routing: str) -> index_builder {
        self.routing = some(routing);
        self
    }
    fn set_parent(parent: str) -> index_builder {
        self.parent = some(parent);
        self
    }
    fn set_timestamp(timestamp: str) -> index_builder {
        self.timestamp = some(timestamp);
        self
    }
    fn set_ttl(ttl: str) -> index_builder {
        self.ttl = some(ttl);
        self
    }
    fn set_op_type(op_type: op_type) -> index_builder {
        self.op_type = op_type;
        self
    }
    fn set_refresh() -> index_builder { self.refresh = true; self }
    fn set_version(version: uint) -> index_builder {
        self.version = version;
        self
    }
    fn set_version_type(version_type: version_type) -> index_builder {
        self.version_type = version_type;
        self
    }
    fn set_percolate(percolate: str) -> index_builder {
        self.percolate = some(percolate);
        self
    }
    fn set_consistency(consistency: consistency) -> index_builder {
        self.consistency = consistency;
        self
    }
    fn set_replication(replication: replication) -> index_builder {
        self.replication = replication;
        self
    }
    fn set_source(source: map<str, json>) -> index_builder {
        self.source = some(source);
        self
    }
    fn execute() -> response::t {
        let path = [self.index, self.typ];
        alt self.id {
          none {}
          some(id) { vec::push(path, id); }
        }

        let path = str::connect(path, "/");
        let params = [];

        alt self.routing {
          none {}
          some(routing) { vec::push(params, "routing=" + routing); }
        }

        alt self.parent {
          none {}
          some(parent) { vec::push(params, "parent=" + parent); }
        }

        alt self.timestamp {
          none {}
          some(timestamp) { vec::push(params, "timestamp=" + timestamp); }
        }

        alt self.ttl {
          none {}
          some(ttl) { vec::push(params, "ttl=" + ttl); }
        }

        alt self.op_type {
          CREATE { vec::push(params, "op_type=create"); }
          INDEX { vec::push(params, "op_type=index"); }
        }

        if self.refresh {
            vec::push(params, "refresh=true");
        }

        alt self.percolate {
          none {}
          some(percolate) { vec::push(params, "percolate=" + percolate); }
        }

        alt self.consistency {
          CONSISTENCY_DEFAULT {}
          ONE { vec::push(params, "consistency=one"); }
          QUORUM { vec::push(params, "consistency=quorum"); }
          ALL { vec::push(params, "consistency=all"); }
        }

        alt self.replication {
          REPLICATION_DEFAULT {}
          SYNC { vec::push(params, "replication=sync"); }
          ASYNC { vec::push(params, "replication=async"); }
        }

        if vec::is_not_empty(params) {
            path += "?" + str::connect(params, "&");
        }

        let source = alt self.source {
          none { map::new_str_hash() }
          some(source) { source }
        };

        alt self.id {
          none { self.client.transport.put(path, source) }
          some(_) { self.client.transport.post(path, source) }
        }
    }
}

type json_dict_builder = { dict: map<str, json> };

fn mk_json_dict_builder() -> json_dict_builder {
    { dict: map::new_str_hash() }
}

impl json_dict_builder for json_dict_builder {
    fn field_float(key: str, value: float) -> json_dict_builder {
        self.dict.insert(key, json::num(value));
        self
    }
    fn field_str(key: str, value: str) -> json_dict_builder {
        self.dict.insert(key, json::string(value));
        self
    }
    fn field_bool(key: str, value: bool) -> json_dict_builder {
        self.dict.insert(key, json::boolean(value));
        self
    }
    fn field_null(key: str) -> json_dict_builder {
        self.dict.insert(key, json::null);
        self
    }
    fn field_dict(key: str, f: fn(json_dict_builder))
      -> json_dict_builder {
        let builder = mk_json_dict_builder();
        f(builder);
        self.dict.insert(key, json::dict(builder.dict));
        self
    }
    fn field_list(key: str, f: fn(json_list_builder)) -> json_dict_builder {
        let builder = mk_json_list_builder();
        f(builder);
        self.dict.insert(key, json::list(builder.list));
        self
    }
}

type json_list_builder = { mut list: [json] };

fn mk_json_list_builder() -> json_list_builder {
    { mut list: [] }
}

impl json_list_builder for json_list_builder {
    fn add_float(value: float) -> json_list_builder {
        vec::push(self.list, json::num(value));
        self
    }
    fn add_str(value: str) -> json_list_builder {
        vec::push(self.list, json::string(value));
        self
    }
    fn add_bool(value: bool) -> json_list_builder {
        vec::push(self.list, json::boolean(value));
        self
    }
    fn add_null() -> json_list_builder {
        vec::push(self.list, json::null);
        self
    }
    fn add_dict(f: fn(json_dict_builder)) -> json_list_builder {
        let builder = mk_json_dict_builder();
        f(builder);
        vec::push(self.list, json::dict(builder.dict));
        self
    }
    fn add_list(f: fn(json_list_builder)) -> json_list_builder {
        let builder = mk_json_list_builder();
        f(builder);
        vec::push(self.list, json::list(builder.list));
        self
    }
}

#[doc = "Transport to talk to Elasticsearch with zeromq"]
type zmq_transport = { socket: zmq::socket };

#[doc = "Zeromq transport implementation"]
impl of transport for zmq_transport {
    fn head(path: str) -> response::t { self.send("HEAD|" + path) }
    fn get(path: str) -> response::t { self.send("GET|" + path) }
    fn put(path: str, doc: map<str, json>) -> response::t {
        self.send("PUT|" + path + "|" + json::to_str(json::dict(doc)))
    }
    fn post(path: str, doc: map<str, json>) -> response::t {
        self.send("POST|" + path + "|" + json::to_str(json::dict(doc)))
    }
    fn delete(path: str) -> response::t {
        self.send("DELETE|" + path)
    }

    fn send(request: str) -> response::t {
        str::as_bytes(request) { |bytes|
            alt self.socket.send_between(bytes, 0u, str::len(request), 0) {
              ok(()) {}
              err(e) { fail e.to_str(); }
            }
        }

        alt self.socket.recv(0) {
          ok(msg) { response::parse(msg) }
          err(e) { fail e.to_str(); }
        }
    }
}

#[doc = "Create a zeromq transport to Elasticsearch"]
fn mk_zmq_transport(ctx: zmq::context, addr: str) -> transport {
    let socket = alt ctx.socket(zmq::REQ) {
      ok(socket) { socket }
      err(e) { fail e.to_str() }
    };

    str::as_bytes(addr) { |bytes|
        alt socket.connect(bytes) {
          ok(()) {}
          err(e) { fail e.to_str(); }
        }
    }

    { socket: socket } as transport
}

#[doc = "Helper function to creating a client with zeromq"]
fn connect_with_zmq(ctx: zmq::context, addr: str) -> client {
    let transport = mk_zmq_transport(ctx, addr);
    mk_client(transport)
}

mod response {
    type t = {
        code: uint,
        status: str,
        doc: json,
    };

    fn parse(msg: [u8]) -> t {
        io::println(#fmt("parse: %?", str::from_bytes(msg)));

        let end = vec::len(msg);

        let (start, code) = parse_code(msg, end);
        let (start, status) = parse_status(msg, start, end);
        let doc = parse_doc(msg, start, end);

        { code: code, status: status, doc: doc }
    }

    fn parse_code(msg: [u8], end: uint) -> (uint, uint) {
        alt vec::position_from(msg, 0u, end) { |c| c == '|' as u8 } {
          none { fail "invalid response" }
          some(i) {
            alt uint::parse_buf(vec::slice(msg, 0u, i), 10u) {
              some(code) { (i + 1u, code) }
              none { fail "invalid status code" }
            }
          }
        }
    }

    fn parse_status(msg: [u8], start: uint, end: uint) -> (uint, str) {
        alt vec::position_from(msg, start, end) { |c| c == '|' as u8 } {
          none { fail "invalid response" }
          some(i) { (i + 1u, str::from_bytes(vec::slice(msg, start, i))) }
        }
    }

    fn parse_doc(msg: [u8], start: uint, end: uint) -> json {
        if start == end { ret json::null; }

        io::with_bytes_reader_between(msg, start, end) { |rdr|
            alt json::from_reader(rdr) {
              ok(json) { json }
              err({line, col, msg}) { fail #fmt("%u:%u: %s", line, col, msg); }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    import std::map;

    #[test]
    fn test() {
        let ctx = alt zmq::init(1) {
          ok(ctx) { ctx }
          err(e) { fail e.to_str(); }
        };

        let client = connect_with_zmq(ctx, "tcp://localhost:9700");
        io::println(#fmt("%?\n", client.transport.head("/")));
        io::println(#fmt("%?\n", client.transport.get("/")));

        io::println(#fmt("%?\n", client.transport.get("/test/test/1")));

        io::println(#fmt("%?\n", client.prepare_index("test", "test")
          .set_id("1")
          .set_version(2u)
          .set_source(mk_json_dict_builder()
              .field_float("foo", 5.0)
              .field_str("bar", "wee")
              .field_dict("baz") { |bld|
                  bld.field_float("a", 2.0);
              }
              .field_list("boo") { |bld|
                  bld.add_float(1.0).add_str("zzz");
              }
              .dict
          )
          .execute()));

        io::println(#fmt("%?\n", client.transport.get("/test/test/1")));

        io::println(#fmt("%?\n", client.delete("test", "test", "1")));
    }
}
<commit_msg>Sync with rust.<commit_after>import result::{ok, err};
import std::io;
import std::json;
import std::map;
import std::map::hashmap;
import zmq::{context, socket, error};

import json = std::json::json;

iface transport {
    fn head(path: str) -> response::t;
    fn get(path: str) -> response::t;
    fn put(path: str, doc: hashmap<str, json>) -> response::t;
    fn post(path: str, doc: hashmap<str, json>) -> response::t;
    fn delete(path: str) -> response::t;
}

type client = { transport: transport };

fn mk_client(transport: transport) -> client {
    { transport: transport }
}

impl client for client {
    fn get(index: str, typ: str, id: str) -> response::t {
        let path = index + "/" + typ + "/" + id;
        self.transport.get(path)
    }
    fn prepare_index(index: str, typ: str) -> index_builder {
        mk_index_builder(self, index, typ)
    }
    fn delete(index: str, typ: str, id: str) -> response::t {
        let path = index + "/" + typ + "/" + id;
        self.transport.delete(path)
    }
}

enum consistency { CONSISTENCY_DEFAULT, ONE, QUORUM, ALL }
enum replication { REPLICATION_DEFAULT, SYNC, ASYNC }
enum op_type { CREATE, INDEX }
enum version_type { INTERNAL, EXTERNAL }

type index_builder = {
    client: client,
    index: str,
    typ: str,
    mut id: option<str>,
    mut routing: option<str>,
    mut parent: option<str>,
    mut timestamp: option<str>,
    mut ttl: option<str>,
    mut op_type: op_type,
    mut refresh: bool,
    mut version: uint,
    mut version_type: version_type,
    mut percolate: option<str>,
    mut consistency: consistency,
    mut replication: replication,
    mut source: option<hashmap<str, json>>,
};

fn mk_index_builder(client: client, index: str, typ: str) -> index_builder {
    {
        client: client,
        index: index,
        typ: typ,
        mut id: none,
        mut routing: none,
        mut parent: none,
        mut timestamp: none,
        mut ttl: none,
        mut op_type: INDEX,
        mut refresh: false,
        mut version: 0u,
        mut version_type: INTERNAL,
        mut percolate: none,
        mut consistency: CONSISTENCY_DEFAULT,
        mut replication: REPLICATION_DEFAULT,
        mut source: none,
    }
}

impl index_builder for index_builder {
    fn set_id(id: str) -> index_builder { self.id = some(id); self }
    fn set_routing(routing: str) -> index_builder {
        self.routing = some(routing);
        self
    }
    fn set_parent(parent: str) -> index_builder {
        self.parent = some(parent);
        self
    }
    fn set_timestamp(timestamp: str) -> index_builder {
        self.timestamp = some(timestamp);
        self
    }
    fn set_ttl(ttl: str) -> index_builder {
        self.ttl = some(ttl);
        self
    }
    fn set_op_type(op_type: op_type) -> index_builder {
        self.op_type = op_type;
        self
    }
    fn set_refresh() -> index_builder { self.refresh = true; self }
    fn set_version(version: uint) -> index_builder {
        self.version = version;
        self
    }
    fn set_version_type(version_type: version_type) -> index_builder {
        self.version_type = version_type;
        self
    }
    fn set_percolate(percolate: str) -> index_builder {
        self.percolate = some(percolate);
        self
    }
    fn set_consistency(consistency: consistency) -> index_builder {
        self.consistency = consistency;
        self
    }
    fn set_replication(replication: replication) -> index_builder {
        self.replication = replication;
        self
    }
    fn set_source(source: hashmap<str, json>) -> index_builder {
        self.source = some(source);
        self
    }
    fn execute() -> response::t {
        let path = [self.index, self.typ];
        alt self.id {
          none {}
          some(id) { vec::push(path, id); }
        }

        let path = str::connect(path, "/");
        let params = [];

        alt self.routing {
          none {}
          some(routing) { vec::push(params, "routing=" + routing); }
        }

        alt self.parent {
          none {}
          some(parent) { vec::push(params, "parent=" + parent); }
        }

        alt self.timestamp {
          none {}
          some(timestamp) { vec::push(params, "timestamp=" + timestamp); }
        }

        alt self.ttl {
          none {}
          some(ttl) { vec::push(params, "ttl=" + ttl); }
        }

        alt self.op_type {
          CREATE { vec::push(params, "op_type=create"); }
          INDEX { vec::push(params, "op_type=index"); }
        }

        if self.refresh {
            vec::push(params, "refresh=true");
        }

        alt self.percolate {
          none {}
          some(percolate) { vec::push(params, "percolate=" + percolate); }
        }

        alt self.consistency {
          CONSISTENCY_DEFAULT {}
          ONE { vec::push(params, "consistency=one"); }
          QUORUM { vec::push(params, "consistency=quorum"); }
          ALL { vec::push(params, "consistency=all"); }
        }

        alt self.replication {
          REPLICATION_DEFAULT {}
          SYNC { vec::push(params, "replication=sync"); }
          ASYNC { vec::push(params, "replication=async"); }
        }

        if vec::is_not_empty(params) {
            path += "?" + str::connect(params, "&");
        }

        let source = alt self.source {
          none { map::new_str_hash() }
          some(source) { source }
        };

        alt self.id {
          none { self.client.transport.put(path, source) }
          some(_) { self.client.transport.post(path, source) }
        }
    }
}

type json_dict_builder = { dict: hashmap<str, json> };

fn mk_json_dict_builder() -> json_dict_builder {
    { dict: map::new_str_hash() }
}

impl json_dict_builder for json_dict_builder {
    fn field_float(key: str, value: float) -> json_dict_builder {
        self.dict.insert(key, json::num(value));
        self
    }
    fn field_str(key: str, value: str) -> json_dict_builder {
        self.dict.insert(key, json::string(value));
        self
    }
    fn field_bool(key: str, value: bool) -> json_dict_builder {
        self.dict.insert(key, json::boolean(value));
        self
    }
    fn field_null(key: str) -> json_dict_builder {
        self.dict.insert(key, json::null);
        self
    }
    fn field_dict(key: str, f: fn(json_dict_builder))
      -> json_dict_builder {
        let builder = mk_json_dict_builder();
        f(builder);
        self.dict.insert(key, json::dict(builder.dict));
        self
    }
    fn field_list(key: str, f: fn(json_list_builder)) -> json_dict_builder {
        let builder = mk_json_list_builder();
        f(builder);
        self.dict.insert(key, json::list(builder.list));
        self
    }
}

type json_list_builder = { mut list: [json] };

fn mk_json_list_builder() -> json_list_builder {
    { mut list: [] }
}

impl json_list_builder for json_list_builder {
    fn add_float(value: float) -> json_list_builder {
        vec::push(self.list, json::num(value));
        self
    }
    fn add_str(value: str) -> json_list_builder {
        vec::push(self.list, json::string(value));
        self
    }
    fn add_bool(value: bool) -> json_list_builder {
        vec::push(self.list, json::boolean(value));
        self
    }
    fn add_null() -> json_list_builder {
        vec::push(self.list, json::null);
        self
    }
    fn add_dict(f: fn(json_dict_builder)) -> json_list_builder {
        let builder = mk_json_dict_builder();
        f(builder);
        vec::push(self.list, json::dict(builder.dict));
        self
    }
    fn add_list(f: fn(json_list_builder)) -> json_list_builder {
        let builder = mk_json_list_builder();
        f(builder);
        vec::push(self.list, json::list(builder.list));
        self
    }
}

#[doc = "Transport to talk to Elasticsearch with zeromq"]
type zmq_transport = { socket: zmq::socket };

#[doc = "Zeromq transport implementation"]
impl of transport for zmq_transport {
    fn head(path: str) -> response::t { self.send("HEAD|" + path) }
    fn get(path: str) -> response::t { self.send("GET|" + path) }
    fn put(path: str, doc: hashmap<str, json>) -> response::t {
        self.send("PUT|" + path + "|" + json::to_str(json::dict(doc)))
    }
    fn post(path: str, doc: hashmap<str, json>) -> response::t {
        self.send("POST|" + path + "|" + json::to_str(json::dict(doc)))
    }
    fn delete(path: str) -> response::t {
        self.send("DELETE|" + path)
    }

    fn send(request: str) -> response::t {
        str::as_bytes(request) { |bytes|
            alt self.socket.send_between(bytes, 0u, str::len(request), 0) {
              ok(()) {}
              err(e) { fail e.to_str(); }
            }
        }

        alt self.socket.recv(0) {
          ok(msg) { response::parse(msg) }
          err(e) { fail e.to_str(); }
        }
    }
}

#[doc = "Create a zeromq transport to Elasticsearch"]
fn mk_zmq_transport(ctx: zmq::context, addr: str) -> transport {
    let socket = alt ctx.socket(zmq::REQ) {
      ok(socket) { socket }
      err(e) { fail e.to_str() }
    };

    str::as_bytes(addr) { |bytes|
        alt socket.connect(bytes) {
          ok(()) {}
          err(e) { fail e.to_str(); }
        }
    }

    { socket: socket } as transport
}

#[doc = "Helper function to creating a client with zeromq"]
fn connect_with_zmq(ctx: zmq::context, addr: str) -> client {
    let transport = mk_zmq_transport(ctx, addr);
    mk_client(transport)
}

mod response {
    type t = {
        code: uint,
        status: str,
        doc: json,
    };

    fn parse(msg: [u8]) -> t {
        io::println(#fmt("parse: %?", str::from_bytes(msg)));

        let end = vec::len(msg);

        let (start, code) = parse_code(msg, end);
        let (start, status) = parse_status(msg, start, end);
        let doc = parse_doc(msg, start, end);

        { code: code, status: status, doc: doc }
    }

    fn parse_code(msg: [u8], end: uint) -> (uint, uint) {
        alt vec::position_from(msg, 0u, end) { |c| c == '|' as u8 } {
          none { fail "invalid response" }
          some(i) {
            alt uint::parse_buf(vec::slice(msg, 0u, i), 10u) {
              some(code) { (i + 1u, code) }
              none { fail "invalid status code" }
            }
          }
        }
    }

    fn parse_status(msg: [u8], start: uint, end: uint) -> (uint, str) {
        alt vec::position_from(msg, start, end) { |c| c == '|' as u8 } {
          none { fail "invalid response" }
          some(i) { (i + 1u, str::from_bytes(vec::slice(msg, start, i))) }
        }
    }

    fn parse_doc(msg: [u8], start: uint, end: uint) -> json {
        if start == end { ret json::null; }

        io::with_bytes_reader_between(msg, start, end) { |rdr|
            alt json::from_reader(rdr) {
              ok(json) { json }
              err({line, col, msg}) { fail #fmt("%u:%u: %s", line, col, msg); }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    import std::map;

    #[test]
    fn test() {
        let ctx = alt zmq::init(1) {
          ok(ctx) { ctx }
          err(e) { fail e.to_str(); }
        };

        let client = connect_with_zmq(ctx, "tcp://localhost:9700");
        io::println(#fmt("%?\n", client.transport.head("/")));
        io::println(#fmt("%?\n", client.transport.get("/")));

        io::println(#fmt("%?\n", client.transport.get("/test/test/1")));

        io::println(#fmt("%?\n", client.prepare_index("test", "test")
          .set_id("1")
          .set_version(2u)
          .set_source(mk_json_dict_builder()
              .field_float("foo", 5.0)
              .field_str("bar", "wee")
              .field_dict("baz") { |bld|
                  bld.field_float("a", 2.0);
              }
              .field_list("boo") { |bld|
                  bld.add_float(1.0).add_str("zzz");
              }
              .dict
          )
          .execute()));

        io::println(#fmt("%?\n", client.transport.get("/test/test/1")));

        io::println(#fmt("%?\n", client.delete("test", "test", "1")));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do [Cap'n Proto code generation]
//! (https://capnproto.org/otherlang.html#how-to-write-compiler-plugins) within
//! a Cargo build. You still need the `capnp` binary (implemented in C++).
//! (If you use a package manager, try looking for a package called
//! `capnproto`.)
//!
//! In your Cargo.toml:
//!
//! ```ignore
//! [package]
//! build = "build.rs"
//!
//! [build-dependencies]
//! capnpc = "0.9"
//! ```
//!
//! In your build.rs:
//!
//! ```ignore
//! extern crate capnpc;
//!
//! fn main() {
//!     capnpc::CompilerCommand::new()
//!         .src_prefix("schema")
//!         .file("schema/foo.capnp")
//!         .file("schema/bar.capnp")
//!         .run().expect("schema compiler command");
//! }
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

extern crate capnp;

/// Code generated from [schema.capnp]
/// (https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
pub mod schema_capnp;

pub mod codegen;
pub mod codegen_types;
mod pointer_constants;
pub mod schema;

use std::path::{Path, PathBuf};

#[derive(Copy, Clone)]
pub enum RustEdition {
    Rust2015,
    Rust2018,
}

fn run_command(
    mut command: ::std::process::Command,
    path: &PathBuf,
) -> ::capnp::Result<()> {
    let mut p = command.spawn()?;
    crate::codegen::generate_code(p.stdout.take().unwrap(), path.as_path())?;
    let exit_status = p.wait()?;
    if !exit_status.success() {
        Err(::capnp::Error::failed(format!(
            "Non-success exit status: {}",
            exit_status
        )))
    } else {
        Ok(())
    }
}

/// A builder object for schema compiler commands.
pub struct CompilerCommand {
    files: Vec<PathBuf>,
    src_prefixes: Vec<PathBuf>,
    import_paths: Vec<PathBuf>,
    no_standard_import: bool,
    output_path: PathBuf,
}

impl CompilerCommand {
    /// Creates a new, empty command.
    pub fn new() -> CompilerCommand {
        CompilerCommand {
            files: Vec::new(),
            src_prefixes: Vec::new(),
            import_paths: Vec::new(),
            no_standard_import: false,
            output_path: PathBuf::from(&::std::env::var("OUT_DIR").unwrap()),
        }
    }

    /// Adds a file to be compiled.
    pub fn file<'a, P>(&'a mut self, path: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.files.push(path.as_ref().to_path_buf());
        self
    }

    /// Adds a --src-prefix flag. For all files specified for compilation that start
    /// with `prefix`, removes the prefix when computing output filenames.
    pub fn src_prefix<'a, P>(&'a mut self, prefix: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.src_prefixes.push(prefix.as_ref().to_path_buf());
        self
    }

    /// Adds an --import_path flag. Adds `dir` to the list of directories searched
    /// for absolute imports.
    pub fn import_path<'a, P>(&'a mut self, dir: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.import_paths.push(dir.as_ref().to_path_buf());
        self
    }

    /// Adds the --no-standard-import flag, indicating that the default import paths of
    /// /usr/include and /usr/local/include should not bet included.
    pub fn no_standard_import<'a>(&'a mut self) -> &'a mut CompilerCommand {
        self.no_standard_import = true;
        self
    }

    /// Sets the Rust edition of the generated code.
    #[deprecated(since = "0.10.0", note = "no longer need to specify rust edition")]
    pub fn edition(&mut self, _rust_edition: RustEdition) -> &mut Self {
        self
    }

    ///Sets the output directory of generated code. Default is OUT_DIR
    pub fn output_path<'a, P>(&'a mut self, path: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.output_path = path.as_ref().to_path_buf();
        self
    }

    /// Runs the command.
    pub fn run(&mut self) -> ::capnp::Result<()> {
        let mut command = ::std::process::Command::new("capnp");
        command.arg("compile").arg("-o").arg("-");

        if self.no_standard_import {
            command.arg("--no-standard-import");
        }

        for import_path in &self.import_paths {
            command.arg(&format!("--import-path={}", import_path.display()));
        }

        for src_prefix in &self.src_prefixes {
            command.arg(&format!("--src-prefix={}", src_prefix.display()));
        }

        for file in &self.files {
            command.arg(&format!("{}", file.display()));
        }

        command.stdout(::std::process::Stdio::piped());
        command.stderr(::std::process::Stdio::inherit());

        run_command(command, &self.output_path).map_err(|error| {
            ::capnp::Error::failed(format!(
                "Error while trying to execute `capnp compile`: {}.  \
                 Please verify that version 0.5.2 or higher of the capnp executable \
                 is installed on your system. See https://capnproto.org/install.html",
                error
            ))
        })
    }
}
<commit_msg>minor doc updates<commit_after>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do [Cap'n Proto code generation]
//! (https://capnproto.org/otherlang.html#how-to-write-compiler-plugins) within
//! a Cargo build. You still need the `capnp` binary (implemented in C++).
//! (If you use a package manager, try looking for a package called
//! `capnproto`.)
//!
//! In your Cargo.toml:
//!
//! ```ignore
//! [package]
//! build = "build.rs"
//!
//! [build-dependencies]
//! capnpc = "0.10"
//! ```
//!
//! In your build.rs:
//!
//! ```ignore
//! extern crate capnpc;
//!
//! fn main() {
//!     capnpc::CompilerCommand::new()
//!         .src_prefix("schema")
//!         .file("schema/foo.capnp")
//!         .file("schema/bar.capnp")
//!         .run().expect("schema compiler command");
//! }
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

extern crate capnp;

/// Code generated from [schema.capnp]
/// (https://github.com/capnproto/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
pub mod schema_capnp;

pub mod codegen;
pub mod codegen_types;
mod pointer_constants;
pub mod schema;

use std::path::{Path, PathBuf};

#[derive(Copy, Clone)]
pub enum RustEdition {
    Rust2015,
    Rust2018,
}

fn run_command(
    mut command: ::std::process::Command,
    path: &PathBuf,
) -> ::capnp::Result<()> {
    let mut p = command.spawn()?;
    crate::codegen::generate_code(p.stdout.take().unwrap(), path.as_path())?;
    let exit_status = p.wait()?;
    if !exit_status.success() {
        Err(::capnp::Error::failed(format!(
            "Non-success exit status: {}",
            exit_status
        )))
    } else {
        Ok(())
    }
}

/// A builder object for schema compiler commands.
pub struct CompilerCommand {
    files: Vec<PathBuf>,
    src_prefixes: Vec<PathBuf>,
    import_paths: Vec<PathBuf>,
    no_standard_import: bool,
    output_path: PathBuf,
}

impl CompilerCommand {
    /// Creates a new, empty command.
    pub fn new() -> CompilerCommand {
        CompilerCommand {
            files: Vec::new(),
            src_prefixes: Vec::new(),
            import_paths: Vec::new(),
            no_standard_import: false,
            output_path: PathBuf::from(&::std::env::var("OUT_DIR").unwrap()),
        }
    }

    /// Adds a file to be compiled.
    pub fn file<'a, P>(&'a mut self, path: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.files.push(path.as_ref().to_path_buf());
        self
    }

    /// Adds a --src-prefix flag. For all files specified for compilation that start
    /// with `prefix`, removes the prefix when computing output filenames.
    pub fn src_prefix<'a, P>(&'a mut self, prefix: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.src_prefixes.push(prefix.as_ref().to_path_buf());
        self
    }

    /// Adds an --import_path flag. Adds `dir` to the list of directories searched
    /// for absolute imports.
    pub fn import_path<'a, P>(&'a mut self, dir: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.import_paths.push(dir.as_ref().to_path_buf());
        self
    }

    /// Adds the --no-standard-import flag, indicating that the default import paths of
    /// /usr/include and /usr/local/include should not bet included.
    pub fn no_standard_import<'a>(&'a mut self) -> &'a mut CompilerCommand {
        self.no_standard_import = true;
        self
    }

    /// Sets the Rust edition of the generated code.
    #[deprecated(since = "0.10.0", note = "no longer need to specify rust edition")]
    pub fn edition(&mut self, _rust_edition: RustEdition) -> &mut Self {
        self
    }

    ///Sets the output directory of generated code. Default is OUT_DIR
    pub fn output_path<'a, P>(&'a mut self, path: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.output_path = path.as_ref().to_path_buf();
        self
    }

    /// Runs the command.
    pub fn run(&mut self) -> ::capnp::Result<()> {
        let mut command = ::std::process::Command::new("capnp");
        command.arg("compile").arg("-o").arg("-");

        if self.no_standard_import {
            command.arg("--no-standard-import");
        }

        for import_path in &self.import_paths {
            command.arg(&format!("--import-path={}", import_path.display()));
        }

        for src_prefix in &self.src_prefixes {
            command.arg(&format!("--src-prefix={}", src_prefix.display()));
        }

        for file in &self.files {
            command.arg(&format!("{}", file.display()));
        }

        command.stdout(::std::process::Stdio::piped());
        command.stderr(::std::process::Stdio::inherit());

        run_command(command, &self.output_path).map_err(|error| {
            ::capnp::Error::failed(format!(
                "Error while trying to execute `capnp compile`: {}.  \
                 Please verify that version 0.5.2 or higher of the capnp executable \
                 is installed on your system. See https://capnproto.org/install.html",
                error
            ))
        })
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    cluster::Cluster,
    effects::{Effect, StopContainer},
    experiments::{Context, Experiment, ExperimentParam},
    instance,
    instance::Instance,
    stats,
    tx_emitter::EmitJobRequest,
    util::unix_timestamp_now,
};
use async_trait::async_trait;
use futures::future::join_all;
use slog_scope::info;
use std::{
    collections::HashSet,
    fmt::{Display, Error, Formatter},
    sync::atomic::Ordering,
    time::Duration,
};
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
pub struct PerformanceBenchmarkNodesDownParams {
    #[structopt(
        long,
        default_value = "0",
        help = "Number of nodes which should be down"
    )]
    pub num_nodes_down: usize,
    #[structopt(
        long,
        help = "Whether cluster test should run against validators or full nodes"
    )]
    pub is_fullnode: bool,
    #[structopt(
    long,
    default_value = Box::leak(format!("{}", DEFAULT_BENCH_DURATION).into_boxed_str()),
    help = "Duration of an experiment in seconds"
    )]
    pub duration: u64,
}

pub struct PerformanceBenchmarkNodesDown {
    down_instances: Vec<Instance>,
    up_instances: Vec<Instance>,
    num_nodes_down: usize,
    duration: Duration,
}

pub const DEFAULT_BENCH_DURATION: u64 = 120;

impl PerformanceBenchmarkNodesDownParams {
    pub fn new_nodes_down(num_nodes_down: usize) -> Self {
        Self {
            num_nodes_down,
            is_fullnode: false,
            duration: DEFAULT_BENCH_DURATION,
        }
    }
}

impl ExperimentParam for PerformanceBenchmarkNodesDownParams {
    type E = PerformanceBenchmarkNodesDown;
    fn build(self, cluster: &Cluster) -> Self::E {
        if self.is_fullnode {
            let (down_instances, up_instances) =
                cluster.split_n_fullnodes_random(self.num_nodes_down);
            Self::E {
                down_instances: down_instances.into_fullnode_instances(),
                up_instances: up_instances.into_fullnode_instances(),
                num_nodes_down: self.num_nodes_down,
                duration: Duration::from_secs(self.duration),
            }
        } else {
            let (down_instances, up_instances) =
                cluster.split_n_validators_random(self.num_nodes_down);
            Self::E {
                down_instances: down_instances.into_validator_instances(),
                up_instances: up_instances.into_validator_instances(),
                num_nodes_down: self.num_nodes_down,
                duration: Duration::from_secs(self.duration),
            }
        }
    }
}

#[async_trait]
impl Experiment for PerformanceBenchmarkNodesDown {
    fn affected_validators(&self) -> HashSet<String> {
        instance::instancelist_to_set(&self.down_instances)
    }

    async fn run(&mut self, context: &mut Context<'_>) -> anyhow::Result<()> {
        let stop_effects: Vec<_> = self
            .down_instances
            .clone()
            .into_iter()
            .map(StopContainer::new)
            .collect();
        let futures = stop_effects.iter().map(|e| e.activate());
        join_all(futures).await;
        let buffer = Duration::from_secs(60);
        let window = self.duration + buffer * 2;
        let emit_job_request = EmitJobRequest::for_instances(
            self.up_instances.clone(),
            context.global_emit_job_request,
        );
        let stats = context
            .tx_emitter
            .emit_txn_for(window, emit_job_request)
            .await?;
        let end = unix_timestamp_now() - buffer;
        let start = end - window + 2 * buffer;
        let (avg_tps, avg_latency) = stats::txn_stats(&context.prometheus, start, end)?;
        let avg_txns_per_block = stats::avg_txns_per_block(&context.prometheus, start, end)?;
        info!(
            "Link to dashboard : {}",
            context.prometheus.link_to_dashboard(start, end)
        );
        let futures = stop_effects.iter().map(|e| e.deactivate());
        join_all(futures).await;
        let submitted_txn = stats.submitted.load(Ordering::Relaxed);
        let expired_txn = stats.expired.load(Ordering::Relaxed);
        context
            .report
            .report_metric(&self, "submitted_txn", submitted_txn as f64);
        context
            .report
            .report_metric(&self, "expired_txn", expired_txn as f64);
        context
            .report
            .report_metric(&self, "avg_txns_per_block", avg_txns_per_block as f64);
        context.report.report_metric(&self, "avg_tps", avg_tps);
        context
            .report
            .report_metric(&self, "avg_latency", avg_latency);
        info!("avg_txns_per_block: {}", avg_txns_per_block);
        let expired_text = if expired_txn == 0 {
            "no expired txns".to_string()
        } else {
            format!("(!) expired {} out of {} txns", expired_txn, submitted_txn)
        };
        context.report.report_text(format!(
            "{} : {:.0} TPS, {:.1} ms latency, {}",
            self, avg_tps, avg_latency, expired_text
        ));
        Ok(())
    }

    fn deadline(&self) -> Duration {
        Duration::from_secs(600)
    }
}

impl Display for PerformanceBenchmarkNodesDown {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
        if self.num_nodes_down == 0 {
            write!(f, "all up")
        } else {
            write!(f, "{}% down", self.num_nodes_down)
        }
    }
}
<commit_msg>[cluster-test] Change num_nodes_down to percent_nodes_down<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    cluster::Cluster,
    effects::{Effect, StopContainer},
    experiments::{Context, Experiment, ExperimentParam},
    instance,
    instance::Instance,
    stats,
    tx_emitter::EmitJobRequest,
    util::unix_timestamp_now,
};
use async_trait::async_trait;
use futures::future::join_all;
use slog_scope::info;
use std::{
    collections::HashSet,
    fmt::{Display, Error, Formatter},
    sync::atomic::Ordering,
    time::Duration,
};
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
pub struct PerformanceBenchmarkNodesDownParams {
    #[structopt(
        long,
        default_value = "0",
        help = "Percent of nodes which should be down"
    )]
    pub percent_nodes_down: usize,
    #[structopt(
        long,
        help = "Whether cluster test should run against validators or full nodes"
    )]
    pub is_fullnode: bool,
    #[structopt(
    long,
    default_value = Box::leak(format!("{}", DEFAULT_BENCH_DURATION).into_boxed_str()),
    help = "Duration of an experiment in seconds"
    )]
    pub duration: u64,
}

pub struct PerformanceBenchmarkNodesDown {
    down_instances: Vec<Instance>,
    up_instances: Vec<Instance>,
    percent_nodes_down: usize,
    duration: Duration,
}

pub const DEFAULT_BENCH_DURATION: u64 = 120;

impl PerformanceBenchmarkNodesDownParams {
    pub fn new_nodes_down(percent_nodes_down: usize) -> Self {
        Self {
            percent_nodes_down,
            is_fullnode: false,
            duration: DEFAULT_BENCH_DURATION,
        }
    }
}

impl ExperimentParam for PerformanceBenchmarkNodesDownParams {
    type E = PerformanceBenchmarkNodesDown;
    fn build(self, cluster: &Cluster) -> Self::E {
        if self.is_fullnode {
            let num_nodes = cluster.fullnode_instances().len();
            let nodes_down = (num_nodes * self.percent_nodes_down) / 100;
            let (down_instances, up_instances) = cluster.split_n_fullnodes_random(nodes_down);
            Self::E {
                down_instances: down_instances.into_fullnode_instances(),
                up_instances: up_instances.into_fullnode_instances(),
                percent_nodes_down: self.percent_nodes_down,
                duration: Duration::from_secs(self.duration),
            }
        } else {
            let num_nodes = cluster.validator_instances().len();
            let nodes_down = (num_nodes * self.percent_nodes_down) / 100;
            let (down_instances, up_instances) = cluster.split_n_validators_random(nodes_down);
            Self::E {
                down_instances: down_instances.into_validator_instances(),
                up_instances: up_instances.into_validator_instances(),
                percent_nodes_down: self.percent_nodes_down,
                duration: Duration::from_secs(self.duration),
            }
        }
    }
}

#[async_trait]
impl Experiment for PerformanceBenchmarkNodesDown {
    fn affected_validators(&self) -> HashSet<String> {
        instance::instancelist_to_set(&self.down_instances)
    }

    async fn run(&mut self, context: &mut Context<'_>) -> anyhow::Result<()> {
        let stop_effects: Vec<_> = self
            .down_instances
            .clone()
            .into_iter()
            .map(StopContainer::new)
            .collect();
        let futures = stop_effects.iter().map(|e| e.activate());
        join_all(futures).await;
        let buffer = Duration::from_secs(60);
        let window = self.duration + buffer * 2;
        let emit_job_request = EmitJobRequest::for_instances(
            self.up_instances.clone(),
            context.global_emit_job_request,
        );
        let stats = context
            .tx_emitter
            .emit_txn_for(window, emit_job_request)
            .await?;
        let end = unix_timestamp_now() - buffer;
        let start = end - window + 2 * buffer;
        let (avg_tps, avg_latency) = stats::txn_stats(&context.prometheus, start, end)?;
        let avg_txns_per_block = stats::avg_txns_per_block(&context.prometheus, start, end)?;
        info!(
            "Link to dashboard : {}",
            context.prometheus.link_to_dashboard(start, end)
        );
        let futures = stop_effects.iter().map(|e| e.deactivate());
        join_all(futures).await;
        let submitted_txn = stats.submitted.load(Ordering::Relaxed);
        let expired_txn = stats.expired.load(Ordering::Relaxed);
        context
            .report
            .report_metric(&self, "submitted_txn", submitted_txn as f64);
        context
            .report
            .report_metric(&self, "expired_txn", expired_txn as f64);
        context
            .report
            .report_metric(&self, "avg_txns_per_block", avg_txns_per_block as f64);
        context.report.report_metric(&self, "avg_tps", avg_tps);
        context
            .report
            .report_metric(&self, "avg_latency", avg_latency);
        info!("avg_txns_per_block: {}", avg_txns_per_block);
        let expired_text = if expired_txn == 0 {
            "no expired txns".to_string()
        } else {
            format!("(!) expired {} out of {} txns", expired_txn, submitted_txn)
        };
        context.report.report_text(format!(
            "{} : {:.0} TPS, {:.1} ms latency, {}",
            self, avg_tps, avg_latency, expired_text
        ));
        Ok(())
    }

    fn deadline(&self) -> Duration {
        Duration::from_secs(600)
    }
}

impl Display for PerformanceBenchmarkNodesDown {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
        if self.percent_nodes_down == 0 {
            write!(f, "all up")
        } else {
            write!(f, "{}% down", self.percent_nodes_down)
        }
    }
}
<|endoftext|>


<commit_before>//! Backend for Rust

use super::RUST_CONTEXT;
use backend::{CompilerOptions, Environment, ForContext, FromNaming, Naming, PackageUtils,
              SnakeCase};
use backend::errors::*;
use core::{ForEachLoc, RpEnumBody, RpEnumOrdinal, RpField, RpInterfaceBody, RpName, RpTupleBody,
           RpType, RpTypeBody};
use genco::{Element, Quoted, Rust, Tokens};
use genco::rust::{imported_alias, imported_alias_ref, imported_ref};
use listeners::Listeners;
use rust_compiler::RustCompiler;
use rust_file_spec::RustFileSpec;
use rust_options::RustOptions;
use std::borrow::Cow;

const TYPE_SEP: &'static str = "_";
const SCOPE_SEP: &'static str = "::";

pub struct RustBackend {
    pub env: Environment,
    listeners: Box<Listeners>,
    id_converter: Option<Box<Naming>>,
    to_lower_snake: Box<Naming>,
    hash_map: Rust<'static>,
    json_value: Rust<'static>,
}

impl RustBackend {
    pub fn new(
        env: Environment,
        _: RustOptions,
        listeners: Box<Listeners>,
        id_converter: Option<Box<Naming>>,
    ) -> RustBackend {
        RustBackend {
            env: env,
            listeners: listeners,
            id_converter: id_converter,
            to_lower_snake: SnakeCase::new().to_lower_snake(),
            hash_map: imported_ref("std::collections", "HashMap"),
            json_value: imported_alias_ref("serde_json", "Value", "json"),
        }
    }

    pub fn compiler(&self, options: CompilerOptions) -> Result<RustCompiler> {
        Ok(RustCompiler {
            out_path: options.out_path,
            backend: self,
        })
    }

    pub fn verify(&self) -> Result<()> {
        Ok(())
    }

    fn ident(&self, name: &str) -> String {
        if let Some(ref id_converter) = self.id_converter {
            id_converter.convert(name)
        } else {
            name.to_owned()
        }
    }

    fn convert_type_name(&self, name: &RpName) -> String {
        name.join(TYPE_SEP)
    }

    fn convert_type_id<'a>(&self, name: &'a RpName) -> Result<Element<'a, Rust<'a>>> {
        let registered = self.env.lookup(name)?;

        let local_name = registered.local_name(&name, |p| p.join(TYPE_SEP), |c| c.join(SCOPE_SEP));

        if let Some(ref prefix) = name.prefix {
            let package_name = self.package(&name.package).parts.join("::");
            return Ok(
                imported_alias(
                    Cow::Owned(package_name),
                    Cow::Owned(local_name),
                    Cow::Borrowed(prefix),
                ).into(),
            );
        }

        Ok(local_name.into())
    }

    fn into_type<'a>(&self, field: &'a RpField) -> Result<Tokens<'a, Rust<'a>>> {
        let stmt = self.into_rust_type(&field.ty)?;

        if field.is_optional() {
            return Ok(toks!["Option<", stmt, ">"]);
        }

        Ok(stmt)
    }

    fn enum_value_fn<'a>(
        &self,
        name: String,
        match_body: Tokens<'a, Rust<'a>>,
    ) -> Tokens<'a, Rust<'a>> {
        let mut value_fn = Tokens::new();
        let mut match_decl = Tokens::new();

        match_decl.push("match *self {");
        match_decl.nested(match_body);
        match_decl.push("}");

        value_fn.push("pub fn value(&self) -> &'static str {");
        value_fn.nested(toks!["use self::", name, "::*;"]);
        value_fn.nested(match_decl);
        value_fn.push("}");

        value_fn
    }

    pub fn into_rust_type<'a>(&self, ty: &'a RpType) -> Result<Tokens<'a, Rust<'a>>> {
        use self::RpType::*;

        let ty = match *ty {
            String => toks!["String"],
            Bytes => toks!["String"],
            Signed { ref size } => {
                if size.map(|s| s <= 32usize).unwrap_or(true) {
                    toks!["i32"]
                } else {
                    toks!["i64"]
                }
            }
            Unsigned { ref size } => {
                if size.map(|s| s <= 32usize).unwrap_or(true) {
                    toks!["u32"]
                } else {
                    toks!["u64"]
                }
            }
            Float => toks!["f32"],
            Double => toks!["f64"],
            Boolean => toks!["bool"],
            Array { ref inner } => {
                let argument = self.into_rust_type(inner)?;
                toks!["Vec<", argument, ">"]
            }
            Name { ref name } => toks![self.convert_type_id(name)?],
            Map { ref key, ref value } => {
                let key = self.into_rust_type(key)?;
                let value = self.into_rust_type(value)?;
                toks![self.hash_map.clone(), "<", key, ", ", value, ">"]
            }
            Any => toks![self.json_value.clone()],
        };

        Ok(ty)
    }

    // Build the corresponding element out of a field declaration.
    fn field_element<'a>(&self, field: &'a RpField) -> Result<Tokens<'a, Rust<'a>>> {
        let mut elements = Tokens::new();

        let ident = self.ident(field.ident());
        let type_spec = self.into_type(field)?;

        if field.is_optional() {
            elements.push(toks!["#[serde(skip_serializing_if=\"Option::is_none\")]"]);
        }

        if field.name() != ident {
            elements.push(toks!["#[serde(rename = ", field.name().quoted(), ")]"]);
        }

        elements.push(toks![ident, ": ", type_spec, ","]);

        Ok(elements.into())
    }

    pub fn process_tuple<'a>(
        &self,
        out: &mut RustFileSpec<'a>,
        body: &'a RpTupleBody,
    ) -> Result<()> {
        let mut fields = Tokens::new();

        for field in &body.fields {
            fields.push(self.into_type(field)?);
        }

        let name = self.convert_type_name(&body.name);

        let mut elements = Tokens::new();
        elements.push("#[derive(Serialize, Deserialize, Debug)]");
        elements.push(toks![
            "struct ",
            name,
            "(",
            fields.join(", "),
            ");",
        ]);

        out.0.push(elements);
        Ok(())
    }

    pub fn process_enum<'a>(&self, out: &mut RustFileSpec<'a>, body: &'a RpEnumBody) -> Result<()> {
        let name = self.convert_type_name(&body.name);

        // variant declarations
        let mut variants = Tokens::new();
        // body of value function
        let mut match_body = Tokens::new();

        body.variants.for_each_loc(|variant| {
            let value = if let RpEnumOrdinal::String(ref s) = variant.ordinal {
                if s != variant.local_name.value() {
                    let rename = toks!["#[serde(rename = ", s.to_owned().quoted(), ")]"];
                    variants.push(rename);
                }

                s
            } else {
                &variant.local_name
            };

            // TODO: should not be necessary to clone since it derives from the body.
            match_body.push(toks![
                variant.local_name.value().as_str(),
                " => ",
                value.clone().quoted(),
                ",",
            ]);

            variants.push(toks![variant.local_name.value().as_str(), ","]);
            Ok(()) as Result<()>
        })?;

        let mut out_enum = Tokens::new();

        out_enum.push("#[derive(Serialize, Deserialize, Debug)]");
        out_enum.push(toks!["pub enum ", name.clone(), " {"]);
        out_enum.nested(variants);
        out_enum.push("}");

        let mut out_impl = Tokens::new();

        out_impl.push(toks!["impl ", name.clone(), " {"]);
        out_impl.nested(self.enum_value_fn(name, match_body));

        // code goes into impl
        for code in body.codes.for_context(RUST_CONTEXT) {
            for line in &code.lines {
                out_impl.nested(line.as_str());
            }
        }

        out_impl.push("}");

        out.0.push(out_enum);
        out.0.push(out_impl);
        Ok(())
    }

    pub fn process_type<'a>(&self, out: &mut RustFileSpec<'a>, body: &'a RpTypeBody) -> Result<()> {
        let mut fields = Tokens::new();

        for field in &body.fields {
            fields.push(self.field_element(field)?);
        }

        let name = self.convert_type_name(&body.name);
        let mut t = Tokens::new();

        t.push("#[derive(Serialize, Deserialize, Debug)]");
        t.push(toks!["pub struct ", name, " {"]);
        t.nested(fields);

        // TODO: clone should not be needed
        for code in body.codes.for_context(RUST_CONTEXT) {
            for line in &code.lines {
                t.nested(toks!(line.as_str()));
            }
        }

        t.push("}");

        out.0.push(t);
        Ok(())
    }

    pub fn process_interface<'a>(
        &self,
        out: &mut RustFileSpec<'a>,
        body: &'a RpInterfaceBody,
    ) -> Result<()> {
        let type_name = self.convert_type_name(&body.name);
        let mut t = Tokens::new();

        t.push("#[derive(Serialize, Deserialize, Debug)]");
        t.push("#[serde(tag = \"type\")]");
        t.push(toks!["pub enum ", type_name, " {"]);

        for code in body.codes.for_context(RUST_CONTEXT) {
            for line in &code.lines {
                t.nested(toks!(line.to_string()));
            }
        }

        let sub_types = body.sub_types.values().map(AsRef::as_ref);

        sub_types.for_each_loc(|sub_type| {
            let mut elements = Tokens::new();

            // TODO: clone should not be needed
            if let Some(sub_type_name) = sub_type.names.first() {
                elements.push(toks![
                    "#[serde(rename = ",
                    sub_type_name.to_string().quoted(),
                    ")]",
                ]);
            }

            elements.push(toks![sub_type.local_name.as_str(), " {"]);

            for field in body.fields.iter().chain(sub_type.fields.iter()) {
                elements.nested(self.field_element(field)?);
            }

            elements.push("},");

            t.nested(elements);

            Ok(()) as Result<()>
        })?;

        t.push("}");

        out.0.push(t);

        Ok(())
    }
}

impl PackageUtils for RustBackend {}
<commit_msg>[rust] copy less<commit_after>//! Backend for Rust

use super::RUST_CONTEXT;
use backend::{CompilerOptions, Environment, ForContext, FromNaming, Naming, PackageUtils,
              SnakeCase};
use backend::errors::*;
use core::{ForEachLoc, RpEnumBody, RpEnumOrdinal, RpField, RpInterfaceBody, RpName, RpTupleBody,
           RpType, RpTypeBody};
use genco::{Element, Quoted, Rust, Tokens};
use genco::rust::{imported_alias, imported_alias_ref, imported_ref};
use listeners::Listeners;
use rust_compiler::RustCompiler;
use rust_file_spec::RustFileSpec;
use rust_options::RustOptions;
use std::borrow::Cow;

const TYPE_SEP: &'static str = "_";
const SCOPE_SEP: &'static str = "::";

pub struct RustBackend {
    pub env: Environment,
    listeners: Box<Listeners>,
    id_converter: Option<Box<Naming>>,
    to_lower_snake: Box<Naming>,
    hash_map: Rust<'static>,
    json_value: Rust<'static>,
}

impl RustBackend {
    pub fn new(
        env: Environment,
        _: RustOptions,
        listeners: Box<Listeners>,
        id_converter: Option<Box<Naming>>,
    ) -> RustBackend {
        RustBackend {
            env: env,
            listeners: listeners,
            id_converter: id_converter,
            to_lower_snake: SnakeCase::new().to_lower_snake(),
            hash_map: imported_ref("std::collections", "HashMap"),
            json_value: imported_alias_ref("serde_json", "Value", "json"),
        }
    }

    pub fn compiler(&self, options: CompilerOptions) -> Result<RustCompiler> {
        Ok(RustCompiler {
            out_path: options.out_path,
            backend: self,
        })
    }

    pub fn verify(&self) -> Result<()> {
        Ok(())
    }

    fn ident(&self, name: &str) -> String {
        if let Some(ref id_converter) = self.id_converter {
            id_converter.convert(name)
        } else {
            name.to_owned()
        }
    }

    fn convert_type_name(&self, name: &RpName) -> String {
        name.join(TYPE_SEP)
    }

    fn convert_type_id<'a>(&self, name: &'a RpName) -> Result<Element<'a, Rust<'a>>> {
        let registered = self.env.lookup(name)?;

        let local_name = registered.local_name(&name, |p| p.join(TYPE_SEP), |c| c.join(SCOPE_SEP));

        if let Some(ref prefix) = name.prefix {
            let package_name = self.package(&name.package).parts.join("::");
            return Ok(
                imported_alias(
                    Cow::Owned(package_name),
                    Cow::Owned(local_name),
                    Cow::Borrowed(prefix),
                ).into(),
            );
        }

        Ok(local_name.into())
    }

    fn into_type<'a>(&self, field: &'a RpField) -> Result<Tokens<'a, Rust<'a>>> {
        let stmt = self.into_rust_type(&field.ty)?;

        if field.is_optional() {
            return Ok(toks!["Option<", stmt, ">"]);
        }

        Ok(stmt)
    }

    fn enum_value_fn<'a>(
        &self,
        name: String,
        match_body: Tokens<'a, Rust<'a>>,
    ) -> Tokens<'a, Rust<'a>> {
        let mut value_fn = Tokens::new();
        let mut match_decl = Tokens::new();

        match_decl.push("match *self {");
        match_decl.nested(match_body);
        match_decl.push("}");

        value_fn.push("pub fn value(&self) -> &'static str {");
        value_fn.nested(toks!["use self::", name, "::*;"]);
        value_fn.nested(match_decl);
        value_fn.push("}");

        value_fn
    }

    pub fn into_rust_type<'a>(&self, ty: &'a RpType) -> Result<Tokens<'a, Rust<'a>>> {
        use self::RpType::*;

        let ty = match *ty {
            String => toks!["String"],
            Bytes => toks!["String"],
            Signed { ref size } => {
                if size.map(|s| s <= 32usize).unwrap_or(true) {
                    toks!["i32"]
                } else {
                    toks!["i64"]
                }
            }
            Unsigned { ref size } => {
                if size.map(|s| s <= 32usize).unwrap_or(true) {
                    toks!["u32"]
                } else {
                    toks!["u64"]
                }
            }
            Float => toks!["f32"],
            Double => toks!["f64"],
            Boolean => toks!["bool"],
            Array { ref inner } => {
                let argument = self.into_rust_type(inner)?;
                toks!["Vec<", argument, ">"]
            }
            Name { ref name } => toks![self.convert_type_id(name)?],
            Map { ref key, ref value } => {
                let key = self.into_rust_type(key)?;
                let value = self.into_rust_type(value)?;
                toks![self.hash_map.clone(), "<", key, ", ", value, ">"]
            }
            Any => toks![self.json_value.clone()],
        };

        Ok(ty)
    }

    // Build the corresponding element out of a field declaration.
    fn field_element<'a>(&self, field: &'a RpField) -> Result<Tokens<'a, Rust<'a>>> {
        let mut elements = Tokens::new();

        let ident = self.ident(field.ident());
        let type_spec = self.into_type(field)?;

        if field.is_optional() {
            elements.push(toks!["#[serde(skip_serializing_if=\"Option::is_none\")]"]);
        }

        if field.name() != ident {
            elements.push(toks!["#[serde(rename = ", field.name().quoted(), ")]"]);
        }

        elements.push(toks![ident, ": ", type_spec, ","]);

        Ok(elements.into())
    }

    pub fn process_tuple<'a>(
        &self,
        out: &mut RustFileSpec<'a>,
        body: &'a RpTupleBody,
    ) -> Result<()> {
        let mut fields = Tokens::new();

        for field in &body.fields {
            fields.push(self.into_type(field)?);
        }

        let name = self.convert_type_name(&body.name);

        let mut elements = Tokens::new();
        elements.push("#[derive(Serialize, Deserialize, Debug)]");
        elements.push(toks![
            "struct ",
            name,
            "(",
            fields.join(", "),
            ");",
        ]);

        out.0.push(elements);
        Ok(())
    }

    pub fn process_enum<'a>(&self, out: &mut RustFileSpec<'a>, body: &'a RpEnumBody) -> Result<()> {
        let name = self.convert_type_name(&body.name);

        // variant declarations
        let mut variants = Tokens::new();
        // body of value function
        let mut match_body = Tokens::new();

        body.variants.for_each_loc(|variant| {
            let value = if let RpEnumOrdinal::String(ref s) = variant.ordinal {
                if s != variant.local_name.value() {
                    let rename = toks!["#[serde(rename = ", s.to_owned().quoted(), ")]"];
                    variants.push(rename);
                }

                s
            } else {
                &variant.local_name
            };

            // TODO: should not be necessary to clone since it derives from the body.
            match_body.push(toks![
                variant.local_name.value().as_str(),
                " => ",
                value.clone().quoted(),
                ",",
            ]);

            variants.push(toks![variant.local_name.value().as_str(), ","]);
            Ok(()) as Result<()>
        })?;

        let mut out_enum = Tokens::new();

        out_enum.push("#[derive(Serialize, Deserialize, Debug)]");
        out_enum.push(toks!["pub enum ", name.clone(), " {"]);
        out_enum.nested(variants);
        out_enum.push("}");

        let mut out_impl = Tokens::new();

        out_impl.push(toks!["impl ", name.clone(), " {"]);
        out_impl.nested(self.enum_value_fn(name, match_body));

        // code goes into impl
        for code in body.codes.for_context(RUST_CONTEXT) {
            for line in &code.lines {
                out_impl.nested(line.as_str());
            }
        }

        out_impl.push("}");

        out.0.push(out_enum);
        out.0.push(out_impl);
        Ok(())
    }

    pub fn process_type<'a>(&self, out: &mut RustFileSpec<'a>, body: &'a RpTypeBody) -> Result<()> {
        let mut fields = Tokens::new();

        for field in &body.fields {
            fields.push(self.field_element(field)?);
        }

        let name = self.convert_type_name(&body.name);
        let mut t = Tokens::new();

        t.push("#[derive(Serialize, Deserialize, Debug)]");
        t.push(toks!["pub struct ", name, " {"]);
        t.nested(fields);

        // TODO: clone should not be needed
        for code in body.codes.for_context(RUST_CONTEXT) {
            for line in &code.lines {
                t.nested(toks!(line.as_str()));
            }
        }

        t.push("}");

        out.0.push(t);
        Ok(())
    }

    pub fn process_interface<'a>(
        &self,
        out: &mut RustFileSpec<'a>,
        body: &'a RpInterfaceBody,
    ) -> Result<()> {
        let type_name = self.convert_type_name(&body.name);
        let mut t = Tokens::new();

        t.push("#[derive(Serialize, Deserialize, Debug)]");
        t.push("#[serde(tag = \"type\")]");
        t.push(toks!["pub enum ", type_name, " {"]);

        for code in body.codes.for_context(RUST_CONTEXT) {
            for line in &code.lines {
                t.nested(line.as_str());
            }
        }

        let sub_types = body.sub_types.values().map(AsRef::as_ref);

        sub_types.for_each_loc(|s| {
            let mut spec = Tokens::new();

            // TODO: clone should not be needed
            if let Some(ref sub_type_name) = s.names.first() {
                let name = sub_type_name.as_str();

                if name != s.local_name.as_str() {
                    spec.push(toks!["#[serde(rename = ", name.quoted(), ")]"]);
                }
            }

            spec.push(toks![s.local_name.as_str(), " {"]);

            for field in body.fields.iter().chain(s.fields.iter()) {
                spec.nested(self.field_element(field)?);
            }

            spec.push("},");
            t.nested(spec);
            Ok(()) as Result<()>
        })?;

        t.push("}");

        out.0.push(t);
        Ok(())
    }
}

impl PackageUtils for RustBackend {}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate clippy_lints;
extern crate rustc;
extern crate rustc_const_eval;
extern crate rustc_const_math;
extern crate syntax;

use clippy_lints::consts::{constant_simple, Constant, FloatWidth};
use rustc_const_math::ConstInt;
use rustc::hir::*;
use syntax::ast::{LitIntType, LitKind, NodeId, StrStyle};
use syntax::codemap::{Spanned, COMMAND_LINE_SP};
use syntax::symbol::Symbol;
use syntax::ptr::P;
use syntax::util::ThinVec;

fn spanned<T>(t: T) -> Spanned<T> {
    Spanned {
        node: t,
        span: COMMAND_LINE_SP,
    }
}

fn expr(n: Expr_) -> Expr {
    Expr {
        id: NodeId::new(1),
        node: n,
        span: COMMAND_LINE_SP,
        attrs: ThinVec::new(),
    }
}

fn lit(l: LitKind) -> Expr {
    expr(ExprLit(P(spanned(l))))
}

fn binop(op: BinOp_, l: Expr, r: Expr) -> Expr {
    expr(ExprBinary(spanned(op), P(l), P(r)))
}

fn check(expect: Constant, expr: &Expr) {
    assert_eq!(Some(expect), constant_simple(expr))
}

const TRUE: Constant = Constant::Bool(true);
const FALSE: Constant = Constant::Bool(false);
const ZERO: Constant = Constant::Int(ConstInt::U8(0));
const ONE: Constant = Constant::Int(ConstInt::U8(1));
const TWO: Constant = Constant::Int(ConstInt::U8(2));

#[test]
fn test_lit() {
    check(TRUE, &lit(LitKind::Bool(true)));
    check(FALSE, &lit(LitKind::Bool(false)));
    check(ZERO, &lit(LitKind::Int(0, LitIntType::Unsuffixed)));
    check(Constant::Str("cool!".into(), StrStyle::Cooked),
          &lit(LitKind::Str(Symbol::intern("cool!"), StrStyle::Cooked)));
}

#[test]
fn test_ops() {
    check(TRUE, &binop(BiOr, lit(LitKind::Bool(false)), lit(LitKind::Bool(true))));
    check(FALSE, &binop(BiAnd, lit(LitKind::Bool(false)), lit(LitKind::Bool(true))));

    let litzero = lit(LitKind::Int(0, LitIntType::Unsuffixed));
    let litone = lit(LitKind::Int(1, LitIntType::Unsuffixed));
    check(TRUE, &binop(BiEq, litzero.clone(), litzero.clone()));
    check(TRUE, &binop(BiGe, litzero.clone(), litzero.clone()));
    check(TRUE, &binop(BiLe, litzero.clone(), litzero.clone()));
    check(FALSE, &binop(BiNe, litzero.clone(), litzero.clone()));
    check(FALSE, &binop(BiGt, litzero.clone(), litzero.clone()));
    check(FALSE, &binop(BiLt, litzero.clone(), litzero.clone()));

    check(ZERO, &binop(BiAdd, litzero.clone(), litzero.clone()));
    check(TWO, &binop(BiAdd, litone.clone(), litone.clone()));
    check(ONE, &binop(BiSub, litone.clone(), litzero.clone()));
    check(ONE, &binop(BiMul, litone.clone(), litone.clone()));
    check(ONE, &binop(BiDiv, litone.clone(), litone.clone()));

    let half_any = Constant::Float("0.5".into(), FloatWidth::Any);
    let half32 = Constant::Float("0.5".into(), FloatWidth::F32);
    let half64 = Constant::Float("0.5".into(), FloatWidth::F64);
    let pos_zero = Constant::Float("0.0".into(), FloatWidth::F64);
    let neg_zero = Constant::Float("-0.0".into(), FloatWidth::F64);

    assert_eq!(pos_zero, pos_zero);
    assert_eq!(neg_zero, neg_zero);
    assert_eq!(None, pos_zero.partial_cmp(&neg_zero));

    assert_eq!(half_any, half32);
    assert_eq!(half_any, half64);
    // for transitivity
    assert_eq!(half32, half64);

    assert_eq!(Constant::Int(ConstInt::U8(0)), Constant::Int(ConstInt::U8(0)));
    assert_eq!(Constant::Int(ConstInt::U8(0)), Constant::Int(ConstInt::I8(0)));
    assert_eq!(Constant::Int(ConstInt::I8(-1)), Constant::Int(ConstInt::I8(-1)));
}
<commit_msg>Remove old tests for ConstInt::Infer as it has been removed<commit_after>#![feature(rustc_private)]

extern crate clippy_lints;
extern crate rustc;
extern crate rustc_const_eval;
extern crate rustc_const_math;
extern crate syntax;

use clippy_lints::consts::{constant_simple, Constant, FloatWidth};
use rustc_const_math::ConstInt;
use rustc::hir::*;
use syntax::ast::{LitIntType, LitKind, NodeId, StrStyle};
use syntax::codemap::{Spanned, COMMAND_LINE_SP};
use syntax::symbol::Symbol;
use syntax::ptr::P;
use syntax::util::ThinVec;

fn spanned<T>(t: T) -> Spanned<T> {
    Spanned {
        node: t,
        span: COMMAND_LINE_SP,
    }
}

fn expr(n: Expr_) -> Expr {
    Expr {
        id: NodeId::new(1),
        node: n,
        span: COMMAND_LINE_SP,
        attrs: ThinVec::new(),
    }
}

fn lit(l: LitKind) -> Expr {
    expr(ExprLit(P(spanned(l))))
}

fn binop(op: BinOp_, l: Expr, r: Expr) -> Expr {
    expr(ExprBinary(spanned(op), P(l), P(r)))
}

fn check(expect: Constant, expr: &Expr) {
    assert_eq!(Some(expect), constant_simple(expr))
}

const TRUE: Constant = Constant::Bool(true);
const FALSE: Constant = Constant::Bool(false);
const ZERO: Constant = Constant::Int(ConstInt::U8(0));
const ONE: Constant = Constant::Int(ConstInt::U8(1));
const TWO: Constant = Constant::Int(ConstInt::U8(2));

#[test]
fn test_lit() {
    check(TRUE, &lit(LitKind::Bool(true)));
    check(FALSE, &lit(LitKind::Bool(false)));
    check(ZERO, &lit(LitKind::Int(0, LitIntType::Unsuffixed)));
    check(Constant::Str("cool!".into(), StrStyle::Cooked),
          &lit(LitKind::Str(Symbol::intern("cool!"), StrStyle::Cooked)));
}

#[test]
fn test_ops() {
    check(TRUE, &binop(BiOr, lit(LitKind::Bool(false)), lit(LitKind::Bool(true))));
    check(FALSE, &binop(BiAnd, lit(LitKind::Bool(false)), lit(LitKind::Bool(true))));

    let litzero = lit(LitKind::Int(0, LitIntType::Unsuffixed));
    let litone = lit(LitKind::Int(1, LitIntType::Unsuffixed));
    check(TRUE, &binop(BiEq, litzero.clone(), litzero.clone()));
    check(TRUE, &binop(BiGe, litzero.clone(), litzero.clone()));
    check(TRUE, &binop(BiLe, litzero.clone(), litzero.clone()));
    check(FALSE, &binop(BiNe, litzero.clone(), litzero.clone()));
    check(FALSE, &binop(BiGt, litzero.clone(), litzero.clone()));
    check(FALSE, &binop(BiLt, litzero.clone(), litzero.clone()));

    check(ZERO, &binop(BiAdd, litzero.clone(), litzero.clone()));
    check(TWO, &binop(BiAdd, litone.clone(), litone.clone()));
    check(ONE, &binop(BiSub, litone.clone(), litzero.clone()));
    check(ONE, &binop(BiMul, litone.clone(), litone.clone()));
    check(ONE, &binop(BiDiv, litone.clone(), litone.clone()));

    let half_any = Constant::Float("0.5".into(), FloatWidth::Any);
    let half32 = Constant::Float("0.5".into(), FloatWidth::F32);
    let half64 = Constant::Float("0.5".into(), FloatWidth::F64);
    let pos_zero = Constant::Float("0.0".into(), FloatWidth::F64);
    let neg_zero = Constant::Float("-0.0".into(), FloatWidth::F64);

    assert_eq!(pos_zero, pos_zero);
    assert_eq!(neg_zero, neg_zero);
    assert_eq!(None, pos_zero.partial_cmp(&neg_zero));

    assert_eq!(half_any, half32);
    assert_eq!(half_any, half64);
    // for transitivity
    assert_eq!(half32, half64);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate adapton;

mod engine_is_from_scratch_consistent {
    //! This module tests that change propagation is from-scratch consistent

    /// Compare to this sound behavior to the unsound behavior from
    /// JaneStreet 'Incremental' libary.  In particular, Yit's gist
    /// shows the problematic change propagation behavior for a
    /// similar example program (dividing by zero when it should not):
    /// https://gist.github.com/khooyp/98abc0e64dc296deaa48
    #[test]
    fn avoid_divide_by_zero () {
        use adapton::macros::*;
        use adapton::engine::*;
        manage::init_dcg();

        // Construct two mutable inputs, `nom` and `den`, a
        // computation `div` that divides the nominator in `nom` by
        // the denominator in `den`, and a thunk `root` that first
        // checks whether the denominator is zero (returning zero if
        // so) and if non-zero, returns the value of the division.

        let nom  = cell!(0);
        let den  = cell!(1);

        // In Rust, cloning is explicit:
        let den2 = den.clone(); // here, we clone the _global reference_ to the cell.
        let den3 = den.clone(); // here, we clone the _global reference_ to the cell, again.

        let div  = thunk![ get!(nom) / get!(den) ];
        let root = thunk![ if get!(den2) == 0 { 0 } else { get!(div) } ];

        assert_eq!(get!(root), 0);
        set(&den3, 0);
        assert_eq!(get!(root), 0);
    }

    #[test]
    fn avoid_expensive_subcomp () {
        use adapton::macros::*;
        use adapton::engine::*;
        use std::hash::{Hash, Hasher};
        use std::collections::hash_map::DefaultHasher;

        manage::init_dcg();

        let flag = cell!(true); // flag: whether or not to do "iterative hash"
        let iter = cell!(3);    // iter: iterations for hashing
        let inp  = cell!(42);   // inp1: input value to hash

        let inp1  = inp.clone();  // we use inp non-linearly below
        let inp2  = inp.clone();  // we use inp non-linearly below
        let flag1 = flag.clone(); // we use flag non-linearly below
        let iter1 = iter.clone(); // we use iter non-linearly below

        let iter_hash = thunk![{
            let inp_val = get!(inp); // value to hash iteratively
            let mut hash_state = DefaultHasher::new();
            for _ in 0..get!(iter) { // hash iteratively, `iter` number of times
                inp_val.hash(&mut hash_state);
            };
            assert!(get!(iter) < 100); // For Testing: Too many iters is an error!
            hash_state.finish() // returns final hash value
        }];
        let root = thunk![ // switches between hashing iteratively, or not
            if get!(flag) { get!(iter_hash) }
            else { get!(inp1) }
        ];

        assert!(get!(root) != get!(inp2));
        set(&flag1, false);
        set(&iter1, 999999999);
        assert!(get!(root) == get!(inp2));
    }
}

mod engine_api {
    //! This module tests gives unit tests for the engine's core API

    #[test]
    fn force_cell () {
        use adapton::macros::*;
        use adapton::engine::*;
        manage::init_dcg();
        let a : u32      = 1234;
        let b : Art<u32> = cell!(a);
        let c : u32      = force(&b);
        assert_eq!(a, c);
    }

    #[test]
    fn force_map_cell () {
        use adapton::macros::*;
        use adapton::engine::*;
        manage::init_dcg();
        let a : u32      = 1234;
        let b : Art<u32> = cell!(a);
        let c : u64      = force_map(&b, |_,x| x as u64);
        assert_eq!(a as u64, c);
    }

    #[test]
    fn force_map_cell_project () {
        use adapton::macros::*;
        use adapton::engine::*;
        manage::init_dcg();
        let pair = (1234 as usize, 5678 as usize);
        let c    = cell!(pair);
        let fst  = force_map(&c, |_,x| x.0);
        let snd  = force_map(&c, |_,x| x.1);
        assert_eq!(pair.0, fst);
        assert_eq!(pair.1, snd);
    }

    #[test]
    fn force_map_prunes_dirty_traversal () {
        // Test whether using force_map correctly prunes dirtying;
        // this test traces the engine, counts the number of dirtying
        // steps, and ensures that this count is zero, as expected.
        use adapton::macros::*;
        use adapton::engine::*;
        use adapton::reflect;
        manage::init_dcg();
        reflect::dcg_reflect_begin();
        let c : Art<(usize,usize)> = cell(name_of_str("pair"), (1234, 5678));
        let t : Art<usize> = thunk![{
            let fst = force_map(&c, |_,x| x.0);
            fst + 100
        }];
        assert_eq!(force(&t), 1334);
        let _ : Art<(usize,usize)> = cell(name_of_str("pair"), (1234, 8765));
        assert_eq!(force(&t), 1334);
        let traces = reflect::dcg_reflect_end();
        let counts = reflect::trace::trace_count(&traces, Some(1));
        assert_eq!(counts.dirty.0, 0);
        assert_eq!(counts.dirty.1, 0);
    }

    #[test]
    fn force_map_thunk () {
        use adapton::macros::*;
        use adapton::engine::*;
        manage::init_dcg();
        let a : u32      = 1234;
        let b : Art<u32> = thunk![a];
        let c : u64      = force_map(&b, |_,x| x as u64);
        assert_eq!(a as u64, c);
    }
}
<commit_msg>make div-by-zero test match PLEMM slides<commit_after>#[macro_use]
extern crate adapton;

mod engine_is_from_scratch_consistent {
    //! This module tests that change propagation is from-scratch consistent

    /// Compare to this sound behavior to the unsound behavior from
    /// JaneStreet 'Incremental' libary.  In particular, Yit's gist
    /// shows the problematic change propagation behavior for a
    /// similar example program (dividing by zero when it should not):
    /// https://gist.github.com/khooyp/98abc0e64dc296deaa48

    #[test]
    fn avoid_divide_by_zero () {
        use adapton::macros::*;
        use adapton::engine::*;
        manage::init_dcg();

        // Construct two mutable inputs, `nom` and `den`, a
        // computation `div` that divides the nominator in `nom` by
        // the denominator in `den`, and a thunk `root` that first
        // checks whether the denominator is zero (returning zero if
        // so) and if non-zero, returns the value of the division.

        let nom  = cell!(42);
        let den  = cell!(2);

        // In Rust, cloning is explicit:
        let den2 = den.clone(); // here, we clone the _global reference_ to the cell.
        let den3 = den.clone(); // here, we clone the _global reference_ to the cell, again.

        let div   = thunk![ get!(nom) / get!(den) ];
        let check = thunk![ if get!(den2) == 0 { None } else { Some(get!(div)) } ];

        assert_eq!(get!(check), Some(21));
        set(&den3, 0); assert_eq!(get!(check), None);
        set(&den3, 2); assert_eq!(get!(check), Some(21));
    }

    #[test]
    fn avoid_expensive_subcomp () {
        use adapton::macros::*;
        use adapton::engine::*;
        use std::hash::{Hash, Hasher};
        use std::collections::hash_map::DefaultHasher;

        manage::init_dcg();

        let flag = cell!(true); // flag: whether or not to do "iterative hash"
        let iter = cell!(3);    // iter: iterations for hashing
        let inp  = cell!(42);   // inp1: input value to hash

        let inp1  = inp.clone();  // we use inp non-linearly below
        let inp2  = inp.clone();  // we use inp non-linearly below
        let flag1 = flag.clone(); // we use flag non-linearly below
        let iter1 = iter.clone(); // we use iter non-linearly below

        let iter_hash = thunk![{
            let inp_val = get!(inp); // value to hash iteratively
            let mut hash_state = DefaultHasher::new();
            for _ in 0..get!(iter) { // hash iteratively, `iter` number of times
                inp_val.hash(&mut hash_state);
            };
            assert!(get!(iter) < 100); // For Testing: Too many iters is an error!
            hash_state.finish() // returns final hash value
        }];
        let root = thunk![ // switches between hashing iteratively, or not
            if get!(flag) { get!(iter_hash) }
            else { get!(inp1) }
        ];

        assert!(get!(root) != get!(inp2));
        set(&flag1, false);
        set(&iter1, 999999999);
        assert!(get!(root) == get!(inp2));
    }
}

mod engine_api {
    //! This module tests gives unit tests for the engine's core API

    #[test]
    fn force_cell () {
        use adapton::macros::*;
        use adapton::engine::*;
        manage::init_dcg();
        let a : u32      = 1234;
        let b : Art<u32> = cell!(a);
        let c : u32      = force(&b);
        assert_eq!(a, c);
    }

    #[test]
    fn force_map_cell () {
        use adapton::macros::*;
        use adapton::engine::*;
        manage::init_dcg();
        let a : u32      = 1234;
        let b : Art<u32> = cell!(a);
        let c : u64      = force_map(&b, |_,x| x as u64);
        assert_eq!(a as u64, c);
    }

    #[test]
    fn force_map_cell_project () {
        use adapton::macros::*;
        use adapton::engine::*;
        manage::init_dcg();
        let pair = (1234 as usize, 5678 as usize);
        let c    = cell!(pair);
        let fst  = force_map(&c, |_,x| x.0);
        let snd  = force_map(&c, |_,x| x.1);
        assert_eq!(pair.0, fst);
        assert_eq!(pair.1, snd);
    }

    #[test]
    fn force_map_prunes_dirty_traversal () {
        // Test whether using force_map correctly prunes dirtying;
        // this test traces the engine, counts the number of dirtying
        // steps, and ensures that this count is zero, as expected.
        use adapton::macros::*;
        use adapton::engine::*;
        use adapton::reflect;
        manage::init_dcg();
        reflect::dcg_reflect_begin();
        let c : Art<(usize,usize)> = cell(name_of_str("pair"), (1234, 5678));
        let t : Art<usize> = thunk![{
            let fst = force_map(&c, |_,x| x.0);
            fst + 100
        }];
        assert_eq!(force(&t), 1334);
        let _ : Art<(usize,usize)> = cell(name_of_str("pair"), (1234, 8765));
        assert_eq!(force(&t), 1334);
        let traces = reflect::dcg_reflect_end();
        let counts = reflect::trace::trace_count(&traces, Some(1));
        assert_eq!(counts.dirty.0, 0);
        assert_eq!(counts.dirty.1, 0);
    }

    #[test]
    fn force_map_thunk () {
        use adapton::macros::*;
        use adapton::engine::*;
        manage::init_dcg();
        let a : u32      = 1234;
        let b : Art<u32> = thunk![a];
        let c : u64      = force_map(&b, |_,x| x as u64);
        assert_eq!(a as u64, c);
    }
}
<|endoftext|>


<commit_before>extern crate klee;

#[test]
fn basic_test() {
  let a : i32 = 0;
  klee::symbol(&a, "a");
  assert_eq!(a, 56);
}

#[test]
fn other_test() {
  let a : i32 = 0;
  let b : i32 = 0;

  klee::symbol(&a, "a");
  klee::symbol(&b, "b");

  if a == 50 {
    if b == 49 {
      panic!("bugger");
    }
  }
}

#[test]
fn yant() {
  let a = klee::some::<bool>(false, "a");
  let b = klee::some::<i32>(0, "b");

  let c = if a {
    if b > 50 && b < 100 {
      true
    } else {
      false
    }
  } else {
    true
  };

  assert_eq!(c, false);
}

#[test]
fn another_test() {
  let a = klee::some::<i32>(0, "a");

  if a > 60 && a < 90 {
    let b = a + 40;
    assert_eq!(b, 0);

    if b == 12 {
      panic!("This path should be unreachable");
    }

    assert_eq!(b, 101);
    assert_eq!(b, 150000);
  }
}
<commit_msg>Update simple.rs<commit_after>extern crate klee;

#[test]
fn basic_test() {
  let a : i32 = 0;
  klee::symbol(&a, "a");
  assert_eq!(a, 56);
}

#[test]
fn other_test() {
  let a : i32 = 0;
  let b : i32 = 0;

  klee::symbol(&a, "a");
  klee::symbol(&b, "b");

  if a == 50 {
    if b == 49 {
      panic!("bugger");
    }
  }
}

#[test]
fn yant() {
  let a = klee::some::<bool>("a");
  let b = klee::some::<i32>("b");

  let c = if a {
    if b > 50 && b < 100 {
      true
    } else {
      false
    }
  } else {
    true
  };

  assert_eq!(c, false);
}

#[test]
fn another_test() {
  let a = klee::some::<i32>("a");

  if a > 60 && a < 90 {
    let b = a + 40;
    assert_eq!(b, 0);

    if b == 12 {
      panic!("This path should be unreachable");
    }

    assert_eq!(b, 101);
    assert_eq!(b, 150000);
  }
}
<|endoftext|>


<commit_before>extern crate test;
extern crate itertools;

use itertools::Itertools;
use itertools::ItertoolsClonable;
use itertools::Stride;
use itertools::StrideMut;

#[test]
fn mut_stride() {
    let mut xs = vec![1i, 1, 1, 1, 1, 1];
    for x in StrideMut::from_slice(xs.as_mut_slice(), 2) {
        *x = 0i;
    }
    assert_eq!(xs, vec![0i, 1, 0, 1, 0, 1]);
}

#[test]
fn mut_stride_compose() {
    let mut xs = vec![1i, 1, 1, 1, 1, 1, 1, 1, 1, 1];
    {
        let iter1 = StrideMut::from_slice(xs.as_mut_slice(), 2);
        let mut iter2 = StrideMut::from_stride(iter1, 3);
        for x in iter2 {
            *x = 0i;
        }
    }
    assert_eq!(xs, vec![0i, 1, 1, 1, 1, 1, 0, 1, 1, 1]);
}

#[test]
fn stride_uneven() {
    let xs = [7i, 9, 8];
    let mut it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 8);
    assert!(it.len() == 0);
    assert!(it.next().is_none());

    let xs = [7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs.slice_from(1), 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 10);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride_compose() {
    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let odds = Stride::from_slice(xs, 2);
    let it = Stride::from_stride(odds, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![1i, 5, 9]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![2i, 6]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, 1);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![2i, 4, 6, 8]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.swap_ends();
    let it = Stride::from_stride(odds, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![9i, 5, 1]);

    let xs = [1i, 2, 3];
    let every = Stride::from_slice(xs, 1);
    assert_eq!(every.len(), 3);
    let odds = Stride::from_stride(every, 2);
    assert_eq!(odds.len(), 2);
    let v = odds.clones().collect::<Vec<int>>();
    assert_eq!(v, vec![1i, 3i]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, -2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![8i, 4]);
}

#[test]
fn from_stride_empty()
{
    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.drain();
    assert!(odds.len() == 0);
    assert!(odds.next().is_none());
    let mut it = Stride::from_stride(odds, 2);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride() {
    let xs: [u8, ..0]  = [];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (0, Some(0)));
    assert!(it.next().is_none());

    let xs = [7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 8);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 2).rev();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let xs = [7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (4, Some(4)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 10);
    assert!(it.len() == 0);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 1).rev();
    assert!(it.size_hint() == (4, Some(4)));
    assert!(*it.next().unwrap() == 10);
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 2);
    it.swap_ends();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, -2);
    assert_eq!(it.size_hint(), (2, Some(2)));
    assert_eq!(*it.next().unwrap(), 10);
    assert_eq!(*it.next().unwrap(), 9);
    assert_eq!(it.next(), None);
}

#[test]
fn stride_index() {
    let xs = [7i, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    assert_eq!(it[0], 7);
    assert_eq!(it[1], 8);
}

#[test]
#[should_fail]
fn stride_index_fail() {
    let xs = [7i, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    let _ = it[2];
}
<commit_msg>Fix stride tests to use slice literals<commit_after>extern crate test;
extern crate itertools;

use itertools::Itertools;
use itertools::ItertoolsClonable;
use itertools::Stride;
use itertools::StrideMut;

#[test]
fn mut_stride() {
    let mut xs = vec![1i, 1, 1, 1, 1, 1];
    for x in StrideMut::from_slice(xs.as_mut_slice(), 2) {
        *x = 0i;
    }
    assert_eq!(xs, vec![0i, 1, 0, 1, 0, 1]);
}

#[test]
fn mut_stride_compose() {
    let mut xs = vec![1i, 1, 1, 1, 1, 1, 1, 1, 1, 1];
    {
        let iter1 = StrideMut::from_slice(xs.as_mut_slice(), 2);
        let mut iter2 = StrideMut::from_stride(iter1, 3);
        for x in iter2 {
            *x = 0i;
        }
    }
    assert_eq!(xs, vec![0i, 1, 1, 1, 1, 1, 0, 1, 1, 1]);
}

#[test]
fn stride_uneven() {
    let xs = &[7i, 9, 8];
    let mut it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 8);
    assert!(it.len() == 0);
    assert!(it.next().is_none());

    let xs = &[7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs.slice_from(1), 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 10);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride_compose() {
    let xs = &[1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let odds = Stride::from_slice(xs, 2);
    let it = Stride::from_stride(odds, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![1i, 5, 9]);

    let xs = &[1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![2i, 6]);

    let xs = &[1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, 1);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![2i, 4, 6, 8]);

    let xs = &[1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.swap_ends();
    let it = Stride::from_stride(odds, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![9i, 5, 1]);

    let xs = &[1i, 2, 3];
    let every = Stride::from_slice(xs, 1);
    assert_eq!(every.len(), 3);
    let odds = Stride::from_stride(every, 2);
    assert_eq!(odds.len(), 2);
    let v = odds.clones().collect::<Vec<int>>();
    assert_eq!(v, vec![1i, 3i]);

    let xs = &[1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, -2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![8i, 4]);
}

#[test]
fn from_stride_empty()
{
    let xs = &[1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.drain();
    assert!(odds.len() == 0);
    assert!(odds.next().is_none());
    let mut it = Stride::from_stride(odds, 2);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride() {
    let xs: &[u8]  = &[];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (0, Some(0)));
    assert!(it.next().is_none());

    let xs = &[7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 8);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 2).rev();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let xs = &[7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (4, Some(4)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 10);
    assert!(it.len() == 0);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 1).rev();
    assert!(it.size_hint() == (4, Some(4)));
    assert!(*it.next().unwrap() == 10);
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 2);
    it.swap_ends();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, -2);
    assert_eq!(it.size_hint(), (2, Some(2)));
    assert_eq!(*it.next().unwrap(), 10);
    assert_eq!(*it.next().unwrap(), 9);
    assert_eq!(it.next(), None);
}

#[test]
fn stride_index() {
    let xs = &[7i, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    assert_eq!(it[0], 7);
    assert_eq!(it[1], 8);
}

#[test]
#[should_fail]
fn stride_index_fail() {
    let xs = &[7i, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    let _ = it[2];
}
<|endoftext|>