<commit_before>use super::helpers::allocations;
use super::helpers::fixtures::{get_language, get_language_queries_path};
use std::ffi::CString;
use std::{fs, ptr, slice, str};
use tree_sitter_tags::c_lib as c;
use tree_sitter_tags::{Error, TagKind, TagsConfiguration, TagsContext};

const PYTHON_TAG_QUERY: &'static str = r#"
(
    (function_definition
      name: (identifier) @name
      body: (block . (expression_statement (string) @doc))) @function
    (#strip! @doc "(^['\"\\s]*)|(['\"\\s]*$)")
)

(function_definition
  name: (identifier) @name) @function

(
    (class_definition
        name: (identifier) @name
        body: (block
            . (expression_statement (string) @doc))) @class
    (#strip! @doc "(^['\"\\s]*)|(['\"\\s]*$)")
)

(class_definition
  name: (identifier) @name) @class

(call
  function: (identifier) @name) @call
"#;

const JS_TAG_QUERY: &'static str = r#"
(
    (comment)* @doc .
    (class_declaration
        name: (identifier) @name) @class
    (#select-adjacent! @doc @class)
    (#strip! @doc "(^[/\\*\\s]*)|([/\\*\\s]*$)")
)

(
    (comment)* @doc .
    (method_definition
        name: (property_identifier) @name) @method
    (#select-adjacent! @doc @method)
    (#strip! @doc "(^[/\\*\\s]*)|([/\\*\\s]*$)")
)

(
    (comment)* @doc .
    (function_declaration
        name: (identifier) @name) @function
    (#select-adjacent! @doc @function)
    (#strip! @doc "(^[/\\*\\s]*)|([/\\*\\s]*$)")
)

(call_expression
    function: (identifier) @name) @call
"#;

const RUBY_TAG_QUERY: &'static str = r#"
(method
    name: (identifier) @name) @method

(method_call
    method: (identifier) @name) @call

((identifier) @name @call
 (#is-not? local))
"#;

#[test]
fn test_tags_python() {
    let language = get_language("python");
    let tags_config = TagsConfiguration::new(language, PYTHON_TAG_QUERY, "").unwrap();
    let mut tag_context = TagsContext::new();

    let source = br#"
    class Customer:
        """
        Data about a customer
        """

        def age(self):
            '''
            Get the customer's age
            '''
            compute_age(self.id)
    }
    "#;

    let tags = tag_context
        .generate_tags(&tags_config, source, None)
        .unwrap()
        .collect::<Result<Vec<_>, _>>()
        .unwrap();

    assert_eq!(
        tags.iter()
            .map(|t| (substr(source, &t.name_range), t.kind))
            .collect::<Vec<_>>(),
        &[
            ("Customer", TagKind::Class),
            ("age", TagKind::Function),
            ("compute_age", TagKind::Call),
        ]
    );

    assert_eq!(substr(source, &tags[0].line_range), "    class Customer:");
    assert_eq!(
        substr(source, &tags[1].line_range),
        "        def age(self):"
    );
    assert_eq!(tags[0].docs.as_ref().unwrap(), "Data about a customer");
    assert_eq!(tags[1].docs.as_ref().unwrap(), "Get the customer's age");
}

#[test]
fn test_tags_javascript() {
    let language = get_language("javascript");
    let tags_config = TagsConfiguration::new(language, JS_TAG_QUERY, "").unwrap();
    let source = br#"
    // hi

    // Data about a customer.
    // bla bla bla
    class Customer {
        /*
         * Get the customer's age
         */
        getAge() {
        }
    }

    // ok

    class Agent {

    }
    "#;

    let mut tag_context = TagsContext::new();
    let tags = tag_context
        .generate_tags(&tags_config, source, None)
        .unwrap()
        .collect::<Result<Vec<_>, _>>()
        .unwrap();

    assert_eq!(
        tags.iter()
            .map(|t| (substr(source, &t.name_range), t.kind))
            .collect::<Vec<_>>(),
        &[
            ("Customer", TagKind::Class),
            ("getAge", TagKind::Method),
            ("Agent", TagKind::Class)
        ]
    );
    assert_eq!(
        tags[0].docs.as_ref().unwrap(),
        "Data about a customer.\nbla bla bla"
    );
    assert_eq!(tags[1].docs.as_ref().unwrap(), "Get the customer's age");
    assert_eq!(tags[2].docs, None);
}

#[test]
fn test_tags_ruby() {
    let language = get_language("ruby");
    let locals_query =
        fs::read_to_string(get_language_queries_path("ruby").join("locals.scm")).unwrap();
    let tags_config = TagsConfiguration::new(language, RUBY_TAG_QUERY, &locals_query).unwrap();
    let source = strip_whitespace(
        8,
        "
        b = 1

        def foo()
            c = 1

            # a is a method because it is not in scope
            # b is a method because `b` doesn't capture variables from its containing scope
            bar a, b, c

            [1, 2, 3].each do |a|
                # a is a parameter
                # b is a method
                # c is a variable, because the block captures variables from its containing scope.
                baz a, b, c
            end
        end",
    );

    let mut tag_context = TagsContext::new();
    let tags = tag_context
        .generate_tags(&tags_config, source.as_bytes(), None)
        .unwrap()
        .collect::<Result<Vec<_>, _>>()
        .unwrap();

    assert_eq!(
        tags.iter()
            .map(|t| (
                substr(source.as_bytes(), &t.name_range),
                t.kind,
                (t.span.start.row, t.span.start.column),
            ))
            .collect::<Vec<_>>(),
        &[
            ("foo", TagKind::Method, (2, 0)),
            ("bar", TagKind::Call, (7, 4)),
            ("a", TagKind::Call, (7, 8)),
            ("b", TagKind::Call, (7, 11)),
            ("each", TagKind::Call, (9, 14)),
            ("baz", TagKind::Call, (13, 8)),
            ("b", TagKind::Call, (13, 15),),
        ]
    );
}

#[test]
fn test_tags_cancellation() {
    use std::sync::atomic::{AtomicUsize, Ordering};

    allocations::record(|| {
        // Large javascript document
        let source = (0..500)
            .map(|_| "/* hi */ class A { /* ok */ b() {} }\n")
            .collect::<String>();

        let cancellation_flag = AtomicUsize::new(0);
        let language = get_language("javascript");
        let tags_config = TagsConfiguration::new(language, JS_TAG_QUERY, "").unwrap();

        let mut tag_context = TagsContext::new();
        let tags = tag_context
            .generate_tags(&tags_config, source.as_bytes(), Some(&cancellation_flag))
            .unwrap();

        for (i, tag) in tags.enumerate() {
            if i == 150 {
                cancellation_flag.store(1, Ordering::SeqCst);
            }
            if let Err(e) = tag {
                assert_eq!(e, Error::Cancelled);
                return;
            }
        }

        panic!("Expected to halt tagging with an error");
    });
}

#[test]
fn test_tags_via_c_api() {
    allocations::record(|| {
        let tagger = c::ts_tagger_new();
        let buffer = c::ts_tags_buffer_new();
        let scope_name = "source.js";
        let language = get_language("javascript");

        let source_code = strip_whitespace(
            12,
            "
            var a = 1;

            // one
            // two
            // three
            function b() {
            }

            // four
            // five
            class C extends D {

            }

            b(a);",
        );

        let c_scope_name = CString::new(scope_name).unwrap();
        let result = c::ts_tagger_add_language(
            tagger,
            c_scope_name.as_ptr(),
            language,
            JS_TAG_QUERY.as_ptr(),
            ptr::null(),
            JS_TAG_QUERY.len() as u32,
            0,
        );
        assert_eq!(result, c::TSTagsError::Ok);

        let result = c::ts_tagger_tag(
            tagger,
            c_scope_name.as_ptr(),
            source_code.as_ptr(),
            source_code.len() as u32,
            buffer,
            ptr::null(),
        );
        assert_eq!(result, c::TSTagsError::Ok);
        let tags = unsafe {
            slice::from_raw_parts(
                c::ts_tags_buffer_tags(buffer),
                c::ts_tags_buffer_tags_len(buffer) as usize,
            )
        };
        let docs = str::from_utf8(unsafe {
            slice::from_raw_parts(
                c::ts_tags_buffer_docs(buffer) as *const u8,
                c::ts_tags_buffer_docs_len(buffer) as usize,
            )
        })
        .unwrap();

        assert_eq!(
            tags.iter()
                .map(|tag| (
                    tag.kind,
                    &source_code[tag.name_start_byte as usize..tag.name_end_byte as usize],
                    &source_code[tag.line_start_byte as usize..tag.line_end_byte as usize],
                    &docs[tag.docs_start_byte as usize..tag.docs_end_byte as usize],
                ))
                .collect::<Vec<_>>(),
            &[
                (
                    c::TSTagKind::Function,
                    "b",
                    "function b() {",
                    "one\ntwo\nthree"
                ),
                (
                    c::TSTagKind::Class,
                    "C",
                    "class C extends D {",
                    "four\nfive"
                ),
                (c::TSTagKind::Call, "b", "b(a);", "")
            ]
        );

        c::ts_tags_buffer_delete(buffer);
        c::ts_tagger_delete(tagger);
    });
}

fn substr<'a>(source: &'a [u8], range: &std::ops::Range<usize>) -> &'a str {
    std::str::from_utf8(&source[range.clone()]).unwrap()
}

fn strip_whitespace(indent: usize, s: &str) -> String {
    s.lines()
        .skip(1)
        .map(|line| &line[line.len().min(indent)..])
        .collect::<Vec<_>>()
        .join("\n")
}
<commit_msg>Tests compile<commit_after>use super::helpers::allocations;
use super::helpers::fixtures::{get_language, get_language_queries_path};
use std::ffi::CString;
use std::{fs, ptr, slice, str};
use tree_sitter_tags::c_lib as c;
use tree_sitter_tags::{Error, SyntaxType, TagsConfiguration, TagsContext};

const PYTHON_TAG_QUERY: &'static str = r#"
(
    (function_definition
      name: (identifier) @name
      body: (block . (expression_statement (string) @doc))) @function
    (#strip! @doc "(^['\"\\s]*)|(['\"\\s]*$)")
)

(function_definition
  name: (identifier) @name) @function

(
    (class_definition
        name: (identifier) @name
        body: (block
            . (expression_statement (string) @doc))) @class
    (#strip! @doc "(^['\"\\s]*)|(['\"\\s]*$)")
)

(class_definition
  name: (identifier) @name) @class

(call
  function: (identifier) @name) @call
"#;

const JS_TAG_QUERY: &'static str = r#"
(
    (comment)* @doc .
    (class_declaration
        name: (identifier) @name) @class
    (#select-adjacent! @doc @class)
    (#strip! @doc "(^[/\\*\\s]*)|([/\\*\\s]*$)")
)

(
    (comment)* @doc .
    (method_definition
        name: (property_identifier) @name) @method
    (#select-adjacent! @doc @method)
    (#strip! @doc "(^[/\\*\\s]*)|([/\\*\\s]*$)")
)

(
    (comment)* @doc .
    (function_declaration
        name: (identifier) @name) @function
    (#select-adjacent! @doc @function)
    (#strip! @doc "(^[/\\*\\s]*)|([/\\*\\s]*$)")
)

(call_expression
    function: (identifier) @name) @call
"#;

const RUBY_TAG_QUERY: &'static str = r#"
(method
    name: (identifier) @name) @method

(method_call
    method: (identifier) @name) @call

((identifier) @name @call
 (#is-not? local))
"#;

#[test]
fn test_tags_python() {
    let language = get_language("python");
    let tags_config = TagsConfiguration::new(language, PYTHON_TAG_QUERY, "").unwrap();
    let mut tag_context = TagsContext::new();

    let source = br#"
    class Customer:
        """
        Data about a customer
        """

        def age(self):
            '''
            Get the customer's age
            '''
            compute_age(self.id)
    }
    "#;

    let tags = tag_context
        .generate_tags(&tags_config, source, None)
        .unwrap()
        .collect::<Result<Vec<_>, _>>()
        .unwrap();

    assert_eq!(
        tags.iter()
            .map(|t| (substr(source, &t.name_range), t.syntax_type))
            .collect::<Vec<_>>(),
        &[
            ("Customer", SyntaxType::Class),
            ("age", SyntaxType::Function),
            ("compute_age", SyntaxType::Call),
        ]
    );

    assert_eq!(substr(source, &tags[0].line_range), "    class Customer:");
    assert_eq!(
        substr(source, &tags[1].line_range),
        "        def age(self):"
    );
    assert_eq!(tags[0].docs.as_ref().unwrap(), "Data about a customer");
    assert_eq!(tags[1].docs.as_ref().unwrap(), "Get the customer's age");
}

#[test]
fn test_tags_javascript() {
    let language = get_language("javascript");
    let tags_config = TagsConfiguration::new(language, JS_TAG_QUERY, "").unwrap();
    let source = br#"
    // hi

    // Data about a customer.
    // bla bla bla
    class Customer {
        /*
         * Get the customer's age
         */
        getAge() {
        }
    }

    // ok

    class Agent {

    }
    "#;

    let mut tag_context = TagsContext::new();
    let tags = tag_context
        .generate_tags(&tags_config, source, None)
        .unwrap()
        .collect::<Result<Vec<_>, _>>()
        .unwrap();

    assert_eq!(
        tags.iter()
            .map(|t| (substr(source, &t.name_range), t.syntax_type))
            .collect::<Vec<_>>(),
        &[
            ("Customer", SyntaxType::Class),
            ("getAge", SyntaxType::Method),
            ("Agent", SyntaxType::Class)
        ]
    );
    assert_eq!(
        tags[0].docs.as_ref().unwrap(),
        "Data about a customer.\nbla bla bla"
    );
    assert_eq!(tags[1].docs.as_ref().unwrap(), "Get the customer's age");
    assert_eq!(tags[2].docs, None);
}

#[test]
fn test_tags_ruby() {
    let language = get_language("ruby");
    let locals_query =
        fs::read_to_string(get_language_queries_path("ruby").join("locals.scm")).unwrap();
    let tags_config = TagsConfiguration::new(language, RUBY_TAG_QUERY, &locals_query).unwrap();
    let source = strip_whitespace(
        8,
        "
        b = 1

        def foo()
            c = 1

            # a is a method because it is not in scope
            # b is a method because `b` doesn't capture variables from its containing scope
            bar a, b, c

            [1, 2, 3].each do |a|
                # a is a parameter
                # b is a method
                # c is a variable, because the block captures variables from its containing scope.
                baz a, b, c
            end
        end",
    );

    let mut tag_context = TagsContext::new();
    let tags = tag_context
        .generate_tags(&tags_config, source.as_bytes(), None)
        .unwrap()
        .collect::<Result<Vec<_>, _>>()
        .unwrap();

    assert_eq!(
        tags.iter()
            .map(|t| (
                substr(source.as_bytes(), &t.name_range),
                t.syntax_type,
                (t.span.start.row, t.span.start.column),
            ))
            .collect::<Vec<_>>(),
        &[
            ("foo", SyntaxType::Method, (2, 0)),
            ("bar", SyntaxType::Call, (7, 4)),
            ("a", SyntaxType::Call, (7, 8)),
            ("b", SyntaxType::Call, (7, 11)),
            ("each", SyntaxType::Call, (9, 14)),
            ("baz", SyntaxType::Call, (13, 8)),
            ("b", SyntaxType::Call, (13, 15),),
        ]
    );
}

#[test]
fn test_tags_cancellation() {
    use std::sync::atomic::{AtomicUsize, Ordering};

    allocations::record(|| {
        // Large javascript document
        let source = (0..500)
            .map(|_| "/* hi */ class A { /* ok */ b() {} }\n")
            .collect::<String>();

        let cancellation_flag = AtomicUsize::new(0);
        let language = get_language("javascript");
        let tags_config = TagsConfiguration::new(language, JS_TAG_QUERY, "").unwrap();

        let mut tag_context = TagsContext::new();
        let tags = tag_context
            .generate_tags(&tags_config, source.as_bytes(), Some(&cancellation_flag))
            .unwrap();

        for (i, tag) in tags.enumerate() {
            if i == 150 {
                cancellation_flag.store(1, Ordering::SeqCst);
            }
            if let Err(e) = tag {
                assert_eq!(e, Error::Cancelled);
                return;
            }
        }

        panic!("Expected to halt tagging with an error");
    });
}

#[test]
fn test_tags_via_c_api() {
    allocations::record(|| {
        let tagger = c::ts_tagger_new();
        let buffer = c::ts_tags_buffer_new();
        let scope_name = "source.js";
        let language = get_language("javascript");

        let source_code = strip_whitespace(
            12,
            "
            var a = 1;

            // one
            // two
            // three
            function b() {
            }

            // four
            // five
            class C extends D {

            }

            b(a);",
        );

        let c_scope_name = CString::new(scope_name).unwrap();
        let result = c::ts_tagger_add_language(
            tagger,
            c_scope_name.as_ptr(),
            language,
            JS_TAG_QUERY.as_ptr(),
            ptr::null(),
            JS_TAG_QUERY.len() as u32,
            0,
        );
        assert_eq!(result, c::TSTagsError::Ok);

        let result = c::ts_tagger_tag(
            tagger,
            c_scope_name.as_ptr(),
            source_code.as_ptr(),
            source_code.len() as u32,
            buffer,
            ptr::null(),
        );
        assert_eq!(result, c::TSTagsError::Ok);
        let tags = unsafe {
            slice::from_raw_parts(
                c::ts_tags_buffer_tags(buffer),
                c::ts_tags_buffer_tags_len(buffer) as usize,
            )
        };
        let docs = str::from_utf8(unsafe {
            slice::from_raw_parts(
                c::ts_tags_buffer_docs(buffer) as *const u8,
                c::ts_tags_buffer_docs_len(buffer) as usize,
            )
        })
        .unwrap();

        assert_eq!(
            tags.iter()
                .map(|tag| (
                    tag.syntax_type,
                    &source_code[tag.name_start_byte as usize..tag.name_end_byte as usize],
                    &source_code[tag.line_start_byte as usize..tag.line_end_byte as usize],
                    &docs[tag.docs_start_byte as usize..tag.docs_end_byte as usize],
                ))
                .collect::<Vec<_>>(),
            &[
                (
                    c::TSSyntaxType::Function,
                    "b",
                    "function b() {",
                    "one\ntwo\nthree"
                ),
                (
                    c::TSSyntaxType::Class,
                    "C",
                    "class C extends D {",
                    "four\nfive"
                ),
                (c::TSSyntaxType::Call, "b", "b(a);", "")
            ]
        );

        c::ts_tags_buffer_delete(buffer);
        c::ts_tagger_delete(tagger);
    });
}

fn substr<'a>(source: &'a [u8], range: &std::ops::Range<usize>) -> &'a str {
    std::str::from_utf8(&source[range.clone()]).unwrap()
}

fn strip_whitespace(indent: usize, s: &str) -> String {
    s.lines()
        .skip(1)
        .map(|line| &line[line.len().min(indent)..])
        .collect::<Vec<_>>()
        .join("\n")
}
<|endoftext|>


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

//! Check license of third-party deps by inspecting src/vendor

use std::fs::File;
use std::io::Read;
use std::path::Path;

static LICENSES: &'static [&'static str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
];

// These are exceptions to Rust's permissive licensing policy, and
// should be considered bugs. Exceptions are only allowed in Rust
// tooling. It is _crucial_ that no exception crates be dependencies
// of the Rust runtime (std / test).
static EXCEPTIONS: &'static [&'static str] = &[
    "mdbook", // MPL2, mdbook
    "openssl", // BSD+advertising clause, cargo, mdbook
    "pest", // MPL2, mdbook via handlebars
    "thread-id", // Apache-2.0, mdbook
    "cssparser", // MPL-2.0, rustdoc
    "smallvec", // MPL-2.0, rustdoc
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros", // MPL-2.0, rustdoc
    "selectors", // MPL-2.0, rustdoc
];

pub fn check(path: &Path, bad: &mut bool) {
    let path = path.join("vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    'next_path: for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // skip our exceptions
        for exception in EXCEPTIONS {
            if dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("src/vendor/{}", exception)) {
                continue 'next_path;
            }
        }

        let toml = dir.path().join("Cargo.toml");
        if !check_license(&toml) {
            *bad = true;
        }
    }
    assert!(saw_dir, "no vendored source");
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1 .. l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}
<commit_msg>add exceptions for new deps<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Check license of third-party deps by inspecting src/vendor

use std::fs::File;
use std::io::Read;
use std::path::Path;

static LICENSES: &'static [&'static str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
];

// These are exceptions to Rust's permissive licensing policy, and
// should be considered bugs. Exceptions are only allowed in Rust
// tooling. It is _crucial_ that no exception crates be dependencies
// of the Rust runtime (std / test).
static EXCEPTIONS: &'static [&'static str] = &[
    "mdbook", // MPL2, mdbook
    "openssl", // BSD+advertising clause, cargo, mdbook
    "pest", // MPL2, mdbook via handlebars
    "thread-id", // Apache-2.0, mdbook
    "toml-query", // MPL-2.0, mdbook
    "is-match", // MPL-2.0, mdbook
    "cssparser", // MPL-2.0, rustdoc
    "smallvec", // MPL-2.0, rustdoc
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros", // MPL-2.0, rustdoc
    "selectors", // MPL-2.0, rustdoc
];

pub fn check(path: &Path, bad: &mut bool) {
    let path = path.join("vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    'next_path: for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // skip our exceptions
        for exception in EXCEPTIONS {
            if dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("src/vendor/{}", exception)) {
                continue 'next_path;
            }
        }

        let toml = dir.path().join("Cargo.toml");
        if !check_license(&toml) {
            *bad = true;
        }
    }
    assert!(saw_dir, "no vendored source");
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1 .. l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}
<|endoftext|>


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

//! Check license of third-party deps by inspecting src/vendor

use std::collections::{BTreeSet, HashSet};
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::process::Command;

use serde_json;

static LICENSES: &'static [&'static str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
    "Unlicense OR MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std / test).
static EXCEPTIONS: &'static [&'static str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
    "ordslice",           // Apache-2.0, rls
    "cloudabi",           // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
];

/// Which crates to check against the whitelist?
static WHITELIST_CRATES: &'static [CrateVersion] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_codegen_llvm", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
static WHITELIST: &'static [Crate] = &[
    Crate("aho-corasick"),
    Crate("arrayvec"),
    Crate("atty"),
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("byteorder"),
    Crate("cc"),
    Crate("chalk-engine"),
    Crate("chalk-macros"),
    Crate("cfg-if"),
    Crate("cmake"),
    Crate("crossbeam-deque"),
    Crate("crossbeam-epoch"),
    Crate("crossbeam-utils"),
    Crate("datafrog"),
    Crate("either"),
    Crate("ena"),
    Crate("env_logger"),
    Crate("filetime"),
    Crate("flate2"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("getopts"),
    Crate("humantime"),
    Crate("jobserver"),
    Crate("kernel32-sys"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("log"),
    Crate("log_settings"),
    Crate("memchr"),
    Crate("memoffset"),
    Crate("miniz-sys"),
    Crate("nodrop"),
    Crate("num_cpus"),
    Crate("owning_ref"),
    Crate("parking_lot"),
    Crate("parking_lot_core"),
    Crate("polonius-engine"),
    Crate("pkg-config"),
    Crate("quick-error"),
    Crate("rand"),
    Crate("redox_syscall"),
    Crate("redox_termios"),
    Crate("regex"),
    Crate("regex-syntax"),
    Crate("remove_dir_all"),
    Crate("rustc-demangle"),
    Crate("rustc-hash"),
    Crate("rustc-rayon"),
    Crate("rustc-rayon-core"),
    Crate("scoped-tls"),
    Crate("scopeguard"),
    Crate("smallvec"),
    Crate("stable_deref_trait"),
    Crate("tempfile"),
    Crate("termcolor"),
    Crate("terminon"),
    Crate("termion"),
    Crate("thread_local"),
    Crate("ucd-util"),
    Crate("unicode-width"),
    Crate("unreachable"),
    Crate("utf8-ranges"),
    Crate("void"),
    Crate("winapi"),
    Crate("winapi-build"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-x86_64-pc-windows-gnu"),
    Crate("wincolor"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to...

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name,)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl<'a> Crate<'a> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dep is in-tree
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(' ');
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences
    let path = path.join("vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // skip our exceptions
        if EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("src/vendor/{}", exception))
        }) {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = *bad || !check_license(&toml);
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of WHITELIST_CRATES at the given path. Changes `bad` to `true` if a check
/// failed.
///
/// Specifically, this checks that the dependencies are on the WHITELIST.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from cargo metadata
    let resolve = get_deps(path, cargo);

    // Get the whitelist into a convenient form
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if unapproved.len() > 0 {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Get the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a, 'b>(
    whitelist: &'a HashSet<Crate>,
    resolve: &'a Resolve,
    visited: &'b mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // Will contain bad deps
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist
    if must_be_on_whitelist {
        // If this dependency is not on the WHITELIST, add to bad set
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!)
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

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

//! Check license of third-party deps by inspecting src/vendor

use std::collections::{BTreeSet, HashSet, HashMap};
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::process::Command;

use serde_json;

static LICENSES: &'static [&'static str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
    "Unlicense OR MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std / test).
static EXCEPTIONS: &'static [&'static str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
    "ordslice",           // Apache-2.0, rls
    "cloudabi",           // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
];

/// Which crates to check against the whitelist?
static WHITELIST_CRATES: &'static [CrateVersion] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_codegen_llvm", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
static WHITELIST: &'static [Crate] = &[
    Crate("aho-corasick"),
    Crate("arrayvec"),
    Crate("atty"),
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("byteorder"),
    Crate("cc"),
    Crate("chalk-engine"),
    Crate("chalk-macros"),
    Crate("cfg-if"),
    Crate("cmake"),
    Crate("crossbeam-deque"),
    Crate("crossbeam-epoch"),
    Crate("crossbeam-utils"),
    Crate("datafrog"),
    Crate("either"),
    Crate("ena"),
    Crate("env_logger"),
    Crate("filetime"),
    Crate("flate2"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("getopts"),
    Crate("humantime"),
    Crate("jobserver"),
    Crate("kernel32-sys"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("log"),
    Crate("log_settings"),
    Crate("memchr"),
    Crate("memoffset"),
    Crate("miniz-sys"),
    Crate("nodrop"),
    Crate("num_cpus"),
    Crate("owning_ref"),
    Crate("parking_lot"),
    Crate("parking_lot_core"),
    Crate("polonius-engine"),
    Crate("pkg-config"),
    Crate("quick-error"),
    Crate("rand"),
    Crate("redox_syscall"),
    Crate("redox_termios"),
    Crate("regex"),
    Crate("regex-syntax"),
    Crate("remove_dir_all"),
    Crate("rustc-demangle"),
    Crate("rustc-hash"),
    Crate("rustc-rayon"),
    Crate("rustc-rayon-core"),
    Crate("scoped-tls"),
    Crate("scopeguard"),
    Crate("smallvec"),
    Crate("stable_deref_trait"),
    Crate("tempfile"),
    Crate("termcolor"),
    Crate("terminon"),
    Crate("termion"),
    Crate("thread_local"),
    Crate("ucd-util"),
    Crate("unicode-width"),
    Crate("unreachable"),
    Crate("utf8-ranges"),
    Crate("void"),
    Crate("winapi"),
    Crate("winapi-build"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-x86_64-pc-windows-gnu"),
    Crate("wincolor"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to...

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name,)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl<'a> Crate<'a> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dep is in-tree
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(' ');
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences
    let path = path.join("vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // skip our exceptions
        if EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("src/vendor/{}", exception))
        }) {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = *bad || !check_license(&toml);
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of WHITELIST_CRATES at the given path. Changes `bad` to `true` if a check
/// failed.
///
/// Specifically, this checks that the dependencies are on the WHITELIST.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from cargo metadata
    let resolve = get_deps(path, cargo);

    // Get the whitelist into a convenient form
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if unapproved.len() > 0 {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }

    check_crate_duplicate(&resolve, bad);
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Get the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a, 'b>(
    whitelist: &'a HashSet<Crate>,
    resolve: &'a Resolve,
    visited: &'b mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // Will contain bad deps
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist
    if must_be_on_whitelist {
        // If this dependency is not on the WHITELIST, add to bad set
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!)
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

    unapproved
}

fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) {
    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
        // These two crates take quite a long time to build, let's not let two
        // versions of them accidentally sneak into our dependency graph to
        // ensure we keep our CI times under control
        // "cargo", // FIXME(#53005)
        // "rustc-ap-syntax", // FIXME(#53006)
    ];
    let mut name_to_id = HashMap::new();
    for node in resolve.nodes.iter() {
        name_to_id.entry(node.id.split_whitespace().next().unwrap())
            .or_insert(Vec::new())
            .push(&node.id);
    }

    for name in FORBIDDEN_TO_HAVE_DUPLICATES {
        if name_to_id[name].len() <= 1 {
            continue
        }
        println!("crate `{}` is duplicated in `Cargo.lock`", name);
        for id in name_to_id[name].iter() {
            println!("  * {}", id);
        }
        *bad = true;
    }
}
<|endoftext|>


<commit_before>//!
//! These are black boxes to perform authenticated asymmetric
//! cryptography.
//!
//! TODO: Document me
//!
//! ## Usage
//! ```rust{.example}
//! use tweetnacl::cryptobox::CryptoBox;
//!
//! let box1 = CryptoBox::new();
//! let box2 = CryptoBox::new();
//!
//! let msg = "my secret message";
//!
//! let (cipher, nonce) = box1.encrypt(msg.as_bytes(), box2.keypair.pk);
//!
//! let plain = box2.decrypt(cipher.as_slice(), nonce.as_slice(), box1.keypair.pk);
//! assert!(plain == Vec::from_slice(msg.as_bytes()));
//! ```

use bindings::*;

/// Size of zero padding used in encrypted messages.
pub static ZERO_BYTES: uint = 32;
/// Size of encrypted message's nonce value.
pub static NONCE_BYTES: uint = 24;
/// Size of public key.
pub static PUBLICKEY_BYTES: uint = 32;
/// Size of secret key.
pub static SECRETKEY_BYTES: uint = 32;

/// TODO: document me
pub struct CryptoBox {
    pub keypair: Keypair,
}

/// A secret key used by CryptoBox
pub struct SecretKey ([u8, ..SECRETKEY_BYTES]);

/// A public key used by CryptoBox
pub struct PublicKey ([u8, ..PUBLICKEY_BYTES]);

impl PublicKey {
    /// Generate a public key matching a given secret key.
    pub fn from_secret_key(key: SecretKey) -> PublicKey {
        let mut pk = [0u8, ..PUBLICKEY_BYTES];
        let SecretKey(sk) = key;

        unsafe {
            crypto_scalarmult_base(pk.as_mut_ptr(), sk.as_ptr());
        }

        PublicKey(pk)
    }
}

/// A asymmetric keypair containing matching public and private keys.
pub struct Keypair {
    /// Public key
    pub pk: PublicKey,
    /// Private key
    pub sk: SecretKey
}

impl Keypair {
    /// Generate a random matching public and private key.
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBLICKEY_BYTES];
        let mut sk = [0u8, ..SECRETKEY_BYTES];

        unsafe {
            crypto_box_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());

            Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
        }
    }
}

impl CryptoBox {
    /// Generate a new CryptoBox using a random keypair
    pub fn new() -> CryptoBox {
        CryptoBox { keypair: Keypair::new() }
    }

    /// Generate a new CryptoBox using an existing keypair.
    pub fn new_with_key(key: Keypair) -> CryptoBox {
        CryptoBox { keypair: key }
    }

    /// Sign a message using this box's secret key and encrypt the
    /// message to the given recipient's PublicKey.
    pub fn encrypt(&self, msg: &[u8], recvKey: PublicKey) -> (Vec<u8>, Vec<u8>) {
        let mut stretched = Vec::from_elem(ZERO_BYTES, 0u8);
        stretched.push_all(msg);

        let SecretKey(sk) = self.keypair.sk;
        let PublicKey(pk) = recvKey;

        let mut nonce = Vec::from_elem(NONCE_BYTES, 0u8);
        let mut cipher = Vec::from_elem(stretched.len(), 0u8);

        unsafe {
            randombytes(nonce.as_mut_ptr(), NONCE_BYTES as u64);

            match crypto_box(cipher.as_mut_ptr(),
                             stretched.as_ptr(),
                             stretched.len() as u64,
                             nonce.as_ptr(),
                             pk.as_ptr(),
                             sk.as_ptr()) {
                0 => (cipher, nonce),
                _ => fail!("crypto_box failed")
            }
        }
    }

    pub fn decrypt(&self, cipher: &[u8], nonce: &[u8], sendKey: PublicKey) -> Vec<u8> {
        let mut msg = Vec::from_elem(cipher.len(), 0u8);

        let SecretKey(sk) = self.keypair.sk;
        let PublicKey(pk) = sendKey;

        unsafe {
            // TODO: error handling.
            match crypto_box_open(msg.as_mut_ptr(),
                                  cipher.as_ptr(),
                                  cipher.len() as u64,
                                  nonce.as_ptr(),
                                  pk.as_ptr(),
                                  sk.as_ptr()) {
                0 => Vec::from_slice(msg.slice(ZERO_BYTES, msg.len())),
                _ => fail!("crypto_box_open failed")
            }
        }
    }
}

#[test]
fn test_cryptobox_sanity() {
    for i in range(0 as uint, 16) {
        let box1 = CryptoBox::new();
        let box2 = CryptoBox::new();

        let msg = Vec::from_elem(i * 4, i as u8);

        let (cipher, nonce) = box1.encrypt(msg.as_slice(), box2.keypair.pk);

        print!("enc:\t{}\nnonce:\t{}\n", cipher, nonce);

        let plain = box2.decrypt(cipher.as_slice(), nonce.as_slice(), box1.keypair.pk);

        print!("plain:\t{}\n", plain);
        print!("msg:\t{}\n", msg);

        assert!(msg == plain);
    }
}

#[test]
fn test_cryptobox_pubkey_from_seckey() {
    for _ in range(0i, 16) {
        let key = Keypair::new();
        let pubkey = PublicKey::from_secret_key(key.sk);

        let PublicKey(k1) = pubkey;
        let PublicKey(k2) = key.pk;

        assert!(k1 == k2);
    }
}
<commit_msg>Switch up API of cryptobox to match secretbox<commit_after>//!
//! These are black boxes to perform authenticated asymmetric
//! cryptography.
//!
//! TODO: Document me
//!
//! ## Usage
//! ```rust{.example}
//! use tweetnacl::cryptobox::{CryptoBox, Keypair};
//!
//! let key1 = Keypair::new();
//! let key2 = Keypair::new();
//!
//! let box1 = CryptoBox::from_key_pair(key1.sk, key2.pk);
//! let box2 = CryptoBox::from_key_pair(key2.sk, key1.pk);
//!
//! let msg = b"my secret message";
//!
//! let boxed = box1.encrypt(msg);
//!
//! let plain = box2.decrypt(boxed);
//! assert!(plain == Vec::from_slice(msg));
//! ```

use bindings::*;

/// Size of zero padding used in encrypted messages.
pub static ZERO_BYTES: uint = 32;
/// Size of encrypted message's nonce value.
pub static NONCE_BYTES: uint = 24;
/// Size of public key.
pub static PUBLICKEY_BYTES: uint = 32;
/// Size of secret key.
pub static SECRETKEY_BYTES: uint = 32;

/// A secret key used by CryptoBox
pub struct SecretKey ([u8, ..SECRETKEY_BYTES]);

/// A public key used by CryptoBox
pub struct PublicKey ([u8, ..PUBLICKEY_BYTES]);

impl PublicKey {
    /// Generate a public key matching a given secret key.
    pub fn from_secret_key(key: SecretKey) -> PublicKey {
        let mut pk = [0u8, ..PUBLICKEY_BYTES];
        let SecretKey(sk) = key;

        unsafe { crypto_scalarmult_base(pk.as_mut_ptr(), sk.as_ptr()); }

        PublicKey(pk)
    }
}

impl SecretKey {
    /// Generate a random new secret key.
    pub fn new() -> SecretKey {
        let mut sk = [0u8, ..SECRETKEY_BYTES];

        unsafe { randombytes(sk.as_mut_ptr(), SECRETKEY_BYTES as u64); }

        SecretKey(sk)
    }
}

/// A asymmetric keypair containing matching public and private keys.
pub struct Keypair {
    /// Public key
    pub pk: PublicKey,
    /// Private key
    pub sk: SecretKey
}

impl Keypair {
    /// Generate a random matching public and private key.
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBLICKEY_BYTES];
        let mut sk = [0u8, ..SECRETKEY_BYTES];

        unsafe {
            crypto_box_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());

            Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
        }
    }
}

pub struct BoxedMsg {
    pub nonce: [u8, ..NONCE_BYTES],
    pub cipher: Vec<u8>
}

/// TODO: document me
pub struct CryptoBox {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl CryptoBox {

    /// Generate a new CryptoBox using an existing keypair.
    pub fn from_key_pair(sendKey: SecretKey, recvKey: PublicKey) -> CryptoBox {
        CryptoBox { sk: sendKey, pk: recvKey }
    }

    /// Sign a message using this box's secret key and encrypt the
    /// message to the given recipient's PublicKey.
    pub fn encrypt(&self, msg: &[u8]) -> BoxedMsg {
        let mut stretched = Vec::from_elem(ZERO_BYTES, 0u8);
        stretched.push_all(msg);

        let SecretKey(sk) = self.sk;
        let PublicKey(pk) = self.pk;

        let mut nonce = [0u8, ..NONCE_BYTES];
        let mut cipher = Vec::from_elem(stretched.len(), 0u8);

        unsafe {
            randombytes(nonce.as_mut_ptr(), NONCE_BYTES as u64);

            match crypto_box(cipher.as_mut_ptr(),
                             stretched.as_ptr(),
                             stretched.len() as u64,
                             nonce.as_ptr(),
                             pk.as_ptr(),
                             sk.as_ptr()) {
                0 => BoxedMsg { nonce: nonce, cipher: cipher },
                _ => fail!("crypto_box failed")
            }
        }
    }

    pub fn decrypt(&self, boxMsg: BoxedMsg) -> Vec<u8> {
        let BoxedMsg { nonce, cipher } = boxMsg;

        let mut msg = Vec::from_elem(cipher.len(), 0u8);

        let SecretKey(sk) = self.sk;
        let PublicKey(pk) = self.pk;

        unsafe {
            // TODO: error handling.
            match crypto_box_open(msg.as_mut_ptr(),
                                  cipher.as_ptr(),
                                  cipher.len() as u64,
                                  nonce.as_ptr(),
                                  pk.as_ptr(),
                                  sk.as_ptr()) {
                0 => Vec::from_slice(msg.slice(ZERO_BYTES, msg.len())),
                _ => fail!("crypto_box_open failed")
            }
        }
    }
}

#[test]
fn test_cryptobox_sanity() {
    for i in range(0 as uint, 16) {
        let key1 = Keypair::new();
        let key2 = Keypair::new();

        let box1 = CryptoBox::from_key_pair(key1.sk, key2.pk);
        let box2 = CryptoBox::from_key_pair(key2.sk, key1.pk);

        let msg = Vec::from_elem(i * 4, i as u8);

        let boxed = box1.encrypt(msg.as_slice());

        print!("enc:\t{}\nnonce:\t{}\n", boxed.cipher, Vec::from_slice(boxed.nonce));

        let plain = box2.decrypt(boxed);

        print!("plain:\t{}\n", plain);
        print!("msg:\t{}\n", msg);

        assert!(msg == plain);
    }
}

#[test]
fn test_cryptobox_pubkey_from_keypair() {
    for _ in range(0i, 16) {
        let key = Keypair::new();
        let pubkey = PublicKey::from_secret_key(key.sk);

        let PublicKey(k1) = pubkey;
        let PublicKey(k2) = key.pk;

        assert!(k1 == k2);
    }
}

#[test]
fn test_cryptobox_pubkey_from_seckey() {
    for _ in range(0i, 16) {
        let key = SecretKey::new();
        let pk = PublicKey::from_secret_key(key);

        let msg = b"secret message";

        let cbox = CryptoBox::from_key_pair(key, pk);
        let boxed = cbox.encrypt(msg);
        let plain = cbox.decrypt(boxed);

        print!("plain:\t{}\n", plain);
        print!("msg:\t{}\n", msg);

        assert!(plain == Vec::from_slice(msg));
    }
}
<|endoftext|>


<commit_before>#![no_std]

#[macro_use]
extern crate static_assertions;

#[test]
fn test_eq_size() {
    assert_eq_size!([u8; 2], u16);
    assert_eq_size!([u8; 2], u16, (u8, u8));
    assert_eq_size!([u8; 4], u32, (u16, u8, u8), (u16, u16));
    // assert_eq_size!(u8, u16); // Fails to compile

    #[deny(unused_unsafe)]
    unsafe { assert_eq_size!(u8, u8); }
}
<commit_msg>[Tests] Ensure assert_eq_size doesn't drop its val<commit_after>#![no_std]

#[macro_use]
extern crate static_assertions;

/// A type that panics on drop.
struct PanicDrop<T>(T);

impl<T> Drop for PanicDrop<T> {
    fn drop(&mut self) {
        panic!("Dropped!");
    }
}

#[test]
fn test_eq_size() {
    assert_eq_size!([u8; 2], u16);
    assert_eq_size!([u8; 2], u16, (u8, u8));
    assert_eq_size!([u8; 4], u32, (u16, u8, u8), (u16, u16));
    // assert_eq_size!(u8, u16); // Fails to compile

    #[deny(unused_unsafe)]
    unsafe { assert_eq_size!(u8, u8); }
}

#[test]
fn test_eq_size_no_drop() {
    assert_eq_size!(u32, PanicDrop<u32>);
    assert_eq_size!(PanicDrop<u32>, u32);
    assert_eq_size!(PanicDrop<u32>, PanicDrop<u32>);
}
<|endoftext|>


<commit_before>use core::ptr;

pub struct Node<T> {
    pub elem: T,
    pub prev: Link<Node<T>>,
    pub next: Link<Node<T>>,
}

impl<T> Node<T> {
    pub fn new(elem: T) -> Self {
        Node {
            elem: elem,
            prev: Link::none(),
            next: Link::none(),
        }
    }
}

pub struct Link<T> {
    ptr: *mut T,
}

impl<T> Link<T> {
    pub fn some(ptr: *mut T) -> Self {
        Link {
            ptr: ptr,
        }
    }

    pub fn none() -> Self {
        Link {
            ptr: ptr::null_mut(),
        }
    }

    pub fn is_null(&self) -> bool {
        self.ptr == ptr::null_mut()
    }

    pub unsafe fn as_ref<'a>(&self) -> Option<&'a T> {
        self.ptr.as_ref()
    }

    pub unsafe fn as_mut<'a>(&mut self) -> Option<&'a mut T> {
        self.ptr.as_mut()
    }
}

impl<T> Clone for Link<T> {
    fn clone(&self) -> Self {
        Link {
            ptr: self.ptr,
        }
    }
}

impl<T> PartialEq<Link<T>> for Link<T> {
    fn eq(&self, rhs: &Link<T>) -> bool {
        self.ptr == rhs.ptr
    }
}
<commit_msg>heap: Add type Node<T><commit_after>use core::ptr;

pub struct UnsafeList<T> {
    head: Link<Node<T>>,
}

impl<T> UnsafeList<T> {
    pub unsafe fn new() -> Self {
        UnsafeList {
            head: Link::none(),
        }
    }

    pub unsafe fn push_front(&mut self, mut elem: Link<Node<T>>) {
        match self.head.as_mut() {
            None => {
                if let Some(ref mut node) = elem.as_mut() {
                    node.prev = Link::none();
                    node.next = Link::none();
                }
            },
            Some(ref mut node) => {
                if let Some(ref mut elem_node) = elem.as_mut() {
                    node.prev = elem.clone();

                    elem_node.next = self.head.clone();
                    elem_node.prev = Link::none();
                }
            }
        }

        self.head = elem;
    }

    pub unsafe fn pop(&mut self, mut elem: Link<Node<T>>) {
        if let Some(node) = elem.as_mut() {
            if let Some(prev) = node.prev.as_mut() {
                prev.next = node.next.clone();
            }

            if let Some(next) = node.next.as_mut() {
                next.prev = node.prev.clone();
            }
        } else {
            return;
        }

        if elem == self.head {
            if let Some(head) = self.head.as_mut() {
                self.head = head.next.clone();
            } else {
                self.head = Link::none();
            }
        }
    }

    pub unsafe fn cursor<'a>(&'a mut self) -> UnsafeCursor<'a, T> {
        let head_dup = self.head.clone();

        UnsafeCursor {
            head: &mut self.head,
            current: head_dup,
        }
    }
}

pub struct UnsafeCursor<'a, T: 'a> {
    head: &'a mut Link<Node<T>>,
    current: Link<Node<T>>,
}

impl<'a, T: 'a> UnsafeCursor<'a, T> {
    pub unsafe fn remove(&mut self) -> Link<Node<T>> {
        if self.current.is_null() {
            return Link::none();
        }

        let mut res = self.current.clone();
        let update_head = *self.head == self.current;

        self.next();

        if let Some(node) = res.as_mut() {
            if let Some(prev) = node.prev.as_mut() {
                prev.next = node.next.clone();
            }

            if let Some(next) = node.next.as_mut() {
                next.prev = node.prev.clone();
            }

            node.next = Link::none();
            node.prev = Link::none();
        }

        if update_head {
            *self.head = self.current.clone();
        }

        res
    }

    pub unsafe fn next(&mut self) {
        if let Some(node) = self.current.as_mut() {
            self.current = node.next.clone();
        }
    }

    pub unsafe fn as_ref(&self) -> Option<&Node<T>> {
        self.current.as_ref()
    }
}

