<commit_before>// aux-build:arc_wake.rs
// edition:2018
// run-pass

#![allow(unused_variables)]
#![feature(async_await, await_macro, futures_api)]

extern crate arc_wake;

use arc_wake::ArcWake;
use std::cell::RefCell;
use std::future::Future;
use std::marker::PhantomData;
use std::sync::Arc;
use std::task::Context;

struct EmptyWaker;

impl ArcWake for EmptyWaker {
    fn wake(self: Arc<Self>) {}
}

#[derive(Debug, Eq, PartialEq)]
enum DropOrder {
    Function,
    Val(&'static str),
}

struct D(&'static str, Arc<RefCell<Vec<DropOrder>>>);

impl Drop for D {
    fn drop(&mut self) {
        self.1.borrow_mut().push(DropOrder::Val(self.0));
    }
}

async fn foo(x: D, _y: D) {
    x.1.borrow_mut().push(DropOrder::Function);
}

async fn bar(x: D, _: D) {
    x.1.borrow_mut().push(DropOrder::Function);
}

async fn baz((x, _): (D, D)) {
    x.1.borrow_mut().push(DropOrder::Function);
}

async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
    x.1.borrow_mut().push(DropOrder::Function);
}

struct Foo;

impl Foo {
    async fn foo(x: D, _y: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    async fn bar(x: D, _: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    async fn baz((x, _): (D, D)) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }
}

struct Bar<'a>(PhantomData<&'a ()>);

impl<'a> Bar<'a> {
    async fn foo(&'a self, x: D, _y: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    async fn bar(&'a self, x: D, _: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    async fn baz(&'a self, (x, _): (D, D)) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    async fn foobar(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }
}

fn main() {
    let empty = Arc::new(EmptyWaker);
    let waker = ArcWake::into_waker(empty);
    let mut cx = Context::from_waker(&waker);

    use DropOrder::*;

    // Currently, the `bar` and `foobar` tests do not output the same order as the equivalent
    // non-async functions. This is because the drop order of captured variables doesn't match the
    // drop order of arguments in a function.

    // Free functions

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(foo(D("x", af.clone()), D("_y", af.clone())));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[Function, Val("_y"), Val("x")]);

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(bar(D("x", af.clone()), D("_", af.clone())));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[Function, Val("x"), Val("_")]);

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(baz((D("x", af.clone()), D("_", af.clone()))));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[Function, Val("x"), Val("_")]);

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(foobar(
        D("x", af.clone()),
        (D("a", af.clone()), D("_", af.clone()), D("_c", af.clone())),
        D("_", af.clone()),
        D("_y", af.clone()),
    ));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[
       Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_"),
    ]);

    // Methods w/out self

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(Foo::foo(D("x", af.clone()), D("_y", af.clone())));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[Function, Val("_y"), Val("x")]);

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(Foo::bar(D("x", af.clone()), D("_", af.clone())));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[Function, Val("x"), Val("_")]);

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(Foo::baz((D("x", af.clone()), D("_", af.clone()))));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[Function, Val("x"), Val("_")]);

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(Foo::foobar(
        D("x", af.clone()),
        (D("a", af.clone()), D("_", af.clone()), D("_c", af.clone())),
        D("_", af.clone()),
        D("_y", af.clone()),
    ));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[
       Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_"),
    ]);

    // Methods

    let b = Bar(Default::default());

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(b.foo(D("x", af.clone()), D("_y", af.clone())));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[Function, Val("_y"), Val("x")]);

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(b.bar(D("x", af.clone()), D("_", af.clone())));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[Function, Val("x"), Val("_")]);

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(b.baz((D("x", af.clone()), D("_", af.clone()))));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[Function, Val("x"), Val("_")]);

    let af = Arc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(b.foobar(
        D("x", af.clone()),
        (D("a", af.clone()), D("_", af.clone()), D("_c", af.clone())),
        D("_", af.clone()),
        D("_y", af.clone()),
    ));
    let _ = fut.as_mut().poll(&mut cx);
    assert_eq!(*af.borrow(), &[
       Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_"),
    ]);
}
<commit_msg>Reduce noise and document test case.<commit_after>// aux-build:arc_wake.rs
// edition:2018
// run-pass

#![allow(unused_variables)]
#![feature(async_await, await_macro, futures_api)]

extern crate arc_wake;

use arc_wake::ArcWake;
use std::cell::RefCell;
use std::future::Future;
use std::marker::PhantomData;
use std::sync::Arc;
use std::rc::Rc;
use std::task::Context;

struct EmptyWaker;

impl ArcWake for EmptyWaker {
    fn wake(self: Arc<Self>) {}
}