pub struct Node<T> {
    pub elem: T,
    pub prev: Link<Node<T>>,
    pub next: Link<Node<T>>,
}

impl<T> Node<T> {
    pub fn new(elem: T) -> Self {
        Node {
            elem: elem,
            prev: Link::none(),
            next: Link::none(),
        }
    }
}

pub struct Link<T> {
    ptr: *mut T,
}

impl<T> Link<T> {
    pub fn some(ptr: *mut T) -> Self {
        Link {
            ptr: ptr,
        }
    }

    pub fn none() -> Self {
        Link {
            ptr: ptr::null_mut(),
        }
    }

    pub fn is_null(&self) -> bool {
        self.ptr == ptr::null_mut()
    }

    pub unsafe fn as_ref<'a>(&self) -> Option<&'a T> {
        self.ptr.as_ref()
    }

    pub unsafe fn as_mut<'a>(&mut self) -> Option<&'a mut T> {
        self.ptr.as_mut()
    }
}

impl<T> Clone for Link<T> {
    fn clone(&self) -> Self {
        Link {
            ptr: self.ptr,
        }
    }
}

impl<T> PartialEq<Link<T>> for Link<T> {
    fn eq(&self, rhs: &Link<T>) -> bool {
        self.ptr == rhs.ptr
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
use rustless;
use serde;
use serde_json;
use rustless::server::status;
use rustless::{Api, Nesting};
use valico::json_dsl;
use valico::common::error as valico_error;
use super::query;
use model::v1::*;
use model;

const MAX_LAT: f64 = 180f64;
const MIN_LAT: f64 = -180f64;

const MAX_LON: f64 = 90f64;
const MIN_LON: f64 = -90f64;

fn render<T>(mut client: rustless::Client,
             obj: T)
             -> Result<rustless::Client, rustless::ErrorResponse>
    where T: serde::Serialize
{
    client.set_json_content_type();
    client.text(serde_json::to_string(&obj).unwrap())
}

pub struct ApiEndPoint {
    pub es_cnx_string: String,
}

impl ApiEndPoint {
    pub fn root(&self) -> rustless::Api {
        Api::build(|api| {
            api.get("", |endpoint| {
                endpoint.handle(|client, _params| {
                    let desc = EndPoint { description: "autocomplete service".to_string() };
                    render(client, desc)
                })
            });

            api.error_formatter(|error, _media| {
                let err = if error.is::<rustless::errors::Validation>() {
                    let val_err = error.downcast::<rustless::errors::Validation>().unwrap();
                    // TODO better message, we shouldn't use {:?} but access the `path`
                    // and `detail` of all errrors in val_err.reason
                    CustomError {
                        short: "validation error".to_string(),
                        long: format!("invalid arguments {:?}", val_err.reason),
                    }
                } else {
                    CustomError {
                        short: "bad_request".to_string(),
                        long: format!("bad request, error: {}", error),
                    }
                };
                let mut resp = rustless::Response::from(status::StatusCode::BadRequest,
                                                        Box::new(serde_json::to_string(&err)
                                                            .unwrap()));
                resp.set_json_content_type();
                Some(resp)
            });
            api.mount(self.v1());
        })
    }

    fn v1(&self) -> rustless::Api {
        Api::build(|api| {
            api.mount(self.status());
            api.mount(self.autocomplete());
        })
    }

    fn status(&self) -> rustless::Api {
        Api::build(|api| {
            api.get("status", |endpoint| {
                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, _params| {
                    let status = Status {
                        version: env!("CARGO_PKG_VERSION").to_string(),
                        es: cnx.to_string(),
                        status: "good".to_string(),
                    };
                    render(client, status)
                })
            });
        })
    }

    fn autocomplete(&self) -> rustless::Api {
        Api::build(|api| {
            api.post("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.opt_typed("q", json_dsl::string());
                    params.opt_typed("size", json_dsl::u64());
                    params.opt_typed("from", json_dsl::u64());
                    params.req("geometry", |geometry| {
                        geometry.coerce(json_dsl::object());
                        geometry.nest(|params| {
                            params.req("type", |geojson_type| {
                                geojson_type.coerce(json_dsl::string());
                                geojson_type.allow_values(&["Polygon".to_string()]);
                            });
                        });
                        geometry.nest(|params| {
                            params.req("coordinates", |shape| {
                                shape.coerce(json_dsl::array());
                                shape.validate_with(|val, path| {
                                    check_coordinates(val, path, "Coordinates is invalid")
                                });
                            });
                        });
                    })
                });

                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, params| {
                    let q = match params.find("q") {
                            Some(val) => val.as_str().unwrap_or(""),
                            None => "",
                        }
                        .to_string();
                    let from = match params.find("from") {
                            Some(val) => val.as_u64().unwrap_or(0),
                            None => 0,
                        };
                    let size = match params.find("size") {
                            Some(val) => val.as_u64().unwrap_or(0),
                            None => 0,
                        };
                    let geometry = params.find_path(&["geometry"]).unwrap();
                    let coordinates =
                        geometry.find_path(&["coordinates"]).unwrap().as_array().unwrap();
                    let mut shape = Vec::new();
                    for ar in coordinates[0].as_array().unwrap() {
                        // (Lat, Lon)
                        shape.push((ar.as_array().unwrap()[1].as_f64().unwrap(),
                                    ar.as_array().unwrap()[0].as_f64().unwrap()));
                    }
                    let model_autocomplete = query::autocomplete(&q, from, size, None, &cnx, Some(shape));

                    let response = model::v1::AutocompleteResponse::from(model_autocomplete);
                    render(client, response)
                })
            });
            api.get("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.req_typed("q", json_dsl::string());
                    params.opt_typed("size", json_dsl::u64());
                    params.opt_typed("from", json_dsl::u64());
                    params.opt("lon", |lon| {
                        lon.coerce(json_dsl::f64());
                        lon.validate_with(|val, path| {
                            check_bound(val, path, MIN_LON, MAX_LON, "lon is not a valid longitude")
                        });
                    });

                    params.opt("lat", |lat| {
                        lat.coerce(json_dsl::f64());
                        lat.validate_with(|val, path| {
                            check_bound(val, path, MIN_LAT, MAX_LAT, "lat is not a valid latitude")
                        });
                    });
                    params.validate_with(|val, path| {
                        // if we have a lat we should have a lon (and the opposite)
                        if let Some(obj) = val.as_object() {
                            let has_lon = obj.get("lon").is_some();
                            let has_lat = obj.get("lat").is_some();
                            if has_lon ^ has_lat {
                                Err(vec![Box::new(json_dsl::errors::WrongValue {
                                             path: path.to_string(),
                                             detail: Some("you need to provide a lon AND a lat \
                                                           if you provide one of them"
                                                 .to_string()),
                                         })])
                            } else {
                                Ok(())
                            }
                        } else {
                            unreachable!("should never happen, already checked");
                        }
                    });
                });
                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, params| {
                    let q = params.find("q").unwrap().as_str().unwrap().to_string();
                    let from = match params.find("from") {
                            Some(val) => val.as_u64().unwrap_or(0),
                            None => 0,
                        };
                    let size = match params.find("size") {
                            Some(val) => val.as_u64().unwrap_or(0),
                            None => 0,
                        };
                    let lon = params.find("lon").and_then(|p| p.as_f64());
                    let lat = params.find("lat").and_then(|p| p.as_f64());
                    // we have already checked that if there is a lon, lat
                    // is not None so we can unwrap
                    let coord = lon.and_then(|lon| {
                        Some(model::Coord {
                            lon: lon,
                            lat: lat.unwrap(),
                        })
                    });
                    let model_autocomplete = query::autocomplete(&q, from, size, coord, &cnx, None);

                    let response = model::v1::AutocompleteResponse::from(model_autocomplete);
                    render(client, response)
                })
            });
        })
    }
}