#[derive(Debug, Eq, PartialEq)]
enum DropOrder {
    Function,
    Val(&'static str),
}

type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;

struct D(&'static str, DropOrderListPtr);

impl Drop for D {
    fn drop(&mut self) {
        self.1.borrow_mut().push(DropOrder::Val(self.0));
    }
}

/// Check that unused bindings are dropped after the function is polled.
async fn foo(x: D, _y: D) {
    x.1.borrow_mut().push(DropOrder::Function);
}

/// Check that underscore patterns are dropped after the function is polled.
async fn bar(x: D, _: D) {
    x.1.borrow_mut().push(DropOrder::Function);
}

/// Check that underscore patterns within more complex patterns are dropped after the function
/// is polled.
async fn baz((x, _): (D, D)) {
    x.1.borrow_mut().push(DropOrder::Function);
}

/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
/// after the function is polled.
async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
    x.1.borrow_mut().push(DropOrder::Function);
}

struct Foo;

impl Foo {
    /// Check that unused bindings are dropped after the method is polled.
    async fn foo(x: D, _y: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    /// Check that underscore patterns are dropped after the method is polled.
    async fn bar(x: D, _: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    /// Check that underscore patterns within more complex patterns are dropped after the method
    /// is polled.
    async fn baz((x, _): (D, D)) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    /// Check that underscore and unused bindings within and outwith more complex patterns are
    /// dropped after the method is polled.
    async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }
}

struct Bar<'a>(PhantomData<&'a ()>);

impl<'a> Bar<'a> {
    /// Check that unused bindings are dropped after the method with self is polled.
    async fn foo(&'a self, x: D, _y: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    /// Check that underscore patterns are dropped after the method with self is polled.
    async fn bar(&'a self, x: D, _: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    /// Check that underscore patterns within more complex patterns are dropped after the method
    /// with self is polled.
    async fn baz(&'a self, (x, _): (D, D)) {
        x.1.borrow_mut().push(DropOrder::Function);
    }

    /// Check that underscore and unused bindings within and outwith more complex patterns are
    /// dropped after the method with self is polled.
    async fn foobar(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
        x.1.borrow_mut().push(DropOrder::Function);
    }
}

fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
    f: impl FnOnce(DropOrderListPtr) -> Fut,
    expected_order: &[DropOrder],
) {
    let empty = Arc::new(EmptyWaker);
    let waker = ArcWake::into_waker(empty);
    let mut cx = Context::from_waker(&waker);

    let actual_order = Rc::new(RefCell::new(Vec::new()));
    let mut fut = Box::pin(f(actual_order.clone()));
    let _ = fut.as_mut().poll(&mut cx);

    assert_eq!(*actual_order.borrow(), expected_order);
}

fn main() {
    use DropOrder::*;

    // At time of writing (23/04/19), the `bar` and `foobar` tests do not output the same order as
    // the equivalent non-async functions. This is because the drop order of captured variables
    // doesn't match the drop order of arguments in a function.

    // Free functions (see doc comment on function for what it tests).
    assert_drop_order_after_poll(|l| foo(D("x", l.clone()), D("_y", l.clone())),
                                 &[Function, Val("_y"), Val("x")]);
    assert_drop_order_after_poll(|l| bar(D("x", l.clone()), D("_", l.clone())),
                                 &[Function, Val("x"), Val("_")]);
    assert_drop_order_after_poll(|l| baz((D("x", l.clone()), D("_", l.clone()))),
                                 &[Function, Val("x"), Val("_")]);
    assert_drop_order_after_poll(|l| {
        foobar(
            D("x", l.clone()),
            (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
            D("_", l.clone()),
            D("_y", l.clone()),
        )
    }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);

    // Methods w/out self (see doc comment on function for what it tests).
    assert_drop_order_after_poll(|l| Foo::foo(D("x", l.clone()), D("_y", l.clone())),
                                 &[Function, Val("_y"), Val("x")]);
    assert_drop_order_after_poll(|l| Foo::bar(D("x", l.clone()), D("_", l.clone())),
                                 &[Function, Val("x"), Val("_")]);
    assert_drop_order_after_poll(|l| Foo::baz((D("x", l.clone()), D("_", l.clone()))),
                                 &[Function, Val("x"), Val("_")]);
    assert_drop_order_after_poll(|l| {
        Foo::foobar(
            D("x", l.clone()),
            (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
            D("_", l.clone()),
            D("_y", l.clone()),
        )
    }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);

    // Methods (see doc comment on function for what it tests).
    let b = Bar(Default::default());
    assert_drop_order_after_poll(|l| b.foo(D("x", l.clone()), D("_y", l.clone())),
                                 &[Function, Val("_y"), Val("x")]);
    assert_drop_order_after_poll(|l| b.bar(D("x", l.clone()), D("_", l.clone())),
                                 &[Function, Val("x"), Val("_")]);
    assert_drop_order_after_poll(|l| b.baz((D("x", l.clone()), D("_", l.clone()))),
                                 &[Function, Val("x"), Val("_")]);
    assert_drop_order_after_poll(|l| {
        b.foobar(
            D("x", l.clone()),
            (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
            D("_", l.clone()),
            D("_y", l.clone()),
        )
    }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);
}
<|endoftext|>


<commit_before>extern crate serde_yaml;

use ::subtitles::metainfo::MetaInfo;
use std::path::{Path, PathBuf};

#[derive(Debug,Deserialize,Serialize,Clone)]
pub struct VideoMeta {
    pub video_path: PathBuf,
    pub json_path: Option<PathBuf>,
    pub lyr_path: Option<PathBuf>,
    pub frm_path: Option<PathBuf>,
    #[serde(default)]
    pub meta_info: MetaInfo,
}

impl VideoMeta {
    pub fn from_yaml<P: AsRef<Path>>(path: P) -> Result<VideoMeta, String> {
        let path = path.as_ref();
        match ::std::fs::File::open(path) {
            Ok(yaml_file) => {
                serde_yaml::from_reader(yaml_file)
                    .map_err(|err| format!("Error when parsing .yaml file : {}", err))
            }
            Err(e) => {
                error!("Error when loading yaml file '{}' : {}", path.display(), e);
                Err(format!("Error when loading yaml file '{}'; file could not be opened",
                            path.display()))
            }
        }
    }

    /// both .yaml or .mp4/.avi/... should work
    pub fn new<P: AsRef<Path>>(path: P) -> Result<VideoMeta, String> {
        let path = path.as_ref();
        match path.extension() {
            None => {
                Err(format!("Error when trying to load file '{}', file has no extension",
                            path.display()))
            }
            Some(s) if s == "yaml" => VideoMeta::from_yaml(path).map(|v_m| v_m.fix_paths(path)),
            Some(s) if s == "avi" || s == "mp4" => {
                let yaml_file: PathBuf = path.with_extension("yaml");
                if yaml_file.exists() {
                    VideoMeta::from_yaml(yaml_file).map(|v_m| v_m.fix_paths(path))
                } else {
                    Ok(VideoMeta {
                        video_path: PathBuf::from(path),
                        lyr_path: None,
                        frm_path: None,
                        json_path: None,
                        meta_info: MetaInfo::default(),
                    })
                }
            }
            Some(ext) => {
                Err(format!("Unrecognized extension '{}'",
                            ext.to_str().unwrap_or("[NON-UTF-8 SEQ]")))
            }
        }
    }

    // maps the paths in video meta so they have paths
    // absolute or relative to cwd
    pub fn fix_paths<P: AsRef<Path>>(mut self, original: P) -> VideoMeta {
        // applying join with an absolute directory overrides the origina one
        // which applies perfectly to our use case
        fn fix_path<P: AsRef<Path>>(original: P, target: &mut PathBuf) {
            // TODO remove .unwrap (so it doesnt crash for a single wrong file)
            *target = original.as_ref().parent().unwrap().join(&target);
        }

        fn fix_option_path<P: AsRef<Path>>(original: P, target: &mut Option<PathBuf>) {
            match *target {
                None => {}
                Some(ref mut target) => {
                    fix_path(original, target);
                }
            }
        }
        fix_path(&original, &mut self.video_path);
        fix_option_path(&original, &mut self.json_path);
        fix_option_path(&original, &mut self.frm_path);
        fix_option_path(&original, &mut self.lyr_path);
        self
    }

    // TODO return a &Path or &'a Path or whatever
    // same for the 2 under
    pub fn json_path(&self) -> PathBuf {
        match self.json_path {
            None => self.video_path.with_extension("json"),
            Some(ref path) => path.clone(),
        }
    }

    pub fn lyr_path(&self) -> PathBuf {
        match self.lyr_path {
            None => self.video_path.with_extension("lyr"),
            Some(ref path) => path.clone(),
        }
    }

    pub fn frm_path(&self) -> PathBuf {
        match self.frm_path {
            None => self.video_path.with_extension("frm"),
            Some(ref path) => path.clone(),
        }
    }
}
<commit_msg>webm support<commit_after>extern crate serde_yaml;

use ::subtitles::metainfo::MetaInfo;
use std::path::{Path, PathBuf};

#[derive(Debug,Deserialize,Serialize,Clone)]
pub struct VideoMeta {
    pub video_path: PathBuf,
    pub json_path: Option<PathBuf>,
    pub lyr_path: Option<PathBuf>,
    pub frm_path: Option<PathBuf>,
    #[serde(default)]
    pub meta_info: MetaInfo,
}

impl VideoMeta {
    pub fn from_yaml<P: AsRef<Path>>(path: P) -> Result<VideoMeta, String> {
        let path = path.as_ref();
        match ::std::fs::File::open(path) {
            Ok(yaml_file) => {
                serde_yaml::from_reader(yaml_file)
                    .map_err(|err| format!("Error when parsing .yaml file : {}", err))
            }
            Err(e) => {
                error!("Error when loading yaml file '{}' : {}", path.display(), e);
                Err(format!("Error when loading yaml file '{}'; file could not be opened",
                            path.display()))
            }
        }
    }

    /// both .yaml or .mp4/.avi/... should work
    pub fn new<P: AsRef<Path>>(path: P) -> Result<VideoMeta, String> {
        let path = path.as_ref();
        match path.extension() {
            None => {
                Err(format!("Error when trying to load file '{}', file has no extension",
                            path.display()))
            }
            Some(s) if s == "yaml" => VideoMeta::from_yaml(path).map(|v_m| v_m.fix_paths(path)),
            Some(s) if s == "avi" || s == "mp4" || s == "webm" => {
                let yaml_file: PathBuf = path.with_extension("yaml");
                if yaml_file.exists() {
                    VideoMeta::from_yaml(yaml_file).map(|v_m| v_m.fix_paths(path))
                } else {
                    Ok(VideoMeta {
                        video_path: PathBuf::from(path),
                        lyr_path: None,
                        frm_path: None,
                        json_path: None,
                        meta_info: MetaInfo::default(),
                    })
                }
            }
            Some(ext) => {
                Err(format!("Unrecognized extension '{}'",
                            ext.to_str().unwrap_or("[NON-UTF-8 SEQ]")))
            }
        }
    }

    // maps the paths in video meta so they have paths
    // absolute or relative to cwd
    pub fn fix_paths<P: AsRef<Path>>(mut self, original: P) -> VideoMeta {
        // applying join with an absolute directory overrides the origina one
        // which applies perfectly to our use case
        fn fix_path<P: AsRef<Path>>(original: P, target: &mut PathBuf) {
            // TODO remove .unwrap (so it doesnt crash for a single wrong file)
            *target = original.as_ref().parent().unwrap().join(&target);
        }

        fn fix_option_path<P: AsRef<Path>>(original: P, target: &mut Option<PathBuf>) {
            match *target {
                None => {}
                Some(ref mut target) => {
                    fix_path(original, target);
                }
            }
        }
        fix_path(&original, &mut self.video_path);
        fix_option_path(&original, &mut self.json_path);
        fix_option_path(&original, &mut self.frm_path);
        fix_option_path(&original, &mut self.lyr_path);
        self
    }

    // TODO return a &Path or &'a Path or whatever
    // same for the 2 under
    pub fn json_path(&self) -> PathBuf {
        match self.json_path {
            None => self.video_path.with_extension("json"),
            Some(ref path) => path.clone(),
        }
    }

    pub fn lyr_path(&self) -> PathBuf {
        match self.lyr_path {
            None => self.video_path.with_extension("lyr"),
            Some(ref path) => path.clone(),
        }
    }

    pub fn frm_path(&self) -> PathBuf {
        match self.frm_path {
            None => self.video_path.with_extension("frm"),
            Some(ref path) => path.clone(),
        }
    }
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo            <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use std::cmp::min;
use std::mem::swap;

pub fn gcd(mut u: u64, mut v: u64) -> u64 {
    // Stein's binary GCD algorithm
    // Base cases: gcd(n, 0) = gcd(0, n) = n
    if u == 0 {
        return v;
    } else if v == 0 {
        return u;
    }

    // gcd(2ⁱ u, 2ʲ v) = 2ᵏ gcd(u, v) with u, v odd and k = min(i, j)
    // 2ᵏ is the greatest power of two that divides both u and v
    let k = {
        let i = u.trailing_zeros();
        let j = v.trailing_zeros();
        u >>= i;
        v >>= j;
        min(i, j)
    };

    loop {
        // Loop invariant: u and v are odd
        debug_assert!(u % 2 == 1, "u = {} is even", u);
        debug_assert!(v % 2 == 1, "v = {} is even", v);

        // gcd(u, v) = gcd(|u - v|, min(u, v))
        if u > v {
            swap(&mut u, &mut v);
        }
        v -= u;

        if v == 0 {
            // Reached the base case; gcd is 2ᵏ u
            return u << k;
        }

        // gcd(u, 2ʲ v) = gcd(u, v) as u is odd
        v >>= v.trailing_zeros();
    }
}

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

    quickcheck! {
        fn euclidean(a: u64, b: u64) -> bool {
            // Test against the Euclidean algorithm
            let g = {
                let (mut a, mut b) = (a, b);
                while b > 0 {
                    a %= b;
                    swap(&mut a, &mut b);
                }
                a
            };
            gcd(a, b) == g
        }

        fn one(a: u64) -> bool {
            gcd(1, a) == 1
        }

        fn zero(a: u64) -> bool {
            gcd(0, a) == a
        }

        fn divisor(a: u64, b: u64) -> bool {
            // Test that gcd(a, b) divides a and b
            let g = gcd(a, b);
            (g != 0 && a % g == 0 && b % g == 0) || (g == 0 && a == 0 && b == 0)
        }

        fn commutative(a: u64, b: u64) -> bool {
            gcd(a, b) == gcd(b, a)
        }

        fn associative(a: u64, b: u64, c: u64) -> bool {
            gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)
        }

        fn scalar_mult(a: u64, b: u64, k: u64) -> bool {
            gcd(k * a, k * b) == k * gcd(a, b)
        }

        fn multiplicative(a: u64, b: u64, c: u64) -> bool {
            // gcd(ab, c) = gcd(a, c) gcd(b, c) when a and b coprime
            gcd(a, b) != 1 || gcd(a * b, c) == gcd(a, c) * gcd(b, c)
        }

        fn linearity(a: u64, b: u64, k: u64) -> bool {
            gcd(a + k * b, b) == gcd(a, b)
        }
    }
}
<commit_msg>tests ~ (sub-crate factor) refactor divisor() test for improved readability<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo            <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use std::cmp::min;
use std::mem::swap;

pub fn gcd(mut u: u64, mut v: u64) -> u64 {
    // Stein's binary GCD algorithm
    // Base cases: gcd(n, 0) = gcd(0, n) = n
    if u == 0 {
        return v;
    } else if v == 0 {
        return u;
    }

    // gcd(2ⁱ u, 2ʲ v) = 2ᵏ gcd(u, v) with u, v odd and k = min(i, j)
    // 2ᵏ is the greatest power of two that divides both u and v
    let k = {
        let i = u.trailing_zeros();
        let j = v.trailing_zeros();
        u >>= i;
        v >>= j;
        min(i, j)
    };

    loop {
        // Loop invariant: u and v are odd
        debug_assert!(u % 2 == 1, "u = {} is even", u);
        debug_assert!(v % 2 == 1, "v = {} is even", v);

        // gcd(u, v) = gcd(|u - v|, min(u, v))
        if u > v {
            swap(&mut u, &mut v);
        }
        v -= u;

        if v == 0 {
            // Reached the base case; gcd is 2ᵏ u
            return u << k;
        }

        // gcd(u, 2ʲ v) = gcd(u, v) as u is odd
        v >>= v.trailing_zeros();
    }
}

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

    quickcheck! {
        fn euclidean(a: u64, b: u64) -> bool {
            // Test against the Euclidean algorithm
            let g = {
                let (mut a, mut b) = (a, b);
                while b > 0 {
                    a %= b;
                    swap(&mut a, &mut b);
                }
                a
            };
            gcd(a, b) == g
        }

        fn one(a: u64) -> bool {
            gcd(1, a) == 1
        }

        fn zero(a: u64) -> bool {
            gcd(0, a) == a
        }

        fn divisor(a: u64, b: u64) -> bool {
            // Test that gcd(a, b) divides a and b
            let g = gcd(a, b);
            if g != 0 {
                a % g == 0 && b % g == 0
            } else {
                a == 0 && b == 0 // for g == 0
            }
        }

        fn commutative(a: u64, b: u64) -> bool {
            gcd(a, b) == gcd(b, a)
        }

        fn associative(a: u64, b: u64, c: u64) -> bool {
            gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)
        }

        fn scalar_mult(a: u64, b: u64, k: u64) -> bool {
            gcd(k * a, k * b) == k * gcd(a, b)
        }

        fn multiplicative(a: u64, b: u64, c: u64) -> bool {
            // gcd(ab, c) = gcd(a, c) gcd(b, c) when a and b coprime
            gcd(a, b) != 1 || gcd(a * b, c) == gcd(a, c) * gcd(b, c)
        }

        fn linearity(a: u64, b: u64, k: u64) -> bool {
            gcd(a + k * b, b) == gcd(a, b)
        }
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;

use std::borrow::Cow::Owned;
use itertools::Itertools;

use liquid;
use liquid::Token::{self, Identifier};
use liquid::lexer::Element::{self, Expression, Tag, Raw};

use syntect::parsing::{SyntaxDefinition, SyntaxSet};
use syntect::highlighting::{ThemeSet, Theme};
use syntect::html::{IncludeBackground, highlighted_snippet_for_string, styles_to_coloured_html,
                    start_coloured_html_snippet};
use syntect::easy::HighlightLines;

use pulldown_cmark as cmark;
use pulldown_cmark::Event::{self, Start, End, Text, Html};

use error;

struct Setup {
    syntax_set: SyntaxSet,
    theme_set: ThemeSet,
}

unsafe impl Send for Setup {}
unsafe impl Sync for Setup {}

lazy_static!{
    static ref SETUP: Setup = Setup {
        syntax_set: SyntaxSet::load_defaults_newlines(),
        theme_set: ThemeSet::load_defaults()
    };
}

pub fn has_syntax_theme(name: &str) -> error::Result<bool> {
    return Ok(SETUP.theme_set.themes.contains_key(name));
}

pub fn list_syntax_themes<'a>() -> Vec<&'a String> {
    return SETUP.theme_set.themes.keys().collect::<Vec<_>>();
}

pub fn list_syntaxes<'a>() -> Vec<String> {
    fn definition_to_string(sd: &SyntaxDefinition) -> String {
        let extensions = sd.file_extensions.iter().join(&", ".to_owned());
        format!("{} [{}]", sd.name, extensions)
    }

    let mut syntaxes = SETUP
        .syntax_set
        .syntaxes()
        .iter()
        .map(definition_to_string)
        .collect::<Vec<_>>();

    // sort alphabetically with insensitive ascii case
    syntaxes.sort_by_key(|a| (a as &str).to_ascii_lowercase());

    return syntaxes;
}

struct CodeBlock {
    lang: Option<String>,
    code: String,
    theme: Theme,
}

impl liquid::Renderable for CodeBlock {
    fn render(&self, _: &mut liquid::Context) -> Result<Option<String>, liquid::Error> {
        let syntax = match self.lang {
                Some(ref lang) => SETUP.syntax_set.find_syntax_by_token(lang),
                _ => None,
            }
            .unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text());

        Ok(Some(highlighted_snippet_for_string(&self.code, syntax, &self.theme)))
    }
}

pub fn initialize_codeblock(arguments: &[Token],
                            tokens: &[Element],
                            theme_name: &str)
                            -> Result<Box<liquid::Renderable>, liquid::Error> {
    let content = tokens
        .iter()
        .fold("".to_owned(), |a, b| {
            match *b {
                    Expression(_, ref text) |
                    Tag(_, ref text) |
                    Raw(ref text) => text,
                }
                .to_owned() + &a
        });

    let lang = match arguments.iter().next() {
        Some(&Identifier(ref x)) => Some(x.clone()),
        _ => None,
    };

    Ok(Box::new(CodeBlock {
                    code: content,
                    lang: lang,
                    theme: SETUP.theme_set.themes[theme_name].clone(),
                }))
}

pub struct DecoratedParser<'a> {
    h: Option<HighlightLines<'a>>,
    parser: cmark::Parser<'a>,
    theme: &'a Theme,
}

impl<'a> DecoratedParser<'a> {
    pub fn new(parser: cmark::Parser<'a>, theme: &'a Theme) -> Self {
        DecoratedParser {
            h: None,
            parser: parser,
            theme: &theme,
        }
    }
}

impl<'a> Iterator for DecoratedParser<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        match self.parser.next() {
            Some(item) => {
                if let Text(text) = item {
                    if let Some(ref mut h) = self.h {
                        let highlighted = &h.highlight(&text);
                        let html = styles_to_coloured_html(highlighted, IncludeBackground::Yes);
                        Some(Html(Owned(html)))
                    } else {
                        Some(Text(text))
                    }
                } else {
                    if let Start(cmark::Tag::CodeBlock(ref info)) = item {
                        // set local highlighter, if found
                        let cur_syntax =
                            info.clone()
                                .split(' ')
                                .next()
                                .and_then(|lang| SETUP.syntax_set.find_syntax_by_token(lang))
                                .unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text());
                        self.h = Some(HighlightLines::new(&cur_syntax, self.theme));
                        let snippet = start_coloured_html_snippet(self.theme);
                        return Some(Html(Owned(snippet)));
                    }
                    if let End(cmark::Tag::CodeBlock(_)) = item {
                        // reset highlighter
                        self.h = None;
                        // close the code block
                        return Some(Html(Owned("
".to_owned())));
                    }

                    Some(item)
                }
            }
            None => None,
        }
    }
}

pub fn decorate_markdown<'a>(parser: cmark::Parser<'a>, theme_name: &str) -> DecoratedParser<'a> {
    DecoratedParser::new(parser, &SETUP.theme_set.themes[theme_name])
}

#[cfg(test)]
mod test {

    use std::default::Default;
    use liquid::{self, Renderable, LiquidOptions, Context};

    use super::*;

    const CODE_BLOCK: &'static str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
    ";

    const CODEBLOCK_RENDERED: &'static str = "
\nmod test {\n        fn hello(arg: int) -> bool {\n            true\n        \
         }\n    \
         }\n    \
         \n
\n";

    const MARKDOWN_RENDERED: &'static str = "
\nmod test {\n        fn hello(arg: int) -> bool {\n            true\n        }\n    }\n    \n
";

    #[test]
    fn codeblock_renders_rust() {
        // Syntect isn't thread safe, for now run everything in the same test.
        {
            let mut options: LiquidOptions = Default::default();
            options
                .blocks
                .insert("codeblock".to_string(),
                        Box::new(|_, args, tokens, _| {
                                     initialize_codeblock(args, tokens, "base16-ocean.dark")
                                 }));
            let template = liquid::parse(&format!("{{% codeblock rust %}}{}{{% endcodeblock %}}",
                                                  CODE_BLOCK),
                                         options)
                    .unwrap();
            let mut data = Context::new();
            let output = template.render(&mut data);
            assert_eq!(output.unwrap(), Some(CODEBLOCK_RENDERED.to_string()));
        }

        {
            let html = format!("```rust
{}
```",
                               CODE_BLOCK);

            let mut buf = String::new();
            let parser = cmark::Parser::new(&html);
            cmark::html::push_html(&mut buf, decorate_markdown(parser, "base16-ocean.dark"));
            assert_eq!(buf, MARKDOWN_RENDERED);
        }
    }
}
<commit_msg>fix(clippy): Unneeded return statement<commit_after>use std::ascii::AsciiExt;

use std::borrow::Cow::Owned;
use itertools::Itertools;

use liquid;
use liquid::Token::{self, Identifier};
use liquid::lexer::Element::{self, Expression, Tag, Raw};

use syntect::parsing::{SyntaxDefinition, SyntaxSet};
use syntect::highlighting::{ThemeSet, Theme};
use syntect::html::{IncludeBackground, highlighted_snippet_for_string, styles_to_coloured_html,
                    start_coloured_html_snippet};
use syntect::easy::HighlightLines;

use pulldown_cmark as cmark;
use pulldown_cmark::Event::{self, Start, End, Text, Html};

use error;

struct Setup {
    syntax_set: SyntaxSet,
    theme_set: ThemeSet,
}

unsafe impl Send for Setup {}
unsafe impl Sync for Setup {}

lazy_static!{
    static ref SETUP: Setup = Setup {
        syntax_set: SyntaxSet::load_defaults_newlines(),
        theme_set: ThemeSet::load_defaults()
    };
}

pub fn has_syntax_theme(name: &str) -> error::Result<bool> {
    Ok(SETUP.theme_set.themes.contains_key(name))
}

pub fn list_syntax_themes<'a>() -> Vec<&'a String> {
    SETUP.theme_set.themes.keys().collect::<Vec<_>>()
}

pub fn list_syntaxes<'a>() -> Vec<String> {
    fn definition_to_string(sd: &SyntaxDefinition) -> String {
        let extensions = sd.file_extensions.iter().join(&", ".to_owned());
        format!("{} [{}]", sd.name, extensions)
    }

    let mut syntaxes = SETUP
        .syntax_set
        .syntaxes()
        .iter()
        .map(definition_to_string)
        .collect::<Vec<_>>();

    // sort alphabetically with insensitive ascii case
    syntaxes.sort_by_key(|a| (a as &str).to_ascii_lowercase());

    syntaxes
}

struct CodeBlock {
    lang: Option<String>,
    code: String,
    theme: Theme,
}

impl liquid::Renderable for CodeBlock {
    fn render(&self, _: &mut liquid::Context) -> Result<Option<String>, liquid::Error> {
        let syntax = match self.lang {
                Some(ref lang) => SETUP.syntax_set.find_syntax_by_token(lang),
                _ => None,
            }
            .unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text());

        Ok(Some(highlighted_snippet_for_string(&self.code, syntax, &self.theme)))
    }
}

pub fn initialize_codeblock(arguments: &[Token],
                            tokens: &[Element],
                            theme_name: &str)
                            -> Result<Box<liquid::Renderable>, liquid::Error> {
    let content = tokens
        .iter()
        .fold("".to_owned(), |a, b| {
            match *b {
                    Expression(_, ref text) |
                    Tag(_, ref text) |
                    Raw(ref text) => text,
                }
                .to_owned() + &a
        });

    let lang = match arguments.iter().next() {
        Some(&Identifier(ref x)) => Some(x.clone()),
        _ => None,
    };

    Ok(Box::new(CodeBlock {
                    code: content,
                    lang: lang,
                    theme: SETUP.theme_set.themes[theme_name].clone(),
                }))
}

pub struct DecoratedParser<'a> {
    h: Option<HighlightLines<'a>>,
    parser: cmark::Parser<'a>,
    theme: &'a Theme,
}

impl<'a> DecoratedParser<'a> {
    pub fn new(parser: cmark::Parser<'a>, theme: &'a Theme) -> Self {
        DecoratedParser {
            h: None,
            parser: parser,
            theme: &theme,
        }
    }
}

impl<'a> Iterator for DecoratedParser<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        match self.parser.next() {
            Some(item) => {
                if let Text(text) = item {
                    if let Some(ref mut h) = self.h {
                        let highlighted = &h.highlight(&text);
                        let html = styles_to_coloured_html(highlighted, IncludeBackground::Yes);
                        Some(Html(Owned(html)))
                    } else {
                        Some(Text(text))
                    }
                } else {
                    if let Start(cmark::Tag::CodeBlock(ref info)) = item {
                        // set local highlighter, if found
                        let cur_syntax =
                            info.clone()
                                .split(' ')
                                .next()
                                .and_then(|lang| SETUP.syntax_set.find_syntax_by_token(lang))
                                .unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text());
                        self.h = Some(HighlightLines::new(&cur_syntax, self.theme));
                        let snippet = start_coloured_html_snippet(self.theme);
                        return Some(Html(Owned(snippet)));
                    }
                    if let End(cmark::Tag::CodeBlock(_)) = item {
                        // reset highlighter
                        self.h = None;
                        // close the code block
                        return Some(Html(Owned("
".to_owned())));
                    }

                    Some(item)
                }
            }
            None => None,
        }
    }
}

pub fn decorate_markdown<'a>(parser: cmark::Parser<'a>, theme_name: &str) -> DecoratedParser<'a> {
    DecoratedParser::new(parser, &SETUP.theme_set.themes[theme_name])
}

#[cfg(test)]
mod test {

    use std::default::Default;
    use liquid::{self, Renderable, LiquidOptions, Context};

    use super::*;

    const CODE_BLOCK: &'static str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
    ";

    const CODEBLOCK_RENDERED: &'static str = "
\nmod test {\n        fn hello(arg: int) -> bool {\n            true\n        \
         }\n    \
         }\n    \
         \n
\n";

    const MARKDOWN_RENDERED: &'static str = "
\nmod test {\n        fn hello(arg: int) -> bool {\n            true\n        }\n    }\n    \n
";

    #[test]
    fn codeblock_renders_rust() {
        // Syntect isn't thread safe, for now run everything in the same test.
        {
            let mut options: LiquidOptions = Default::default();
            options
                .blocks
                .insert("codeblock".to_string(),
                        Box::new(|_, args, tokens, _| {
                                     initialize_codeblock(args, tokens, "base16-ocean.dark")
                                 }));
            let template = liquid::parse(&format!("{{% codeblock rust %}}{}{{% endcodeblock %}}",
                                                  CODE_BLOCK),
                                         options)
                    .unwrap();
            let mut data = Context::new();
            let output = template.render(&mut data);
            assert_eq!(output.unwrap(), Some(CODEBLOCK_RENDERED.to_string()));
        }

        {
            let html = format!("```rust
{}
```",
                               CODE_BLOCK);

            let mut buf = String::new();
            let parser = cmark::Parser::new(&html);
            cmark::html::push_html(&mut buf, decorate_markdown(parser, "base16-ocean.dark"));
            assert_eq!(buf, MARKDOWN_RENDERED);
        }
    }
}
<|endoftext|>


<commit_before>// fn first() {
//    let mut v = vec![1,2,3,4,5,6,7,8,9];

//    for num in &mut v {
//        if num < 5 {
//            v.push(num *num);
//        }

//        println!("{}",num);
//    }
// }

/// We now can iterate over v while adding more to v but
///   1. We don't have a mechanism to continue iterating over the newly
///      added elements, but we could do this with a queue, if need be.
///
///   2. We were required to add create a copy, which may or may not be good.
fn second() {
    let mut v = vec![5,2,3,7,9];

    let v_clone = v.clone();
    for num in v_clone {
        if num < 5 {
            v.push(num*num);
        }

        println!("{}", num);
    }

    println!("{:?}", v);
}

/// Iterating over indices

fn third() {
    let mut v = vec![5,2,3,7,9];

    let mut n = 0;
    while n < v.len() {
        let num = v[n];
        n += 1;

        if num < 5 {
            v.push(num*num);
        }

        println!("{}", num);
    }
}

/// Suppose you need to remove an element while iterating.
/// You can do the reverse swap-pop method. Do however note
/// that you will not preserve ordering while

fn fourth() {
    let mut v = vec![5,2,3,7,9];

    for i in (0..v.len()).rev() {
        if v[i] < 5 {
            //swap and pop
            v.swap_remove(i);
            println!("Pop!");
            continue;
        }
        println!("{}", v[i]);
    }

    println!("{:?}", v);
}

/// Dealing with iterators that don't have indicies.  Let's take a string for instance
/// (even though you can save indicies using `char_indices()`).
/// Here you can save the items you wish to push to the end

fn fifth() {
    let mut my_string = "Hello, String!".to_string();
    let mut acc = String::new();

    for ch in my_string.chars() {
        if ch == 'l' {
            acc.push('!');
        }
    }
    my_string = my_string + &acc;
    println!("{}", my_string);

}

fn main() {
    // second();
    // third();
    fourth();
    fifth();
}<commit_msg>clean up basic iteration examples<commit_after>/// We now can iterate over v while adding more to v but
///   1. We don't have a mechanism to continue iterating over the newly
///      added elements, but we could do this with a queue, if need be.
///
///   2. We were required to add create a copy, which may or may not be good.
fn iter_and_append() {
    let mut my_string = "Hello, String!".to_string();

    // Allocate a buffer
    let mut res = String::new();
    for ch in my_string.chars() {
        if ch == 'l' {
            res.push('!');
        }
    }

    my_string = my_string + &res;
    println!("{}", my_string);
}

/// For such a small example, you may find a functional approach better.
/// Which you choose is mostly up to personal preference.  Differences between
/// the functinoal approach and using a loop start to become noticable once
/// you need to modify 'global state'.  We will discuss that shortly, but
/// here is the first example, rewritten using `chain` with a `filter_map`.

fn iter_and_append_f() {
    let mut my_string = "Hello, String!".to_string();
    let mut new_string = String::new();

    new_string = my_string.chars().chain(
        my_string.chars().filter_map(
            |c| match c {
                'l' => Some('!'),
                _ => None
            }
        )
    ).collect();

    println!("{}", new_string);
}

/// Suppose you need to remove an element while iterating.
/// You can do the reverse swap-pop method. Do however note
/// that you will not preserve ordering while.
/// This also only works for iterators that give you
/// access to indices.

fn remove_evens() {
    // We iterate backwards for a few reaons:
    //   1. When we swap, we swap with an element
    //      that we have already processed.
    //   2. Pop is more efficient than removing
    //      an element from the beginning
    //   3. Popping reduces `v.len()` as we iterate
    //      which would require for use to compensate
    //      the index `i` after every removal if we
    //      iterated from 0..v.len();
    let mut v = vec![5,2,3,6,9];

    for i in (0..v.len()).rev() {
        if v[i] % 2 == 0 {
            v.swap_remove(i);
        }
    }

    println!("{:?}", v);
}

/// As before, you may find such a simple example easier to
/// handle using `filter` (I certainly would recommend this).

fn remove_vowels() {
    let mut my_string = "Hello, String!".to_string();
    let mut res = String::new();

    res = my_string.chars().filter(
        |&c| match c {
            'a' | 'e' | 'i' | 'o' | 'u'
               => false,
            _  => true,
        }
    ).collect();

    println!("{}", res);
}

fn main() {
    iter_and_append();
    iter_and_append_f();
    remove_evens();
    remove_vowels();
}<|endoftext|>


<commit_before>//! See https://github.com/matklad/cargo-xtask/.
//!
//! This binary defines various auxiliary build commands, which are not
//! expressible with just `cargo`. Notably, it provides `cargo xtask codegen`
//! for code genetaiont and `cargo xtask install` for installation of
//! rust-analyzer server and client.
//!
//! This binary is integrated into the `cargo` command line by using an alias in
//! `.cargo/config`.
mod help;

use core::fmt::Write;
use core::str;
use pico_args::Arguments;
use std::{env, path::PathBuf};
use xtask::{
    codegen::{self, Mode},
    install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt, run_with_output, Cmd, Result,
};

// Latest stable, feel free to send a PR if this lags behind.
const REQUIRED_RUST_VERSION: u32 = 38;

struct InstallOpt {
    client: Option<ClientOpt>,
    server: Option<ServerOpt>,
}

enum ClientOpt {
    VsCode,
}

struct ServerOpt {
    jemalloc: bool,
}

fn main() -> Result<()> {
    let subcommand = match std::env::args_os().nth(1) {
        None => {
            eprintln!("{}", help::GLOBAL_HELP);
            return Ok(());
        }
        Some(s) => s,
    };
    let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());
    let subcommand = &*subcommand.to_string_lossy();
    match subcommand {
        "install" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::INSTALL_HELP);
                return Ok(());
            }
            let server = matches.contains("--server");
            let client_code = matches.contains("--client-code");
            if server && client_code {
                eprintln!("{}", help::INSTALL_RA_CONFLICT);
                return Ok(());
            }
            let jemalloc = matches.contains("--jemalloc");
            matches.finish().or_else(handle_extra_flags)?;
            let opts = InstallOpt {
                client: if server { None } else { Some(ClientOpt::VsCode) },
                server: if client_code { None } else { Some(ServerOpt { jemalloc: jemalloc }) },
            };
            install(opts)?
        }
        "codegen" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            codegen::generate_syntax(Mode::Overwrite)?;
            codegen::generate_parser_tests(Mode::Overwrite)?;
            codegen::generate_assists_docs(Mode::Overwrite)?;
        }
        "format" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_rustfmt(Mode::Overwrite)?
        }
        "format-hook" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            install_format_hook()?
        }
        "lint" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_clippy()?
        }
        "fuzz-tests" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_fuzzer()?
        }
        _ => eprintln!("{}", help::GLOBAL_HELP),
    }
    Ok(())
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        Err(format!("Invalid flags: {}", invalid_flags).into())
    } else {
        Err(e.to_string().into())
    }
}

fn install(opts: InstallOpt) -> Result<()> {
    if cfg!(target_os = "macos") {
        fix_path_for_mac()?
    }
    if let Some(server) = opts.server {
        install_server(server)?;
    }
    if let Some(client) = opts.client {
        install_client(client)?;
    }
    Ok(())
}

fn fix_path_for_mac() -> Result<()> {
    let mut vscode_path: Vec<PathBuf> = {
        const COMMON_APP_PATH: &str =
            r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
        const ROOT_DIR: &str = "";
        let home_dir = match env::var("HOME") {
            Ok(home) => home,
            Err(e) => Err(format!("Failed getting HOME from environment with error: {}.", e))?,
        };

        [ROOT_DIR, &home_dir]
            .iter()
            .map(|dir| String::from(*dir) + COMMON_APP_PATH)
            .map(PathBuf::from)
            .filter(|path| path.exists())
            .collect()
    };

    if !vscode_path.is_empty() {
        let vars = match env::var_os("PATH") {
            Some(path) => path,
            None => Err("Could not get PATH variable from env.")?,
        };

        let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
        paths.append(&mut vscode_path);
        let new_paths = env::join_paths(paths)?;
        env::set_var("PATH", &new_paths);
    }

    Ok(())
}

fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
    let npm_version = Cmd {
        unix: r"npm --version",
        windows: r"cmd.exe /c npm.cmd --version",
        work_dir: "./editors/code",
    }
    .run();

    if npm_version.is_err() {
        eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin")
    }

    Cmd { unix: r"npm ci", windows: r"cmd.exe /c npm.cmd ci", work_dir: "./editors/code" }.run()?;
    Cmd {
        unix: r"npm run package",
        windows: r"cmd.exe /c npm.cmd run package",
        work_dir: "./editors/code",
    }
    .run()?;

    let code_binary = ["code", "code-insiders", "codium"].iter().find(|bin| {
        Cmd {
            unix: &format!("{} --version", bin),
            windows: &format!("cmd.exe /c {}.cmd --version", bin),
            work_dir: "./editors/code",
        }
        .run()
        .is_ok()
    });

    let code_binary = match code_binary {
        Some(it) => it,
        None => Err("Can't execute `code --version`. Perhaps it is not in $PATH?")?,
    };

    Cmd {
        unix: &format!(r"{} --install-extension ./ra-lsp-0.0.1.vsix --force", code_binary),
        windows: &format!(
            r"cmd.exe /c {}.cmd --install-extension ./ra-lsp-0.0.1.vsix --force",
            code_binary
        ),
        work_dir: "./editors/code",
    }
    .run()?;

    let output = Cmd {
        unix: &format!(r"{} --list-extensions", code_binary),
        windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary),
        work_dir: ".",
    }
    .run_with_output()?;

    if !str::from_utf8(&output.stdout)?.contains("ra-lsp") {
        Err("Could not install the Visual Studio Code extension. \
             Please make sure you have at least NodeJS 10.x installed and try again.")?;
    }

    Ok(())
}

fn install_server(opts: ServerOpt) -> Result<()> {
    let mut old_rust = false;
    if let Ok(output) = run_with_output("cargo --version", ".") {
        if let Ok(stdout) = String::from_utf8(output.stdout) {
            if !check_version(&stdout, REQUIRED_RUST_VERSION) {
                old_rust = true;
            }
        }
    }

    if old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION
        )
    }

    let res = if opts.jemalloc {
        run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".")
    } else {
        run("cargo install --path crates/ra_lsp_server --locked --force", ".")
    };

    if res.is_err() && old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION
        )
    }

    res
}

fn check_version(version_output: &str, min_minor_version: u32) -> bool {
    // Parse second the number out of
    //      cargo 1.39.0-beta (1c6ec66d5 2019-09-30)
    let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok());
    match minor {
        None => true,
        Some(minor) => minor >= min_minor_version,
    }
}
<commit_msg>echo cargo version during install<commit_after>//! See https://github.com/matklad/cargo-xtask/.
//!
//! This binary defines various auxiliary build commands, which are not
//! expressible with just `cargo`. Notably, it provides `cargo xtask codegen`
//! for code genetaiont and `cargo xtask install` for installation of
//! rust-analyzer server and client.
//!
//! This binary is integrated into the `cargo` command line by using an alias in
//! `.cargo/config`.
mod help;

use core::fmt::Write;
use core::str;
use pico_args::Arguments;
use std::{env, path::PathBuf};
use xtask::{
    codegen::{self, Mode},
    install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt, run_with_output, Cmd, Result,
};

// Latest stable, feel free to send a PR if this lags behind.
const REQUIRED_RUST_VERSION: u32 = 38;

struct InstallOpt {
    client: Option<ClientOpt>,
    server: Option<ServerOpt>,
}

enum ClientOpt {
    VsCode,
}

struct ServerOpt {
    jemalloc: bool,
}

fn main() -> Result<()> {
    let subcommand = match std::env::args_os().nth(1) {
        None => {
            eprintln!("{}", help::GLOBAL_HELP);
            return Ok(());
        }
        Some(s) => s,
    };
    let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());
    let subcommand = &*subcommand.to_string_lossy();
    match subcommand {
        "install" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::INSTALL_HELP);
                return Ok(());
            }
            let server = matches.contains("--server");
            let client_code = matches.contains("--client-code");
            if server && client_code {
                eprintln!("{}", help::INSTALL_RA_CONFLICT);
                return Ok(());
            }
            let jemalloc = matches.contains("--jemalloc");
            matches.finish().or_else(handle_extra_flags)?;
            let opts = InstallOpt {
                client: if server { None } else { Some(ClientOpt::VsCode) },
                server: if client_code { None } else { Some(ServerOpt { jemalloc: jemalloc }) },
            };
            install(opts)?
        }
        "codegen" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            codegen::generate_syntax(Mode::Overwrite)?;
            codegen::generate_parser_tests(Mode::Overwrite)?;
            codegen::generate_assists_docs(Mode::Overwrite)?;
        }
        "format" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_rustfmt(Mode::Overwrite)?
        }
        "format-hook" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            install_format_hook()?
        }
        "lint" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_clippy()?
        }
        "fuzz-tests" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_fuzzer()?
        }
        _ => eprintln!("{}", help::GLOBAL_HELP),
    }
    Ok(())
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        Err(format!("Invalid flags: {}", invalid_flags).into())
    } else {
        Err(e.to_string().into())
    }
}

fn install(opts: InstallOpt) -> Result<()> {
    if cfg!(target_os = "macos") {
        fix_path_for_mac()?
    }
    if let Some(server) = opts.server {
        install_server(server)?;
    }
    if let Some(client) = opts.client {
        install_client(client)?;
    }
    Ok(())
}

fn fix_path_for_mac() -> Result<()> {
    let mut vscode_path: Vec<PathBuf> = {
        const COMMON_APP_PATH: &str =
            r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
        const ROOT_DIR: &str = "";
        let home_dir = match env::var("HOME") {
            Ok(home) => home,
            Err(e) => Err(format!("Failed getting HOME from environment with error: {}.", e))?,
        };

        [ROOT_DIR, &home_dir]
            .iter()
            .map(|dir| String::from(*dir) + COMMON_APP_PATH)
            .map(PathBuf::from)
            .filter(|path| path.exists())
            .collect()
    };

    if !vscode_path.is_empty() {
        let vars = match env::var_os("PATH") {
            Some(path) => path,
            None => Err("Could not get PATH variable from env.")?,
        };

        let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
        paths.append(&mut vscode_path);
        let new_paths = env::join_paths(paths)?;
        env::set_var("PATH", &new_paths);
    }

    Ok(())
}

fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
    let npm_version = Cmd {
        unix: r"npm --version",
        windows: r"cmd.exe /c npm.cmd --version",
        work_dir: "./editors/code",
    }
    .run();

    if npm_version.is_err() {
        eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin")
    }

    Cmd { unix: r"npm ci", windows: r"cmd.exe /c npm.cmd ci", work_dir: "./editors/code" }.run()?;
    Cmd {
        unix: r"npm run package",
        windows: r"cmd.exe /c npm.cmd run package",
        work_dir: "./editors/code",
    }
    .run()?;

    let code_binary = ["code", "code-insiders", "codium"].iter().find(|bin| {
        Cmd {
            unix: &format!("{} --version", bin),
            windows: &format!("cmd.exe /c {}.cmd --version", bin),
            work_dir: "./editors/code",
        }
        .run()
        .is_ok()
    });

    let code_binary = match code_binary {
        Some(it) => it,
        None => Err("Can't execute `code --version`. Perhaps it is not in $PATH?")?,
    };

    Cmd {
        unix: &format!(r"{} --install-extension ./ra-lsp-0.0.1.vsix --force", code_binary),
        windows: &format!(
            r"cmd.exe /c {}.cmd --install-extension ./ra-lsp-0.0.1.vsix --force",
            code_binary
        ),
        work_dir: "./editors/code",
    }
    .run()?;

    let output = Cmd {
        unix: &format!(r"{} --list-extensions", code_binary),
        windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary),
        work_dir: ".",
    }
    .run_with_output()?;

    if !str::from_utf8(&output.stdout)?.contains("ra-lsp") {
        Err("Could not install the Visual Studio Code extension. \
             Please make sure you have at least NodeJS 10.x installed and try again.")?;
    }

    Ok(())
}

fn install_server(opts: ServerOpt) -> Result<()> {
    let mut old_rust = false;
    if let Ok(output) = run_with_output("cargo --version", ".") {
        if let Ok(stdout) = String::from_utf8(output.stdout) {
            println!("{}", stdout);
            if !check_version(&stdout, REQUIRED_RUST_VERSION) {
                old_rust = true;
            }
        }
    }

    if old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION
        )
    }

    let res = if opts.jemalloc {
        run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".")
    } else {
        run("cargo install --path crates/ra_lsp_server --locked --force", ".")
    };

    if res.is_err() && old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION
        )
    }

    res
}

fn check_version(version_output: &str, min_minor_version: u32) -> bool {
    // Parse second the number out of
    //      cargo 1.39.0-beta (1c6ec66d5 2019-09-30)
    let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok());
    match minor {
        None => true,
        Some(minor) => minor >= min_minor_version,
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

// xfail-test FIXME #1866
mod a {
    pub type rust_task = uint;
    pub mod rustrt {
        use super::rust_task;
        extern {
            pub fn rust_task_is_unwinding(rt: *rust_task) -> bool;
        }
    }
}

mod b {
    pub type rust_task = bool;
    pub mod rustrt {
        use super::rust_task;
        extern {
            pub fn rust_task_is_unwinding(rt: *rust_task) -> bool;
        }
    }
}

pub fn main() { }
<commit_msg>auto merge of #8986 : metajack/rust/rem-1866-xfail-comment, r=huonw<commit_after>// Copyright 2012 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.

mod a {
    pub type rust_task = uint;
    pub mod rustrt {
        use super::rust_task;
        extern {
            pub fn rust_task_is_unwinding(rt: *rust_task) -> bool;
        }
    }
}

mod b {
    pub type rust_task = bool;
    pub mod rustrt {
        use super::rust_task;
        extern {
            pub fn rust_task_is_unwinding(rt: *rust_task) -> bool;
        }
    }
}

pub fn main() { }
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use std::cmp::Ordering;

use super::symbol_range::*;

///
/// A symbol map maps from one set of symbol ranges to another
///
pub struct SymbolMap<Symbol: PartialOrd+Clone> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: PartialOrd+Clone> SymbolMap<Symbol> {
    ///
    /// Creates a new symbol map
    ///
    pub fn new() -> SymbolMap<Symbol> {
        SymbolMap { ranges: vec![] }
    }

    ///
    /// Orders two symbols (makes unordered symbols equal)
    ///
    #[inline]
    fn order_symbols(a: &Symbol, b: &Symbol) -> Ordering {
        if let Some(order) = a.partial_cmp(b) {
            order
        } else {
            Ordering::Equal
        }
    }

    ///
    /// Orders two symbol ranges
    ///
    #[inline]
    fn order_ranges(a: &SymbolRange<Symbol>, b: &SymbolRange<Symbol>) -> Ordering {
        let ordering = SymbolMap::order_symbols(&a.lowest, &b.lowest);

        if ordering == Ordering::Equal {
            SymbolMap::order_symbols(&a.highest, &b.highest)
        } else {
            ordering
        }
    }

    ///
    /// Adds a range to those that are known about by this object
    ///
    pub fn add_range(&mut self, range: &SymbolRange<Symbol>) {
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Insert the range if it is not already in the map
        if let Err(insertion_pos) = existing {
            self.ranges.insert(insertion_pos, range.clone());
        }
    }

    ///
    /// Finds the ranges in this map that overlap the target ranges
    ///
    pub fn find_overlapping_ranges(&self, range: &SymbolRange<Symbol>) -> Vec<&SymbolRange<Symbol>> {
        let mut result = vec![];

        // Find the first range that matches (or the insertion position, which should be the first range wit a lowest value higher than the target range)
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Start returning values from here
        let mut pos = match existing {
            Ok(found_position) => found_position,
            Err(insert_position) => insert_position
        };

        // TODO: can we construct a set of ranges such that one is missed here? Think maybe we can
        while pos < self.ranges.len() && self.ranges[pos].lowest <= range.highest {
            result.push(&self.ranges[pos]);
            pos += 1;
        }

        result
    }

    ///
    /// Creates a non-overlapping range from an overlapping one
    ///
    pub fn to_non_overlapping_map(&self) -> SymbolMap<Symbol> {
        // Create a vector of all the range symbols
        let mut range_symbols: Vec<Symbol> = self.ranges.iter()
            .map(|r| r.lowest.clone())
            .chain(self.ranges.iter().map(|r| r.highest.clone()))
            .collect();

        // Sort and dedupe (we'll get pairs of ranges)
        range_symbols.sort_by(SymbolMap::order_symbols);
        range_symbols.dedup();

        // Generate a new symbol map with these ranges
        // They'll overlap with the last value, which should be OK if following the rules for adjacent ranges in symbol_range.rs
        let mut result = vec![];
        for index in 0..range_symbols.len()-1 {
            result.push(SymbolRange::new(range_symbols[index].clone(), range_symbols[index+1].clone()));
        }

        // We already sorted everything, so bypass the usual 'add' method (which sorts as it goes)
        SymbolMap { ranges: result }
    }
}

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

    #[test]
    fn can_lookup_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(0, 1));
        let all    = map.find_overlapping_ranges(&SymbolRange::new(1, 3));
        let top    = map.find_overlapping_ranges(&SymbolRange::new(6, 6));

        println!("All is: {:?}", all);

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(2, 5), &SymbolRange::new(3, 6)]);
        assert!(top == vec![&SymbolRange::new(6, 6)]);
    }

    #[test]
    fn can_lookup_mid_range() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(5, 10));
        map.add_range(&SymbolRange::new(11, 15));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
    }

    #[test]
    fn works_with_duplicate_lower_values() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 2));
        map.add_range(&SymbolRange::new(0, 3));

        let all    = map.find_overlapping_ranges(&SymbolRange::new(0, 1));

        println!("With duplicate lower values is: {:?}", all);

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(0, 3)]);
    }

    #[test]
    fn obeys_adjacency_rule() {
        let mut map = SymbolMap::new();

        // By the adjacency rule for symbol ranges (in symbol_range.rs), '4' here is only in the upper range
        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(4, 8));

        let top = map.find_overlapping_ranges(&SymbolRange::new(4, 4));

        assert!(top == vec![&SymbolRange::new(4, 8)]);
    }

    #[test]
    fn can_get_non_overlapping_map() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(2, 3), &SymbolRange::new(3, 6)]);
    }
}
<commit_msg>Fix the set of non-overlapping ranges<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use std::cmp::Ordering;

use super::symbol_range::*;

///
/// A symbol map maps from one set of symbol ranges to another
///
pub struct SymbolMap<Symbol: PartialOrd+Clone> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: PartialOrd+Clone> SymbolMap<Symbol> {
    ///
    /// Creates a new symbol map
    ///
    pub fn new() -> SymbolMap<Symbol> {
        SymbolMap { ranges: vec![] }
    }

    ///
    /// Orders two symbols (makes unordered symbols equal)
    ///
    #[inline]
    fn order_symbols(a: &Symbol, b: &Symbol) -> Ordering {
        if let Some(order) = a.partial_cmp(b) {
            order
        } else {
            Ordering::Equal
        }
    }

    ///
    /// Orders two symbol ranges
    ///
    #[inline]
    fn order_ranges(a: &SymbolRange<Symbol>, b: &SymbolRange<Symbol>) -> Ordering {
        let ordering = SymbolMap::order_symbols(&a.lowest, &b.lowest);

        if ordering == Ordering::Equal {
            SymbolMap::order_symbols(&a.highest, &b.highest)
        } else {
            ordering
        }
    }

    ///
    /// Adds a range to those that are known about by this object
    ///
    pub fn add_range(&mut self, range: &SymbolRange<Symbol>) {
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Insert the range if it is not already in the map
        if let Err(insertion_pos) = existing {
            self.ranges.insert(insertion_pos, range.clone());
        }
    }

    ///
    /// Finds the ranges in this map that overlap the target ranges
    ///
    pub fn find_overlapping_ranges(&self, range: &SymbolRange<Symbol>) -> Vec<&SymbolRange<Symbol>> {
        let mut result = vec![];

        // Find the first range that matches (or the insertion position, which should be the first range wit a lowest value higher than the target range)
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Start returning values from here
        let mut pos = match existing {
            Ok(found_position) => found_position,
            Err(insert_position) => insert_position
        };

        // TODO: can we construct a set of ranges such that one is missed here? Think maybe we can
        while pos < self.ranges.len() && self.ranges[pos].lowest <= range.highest {
            result.push(&self.ranges[pos]);
            pos += 1;
        }

        result
    }

    ///
    /// Creates a non-overlapping range from an overlapping one
    ///
    pub fn to_non_overlapping_map(&self) -> SymbolMap<Symbol> {
        // Create a vector of all the range symbols
        let mut range_symbols: Vec<Symbol> = self.ranges.iter()
            .map(|r| r.lowest.clone())
            .chain(self.ranges.iter().map(|r| r.highest.clone()))
            .collect();

        // Sort and dedupe (we'll get pairs of ranges)
        range_symbols.sort_by(SymbolMap::order_symbols);
        range_symbols.dedup();

        // Generate a new symbol map with these ranges
        // They'll overlap with the last value, which should be OK if following the rules for adjacent ranges in symbol_range.rs
        let mut result = vec![];
        for index in 0..range_symbols.len()-1 {
            result.push(SymbolRange::new(range_symbols[index].clone(), range_symbols[index+1].clone()));
        }

        // We already sorted everything, so bypass the usual 'add' method (which sorts as it goes)
        SymbolMap { ranges: result }
    }
}

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

    #[test]
    fn can_lookup_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(0, 1));
        let all    = map.find_overlapping_ranges(&SymbolRange::new(1, 3));
        let top    = map.find_overlapping_ranges(&SymbolRange::new(6, 6));

        println!("All is: {:?}", all);

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(2, 5), &SymbolRange::new(3, 6)]);
        assert!(top == vec![&SymbolRange::new(6, 6)]);
    }

    #[test]
    fn can_lookup_mid_range() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(5, 10));
        map.add_range(&SymbolRange::new(11, 15));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
    }

    #[test]
    fn works_with_duplicate_lower_values() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 2));
        map.add_range(&SymbolRange::new(0, 3));

        let all    = map.find_overlapping_ranges(&SymbolRange::new(0, 1));

        println!("With duplicate lower values is: {:?}", all);

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(0, 3)]);
    }

    #[test]
    fn obeys_adjacency_rule() {
        let mut map = SymbolMap::new();

        // By the adjacency rule for symbol ranges (in symbol_range.rs), '4' here is only in the upper range
        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(4, 8));

        let top = map.find_overlapping_ranges(&SymbolRange::new(4, 4));

        assert!(top == vec![&SymbolRange::new(4, 8)]);
    }

    #[test]
    fn can_get_non_overlapping_map() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(2, 3), &SymbolRange::new(3, 4), &SymbolRange::new(4, 5), &SymbolRange::new(5, 6)]);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

use core::fmt;
use parser;

impl<'a> fmt::Display for parser::Expected {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            parser::Expected::Any(ref crits) => write!(f, "one of {:?}", crits),
            parser::Expected::Exact(crit) => write!(f, "{}", crit),
            parser::Expected::Range { min, max } => {
                write!(f, "{}..{} inclusive", min, max)
            }
        }
    }
}

impl fmt::Display for parser::ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: ", self._description())?;

        match *self {
            parser::ParseError::InvalidCharacter {
                expected,
                found,
                index,
            } => write!(
                f,
                "expected {}, found {} at {}",
                expected,
                found,
                index
            ),
            parser::ParseError::InvalidGroupCount {
                ref expected,
                found,
            } => write!(f, "expected {}, found {}", expected, found),
            parser::ParseError::InvalidGroupLength {
                ref expected,
                found,
                group,
            } => write!(
                f,
                "expected {}, found {} in group {}",
                expected, found, group,
            ),
            parser::ParseError::InvalidLength {
                ref expected,
                found,
            } => write!(f, "expected {}, found {}", expected, found),
        }
    }
}
<commit_msg>fmt<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

use core::fmt;
use parser;

impl<'a> fmt::Display for parser::Expected {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            parser::Expected::Any(ref crits) => write!(f, "one of {:?}", crits),
            parser::Expected::Exact(crit) => write!(f, "{}", crit),
            parser::Expected::Range { min, max } => {
                write!(f, "{}..{} inclusive", min, max)
            }
        }
    }
}

impl fmt::Display for parser::ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: ", self._description())?;

        match *self {
            parser::ParseError::InvalidCharacter {
                expected,
                found,
                index,
            } => {
                write!(f, "expected {}, found {} at {}", expected, found, index)
            }
            parser::ParseError::InvalidGroupCount {
                ref expected,
                found,
            } => write!(f, "expected {}, found {}", expected, found),
            parser::ParseError::InvalidGroupLength {
                ref expected,
                found,
                group,
            } => write!(
                f,
                "expected {}, found {} in group {}",
                expected, found, group,
            ),
            parser::ParseError::InvalidLength {
                ref expected,
                found,
            } => write!(f, "expected {}, found {}", expected, found),
        }
    }
}
<|endoftext|>