fn check_bound(val: &serde_json::Value,
               path: &str,
               min: f64,
               max: f64,
               error_msg: &str)
               -> Result<(), valico_error::ValicoErrors> {
    if let Some(lon) = val.as_f64() {
        if min <= lon && lon <= max {
            Ok(())
        } else {
            Err(vec![Box::new(json_dsl::errors::WrongValue {
                         path: path.to_string(),
                         detail: Some(error_msg.to_string()),
                     })])
        }
    } else {
        unreachable!("should never happen, already checked");
    }
}

fn check_coordinates(val: &serde_json::Value,
                     path: &str,
                     error_msg: &str)
                     -> Result<(), valico_error::ValicoErrors> {

    if !val.is_array() {
        return Err(vec![Box::new(json_dsl::errors::WrongType {
                            path: path.to_string(),
                            detail: error_msg.to_string(),
                        })]);
    }
    let array = val.as_array().unwrap();
    if array.is_empty() {
        return Err(vec![Box::new(json_dsl::errors::WrongValue {
                            path: path.to_string(),
                            detail: Some(error_msg.to_string()),
                        })]);
    }

    for arr0 in array {
        if !arr0.is_array() {
            return Err(vec![Box::new(json_dsl::errors::WrongType {
                                path: path.to_string(),
                                detail: error_msg.to_string(),
                            })]);
        }
        let arr1 = arr0.as_array().unwrap();
        if arr1.is_empty() {
            return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                path: path.to_string(),
                                detail: Some(error_msg.to_string()),
                            })]);
        }
        for arr2 in arr1 {
            if !arr2.is_array() {
                return Err(vec![Box::new(json_dsl::errors::WrongType {
                                    path: path.to_string(),
                                    detail: error_msg.to_string(),
                                })]);
            }
            let lonlat = arr2.as_array().unwrap();
            if lonlat.len() != 2 {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }

            if !(lonlat[0].is_f64() && lonlat[1].is_f64()) {
                return Err(vec![Box::new(json_dsl::errors::WrongType {
                                    path: path.to_string(),
                                    detail: error_msg.to_string(),
                                })]);
            }
            let lon = lonlat[0].as_f64().unwrap();
            let lat = lonlat[1].as_f64().unwrap();
            if !(MIN_LON <= lon && lon <= MAX_LON) {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }
            if !(MIN_LAT <= lat && lat <= MAX_LAT) {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }
        }
    }
    Ok(())
}
<commit_msg>const added<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
use rustless;
use serde;
use serde_json;
use rustless::server::status;
use rustless::{Api, Nesting};
use valico::json_dsl;
use valico::common::error as valico_error;
use super::query;
use model::v1::*;
use model;

const MAX_LAT: f64 = 180f64;
const MIN_LAT: f64 = -180f64;

const MAX_LON: f64 = 90f64;
const MIN_LON: f64 = -90f64;
const DEFAULT_SIZE: u64 = 10u64;
const DEFAULT_FROM: u64 = 0u64;

fn render<T>(mut client: rustless::Client,
             obj: T)
             -> Result<rustless::Client, rustless::ErrorResponse>
    where T: serde::Serialize
{
    client.set_json_content_type();
    client.text(serde_json::to_string(&obj).unwrap())
}

pub struct ApiEndPoint {
    pub es_cnx_string: String,
}

impl ApiEndPoint {
    pub fn root(&self) -> rustless::Api {
        Api::build(|api| {
            api.get("", |endpoint| {
                endpoint.handle(|client, _params| {
                    let desc = EndPoint { description: "autocomplete service".to_string() };
                    render(client, desc)
                })
            });

            api.error_formatter(|error, _media| {
                let err = if error.is::<rustless::errors::Validation>() {
                    let val_err = error.downcast::<rustless::errors::Validation>().unwrap();
                    // TODO better message, we shouldn't use {:?} but access the `path`
                    // and `detail` of all errrors in val_err.reason
                    CustomError {
                        short: "validation error".to_string(),
                        long: format!("invalid arguments {:?}", val_err.reason),
                    }
                } else {
                    CustomError {
                        short: "bad_request".to_string(),
                        long: format!("bad request, error: {}", error),
                    }
                };
                let mut resp = rustless::Response::from(status::StatusCode::BadRequest,
                                                        Box::new(serde_json::to_string(&err)
                                                            .unwrap()));
                resp.set_json_content_type();
                Some(resp)
            });
            api.mount(self.v1());
        })
    }

    fn v1(&self) -> rustless::Api {
        Api::build(|api| {
            api.mount(self.status());
            api.mount(self.autocomplete());
        })
    }

    fn status(&self) -> rustless::Api {
        Api::build(|api| {
            api.get("status", |endpoint| {
                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, _params| {
                    let status = Status {
                        version: env!("CARGO_PKG_VERSION").to_string(),
                        es: cnx.to_string(),
                        status: "good".to_string(),
                    };
                    render(client, status)
                })
            });
        })
    }

    fn autocomplete(&self) -> rustless::Api {
        Api::build(|api| {
            api.post("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.opt_typed("q", json_dsl::string());
                    params.opt_typed("size", json_dsl::u64());
                    params.opt_typed("from", json_dsl::u64());
                    params.req("geometry", |geometry| {
                        geometry.coerce(json_dsl::object());
                        geometry.nest(|params| {
                            params.req("type", |geojson_type| {
                                geojson_type.coerce(json_dsl::string());
                                geojson_type.allow_values(&["Polygon".to_string()]);
                            });
                        });
                        geometry.nest(|params| {
                            params.req("coordinates", |shape| {
                                shape.coerce(json_dsl::array());
                                shape.validate_with(|val, path| {
                                    check_coordinates(val, path, "Coordinates is invalid")
                                });
                            });
                        });
                    })
                });

                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, params| {
                    let q = match params.find("q") {
                            Some(val) => val.as_str().unwrap_or(""),
                            None => "",
                        }
                        .to_string();
                    let from = match params.find("from") {
                            Some(val) => val.as_u64().unwrap_or(DEFAULT_FROM),
                            None => DEFAULT_FROM,
                        };
                    let size = match params.find("size") {
                            Some(val) => val.as_u64().unwrap_or(DEFAULT_SIZE),
                            None => DEFAULT_SIZE,
                        };
                    let geometry = params.find_path(&["geometry"]).unwrap();
                    let coordinates =
                        geometry.find_path(&["coordinates"]).unwrap().as_array().unwrap();
                    let mut shape = Vec::new();
                    for ar in coordinates[0].as_array().unwrap() {
                        // (Lat, Lon)
                        shape.push((ar.as_array().unwrap()[1].as_f64().unwrap(),
                                    ar.as_array().unwrap()[0].as_f64().unwrap()));
                    }
                    let model_autocomplete = query::autocomplete(&q, from, size, None, &cnx, Some(shape));

                    let response = model::v1::AutocompleteResponse::from(model_autocomplete);
                    render(client, response)
                })
            });
            api.get("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.req_typed("q", json_dsl::string());
                    params.opt_typed("size", json_dsl::u64());
                    params.opt_typed("from", json_dsl::u64());
                    params.opt("lon", |lon| {
                        lon.coerce(json_dsl::f64());
                        lon.validate_with(|val, path| {
                            check_bound(val, path, MIN_LON, MAX_LON, "lon is not a valid longitude")
                        });
                    });

                    params.opt("lat", |lat| {
                        lat.coerce(json_dsl::f64());
                        lat.validate_with(|val, path| {
                            check_bound(val, path, MIN_LAT, MAX_LAT, "lat is not a valid latitude")
                        });
                    });
                    params.validate_with(|val, path| {
                        // if we have a lat we should have a lon (and the opposite)
                        if let Some(obj) = val.as_object() {
                            let has_lon = obj.get("lon").is_some();
                            let has_lat = obj.get("lat").is_some();
                            if has_lon ^ has_lat {
                                Err(vec![Box::new(json_dsl::errors::WrongValue {
                                             path: path.to_string(),
                                             detail: Some("you need to provide a lon AND a lat \
                                                           if you provide one of them"
                                                 .to_string()),
                                         })])
                            } else {
                                Ok(())
                            }
                        } else {
                            unreachable!("should never happen, already checked");
                        }
                    });
                });
                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, params| {
                    let q = params.find("q").unwrap().as_str().unwrap().to_string();
                    let from = match params.find("from") {
                            Some(val) => val.as_u64().unwrap_or(DEFAULT_FROM),
                            None => DEFAULT_FROM,
                        };
                    let size = match params.find("size") {
                            Some(val) => val.as_u64().unwrap_or(DEFAULT_SIZE),
                            None => DEFAULT_SIZE,
                        };
                    let lon = params.find("lon").and_then(|p| p.as_f64());
                    let lat = params.find("lat").and_then(|p| p.as_f64());
                    // we have already checked that if there is a lon, lat
                    // is not None so we can unwrap
                    let coord = lon.and_then(|lon| {
                        Some(model::Coord {
                            lon: lon,
                            lat: lat.unwrap(),
                        })
                    });
                    let model_autocomplete = query::autocomplete(&q, from, size, coord, &cnx, None);

                    let response = model::v1::AutocompleteResponse::from(model_autocomplete);
                    render(client, response)
                })
            });
        })
    }
}

fn check_bound(val: &serde_json::Value,
               path: &str,
               min: f64,
               max: f64,
               error_msg: &str)
               -> Result<(), valico_error::ValicoErrors> {
    if let Some(lon) = val.as_f64() {
        if min <= lon && lon <= max {
            Ok(())
        } else {
            Err(vec![Box::new(json_dsl::errors::WrongValue {
                         path: path.to_string(),
                         detail: Some(error_msg.to_string()),
                     })])
        }
    } else {
        unreachable!("should never happen, already checked");
    }
}

fn check_coordinates(val: &serde_json::Value,
                     path: &str,
                     error_msg: &str)
                     -> Result<(), valico_error::ValicoErrors> {

    if !val.is_array() {
        return Err(vec![Box::new(json_dsl::errors::WrongType {
                            path: path.to_string(),
                            detail: error_msg.to_string(),
                        })]);
    }
    let array = val.as_array().unwrap();
    if array.is_empty() {
        return Err(vec![Box::new(json_dsl::errors::WrongValue {
                            path: path.to_string(),
                            detail: Some(error_msg.to_string()),
                        })]);
    }

    for arr0 in array {
        if !arr0.is_array() {
            return Err(vec![Box::new(json_dsl::errors::WrongType {
                                path: path.to_string(),
                                detail: error_msg.to_string(),
                            })]);
        }
        let arr1 = arr0.as_array().unwrap();
        if arr1.is_empty() {
            return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                path: path.to_string(),
                                detail: Some(error_msg.to_string()),
                            })]);
        }
        for arr2 in arr1 {
            if !arr2.is_array() {
                return Err(vec![Box::new(json_dsl::errors::WrongType {
                                    path: path.to_string(),
                                    detail: error_msg.to_string(),
                                })]);
            }
            let lonlat = arr2.as_array().unwrap();
            if lonlat.len() != 2 {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }

            if !(lonlat[0].is_f64() && lonlat[1].is_f64()) {
                return Err(vec![Box::new(json_dsl::errors::WrongType {
                                    path: path.to_string(),
                                    detail: error_msg.to_string(),
                                })]);
            }
            let lon = lonlat[0].as_f64().unwrap();
            let lat = lonlat[1].as_f64().unwrap();
            if !(MIN_LON <= lon && lon <= MAX_LON) {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }
            if !(MIN_LAT <= lat && lat <= MAX_LAT) {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>extern crate curl;

use std::process;
use curl::http;

fn main() {
    let url = "https://raw.githubusercontent.com/clux/muslrust/master/test/curlcrate/src/main.rs";

    let resp = http::handle().get(url).exec().unwrap();
    let body = String::from_utf8_lossy(resp.get_body());
    println!("{}", body);
    process::exit(if resp.get_code() == 200 { 0 } else { 1 });
    // NB: This is a quine
}
<commit_msg>fix curl compile errors - the library was rewritten for 1.9<commit_after>extern crate curl;

use std::process;
use std::io::{stdout, Write};
use curl::easy::Easy;

fn main() {
    let url = "https://raw.githubusercontent.com/clux/muslrust/master/test/curlcrate/src/main.rs";

    let mut easy = Easy::new();
    easy.fail_on_error(true).unwrap();
    easy.url(url).unwrap();
    easy.write_function(|data| {
        Ok(stdout().write(data).unwrap())
    }).unwrap();
    easy.perform().unwrap_or_else(|e| {
      println!("Failed: {}", e);
      process::exit(1);
    });
    // NB: This is a quine
}
<|endoftext|>


<commit_before>//! Function System
//!
//! In Tokamak, all arithmetic operators, predicates, and functions are regarded as
//! a kind of functions. For example, the arithmetic operator plus (+) for i32 values
//! can be represented as a triple ("+", [i32, i32], FuncKind::Scalar).
//!

use std::cmp::Ordering;
use std::rc::Rc;
use std::cell::RefCell;

use err::{Result, Void, void_ok};
use plugin::{PluginManager, TypeRegistry};
use rows::{MiniPage,MiniPageWriter};
use types::Ty;

#[derive(Eq, Copy, Clone, PartialEq, PartialOrd, Ord)]
pub enum FnKind
{
  Scalar,
  Aggregation,
  Window
}

pub type NoArgFn   = Rc<Fn(&mut MiniPageWriter, usize) -> Void>;
pub type UnaryFn   = Rc<Fn(&MiniPage, &mut MiniPageWriter, usize) -> Void>;
pub type BinaryFn  = Rc<Fn(&MiniPage, &MiniPage, &mut MiniPageWriter, usize) -> Void>;
pub type TrinityFn = Rc<Fn(&MiniPage, &MiniPage, &MiniPage, &mut MiniPageWriter, usize) -> Void>;

#[derive(Clone)]
pub struct InvokeAction
{
  pub ret_type   : Ty,
  pub method     : InvokeMethod
}

impl InvokeAction
{
	pub fn new(ret_type: Ty, method: InvokeMethod) -> InvokeAction
	{
		InvokeAction {
			ret_type: ret_type,
			method  : method
		}
	}

	pub fn new_noarg(ret_type: Ty, f: NoArgFn) -> InvokeAction {
		InvokeAction {
			ret_type: ret_type,
			method  : InvokeMethod::NoArgOp(f)
		}
	}
}

#[derive(Clone)]
pub enum InvokeMethod
{
  NoArgOp   (NoArgFn),
  UnaryOp   (UnaryFn),
  BinaryOp  (BinaryFn),
  TrinityOp (TrinityFn)
}

#[derive(Clone)]
pub struct FuncSignature
{
  // Function Name
  name     : String,
  // Function argument data types
  arg_types: Vec<Ty>,
  // Function kind
  fn_kind  : FnKind
}

impl FuncSignature
{
  pub fn new(name: String, arg_types: Vec<Ty>, fn_kind: FnKind) -> FuncSignature
  {
    FuncSignature {
      name     : name,
      arg_types: arg_types,
      fn_kind  : fn_kind
    }
  }
}

impl Eq for FuncSignature {}

// TODO - compare other attributes
impl PartialEq for FuncSignature {
  fn eq(&self, other: &FuncSignature) -> bool {
    &self.name     == &other.name &&
    self.arg_types == other.arg_types &&
    self.fn_kind   == other.fn_kind
  }
}

// TODO - compare other attributes
impl PartialOrd for FuncSignature
{
   fn partial_cmp(&self, other: &FuncSignature) -> Option<Ordering> {
     self.name.partial_cmp(&other.name)
   }

   fn lt(&self, other: &FuncSignature) -> bool { self.name < other.name }
   fn le(&self, other: &FuncSignature) -> bool { self.name <= other.name }
   fn gt(&self, other: &FuncSignature) -> bool { self.name > other.name }
   fn ge(&self, other: &FuncSignature) -> bool { self.name <= other.name }
}

// TODO - compare other attributes
impl Ord for FuncSignature {
  fn cmp(&self, other: &FuncSignature) -> Ordering {
    self.name.cmp(&other.name)
  }
}<commit_msg>Remove the manual implementation of Eq, PartialEq for FuncSignature.<commit_after>//! Function System
//!
//! In Tokamak, all arithmetic operators, predicates, and functions are regarded as
//! a kind of functions. For example, the arithmetic operator plus (+) for i32 values
//! can be represented as a triple ("+", [i32, i32], FuncKind::Scalar).
//!

use std::cmp::Ordering;
use std::rc::Rc;
use std::cell::RefCell;

use err::{Result, Void, void_ok};
use plugin::{PluginManager, TypeRegistry};
use rows::{MiniPage,MiniPageWriter};
use types::Ty;

#[derive(Eq, Copy, Clone, PartialEq, PartialOrd, Ord)]
pub enum FnKind
{
  Scalar,
  Aggregation,
  Window
}

pub type NoArgFn   = Rc<Fn(&mut MiniPageWriter, usize) -> Void>;
pub type UnaryFn   = Rc<Fn(&MiniPage, &mut MiniPageWriter, usize) -> Void>;
pub type BinaryFn  = Rc<Fn(&MiniPage, &MiniPage, &mut MiniPageWriter, usize) -> Void>;
pub type TrinityFn = Rc<Fn(&MiniPage, &MiniPage, &MiniPage, &mut MiniPageWriter, usize) -> Void>;

#[derive(Clone)]
pub struct InvokeAction
{
  pub ret_type   : Ty,
  pub method     : InvokeMethod
}

impl InvokeAction
{
	pub fn new(ret_type: Ty, method: InvokeMethod) -> InvokeAction
	{
		InvokeAction {
			ret_type: ret_type,
			method  : method
		}
	}

	pub fn new_noarg(ret_type: Ty, f: NoArgFn) -> InvokeAction {
		InvokeAction {
			ret_type: ret_type,
			method  : InvokeMethod::NoArgOp(f)
		}
	}
}

#[derive(Clone)]
pub enum InvokeMethod
{
  NoArgOp   (NoArgFn),
  UnaryOp   (UnaryFn),
  BinaryOp  (BinaryFn),
  TrinityOp (TrinityFn)
}

#[derive(Clone, Eq, PartialEq)]
pub struct FuncSignature
{
  // Function Name
  name     : String,
  // Function argument data types
  arg_types: Vec<Ty>,
  // Function kind
  fn_kind  : FnKind
}

impl FuncSignature
{
  pub fn new(name: String, arg_types: Vec<Ty>, fn_kind: FnKind) -> FuncSignature
  {
    FuncSignature {
      name     : name,
      arg_types: arg_types,
      fn_kind  : fn_kind
    }
  }
}

// TODO - compare other attributes
impl PartialOrd for FuncSignature
{
   fn partial_cmp(&self, other: &FuncSignature) -> Option<Ordering> {
     self.name.partial_cmp(&other.name)
   }

   fn lt(&self, other: &FuncSignature) -> bool { self.name < other.name }
   fn le(&self, other: &FuncSignature) -> bool { self.name <= other.name }
   fn gt(&self, other: &FuncSignature) -> bool { self.name > other.name }
   fn ge(&self, other: &FuncSignature) -> bool { self.name <= other.name }
}

// TODO - compare other attributes
impl Ord for FuncSignature {
  fn cmp(&self, other: &FuncSignature) -> Ordering {
    self.name.cmp(&other.name)
  }
}<|endoftext|>