<commit_before>extern crate html5ever;
extern crate tendril;
extern crate regex;
extern crate hyper;
extern crate string_cache;
extern crate url;

use html5ever::rcdom::{Document, Doctype, Text, Comment, Element};
use html5ever::rcdom::{RcDom, Handle};
use html5ever::{parse_document, Attribute};
use tendril::stream::TendrilSink;
use std::default::Default;
use uuid::Uuid;

use regex::Regex;
use hyper::Client;
use hyper::header::Connection;
use hyper::header::ConnectionOption;

use Provider;
use Track;
use soundcloud;
use youtube;

use url::percent_encoding::lossy_utf8_percent_decode;

static YOUTUBE_EMBED:    &'static str = r"www.youtube.com/embed/([^\?&{videoseries}].+)";
static YOUTUBE_LIST:         &'static str = r"www.youtube.com/embed/videoseries\?list=([^\?]+)";
static YOUTUBE_WATCH:        &'static str = r"www.youtube.com/watch\?v=([^\?&]+)";
static SOUNDCLOUD_TRACK:     &'static str = r"api.soundcloud.com/tracks/([^\?&]+)";
static SOUNDCLOUD_PLAYLIST:  &'static str = r"api.soundcloud.com/playlists/([^\?&]+)";
static SOUNDCLOUD_USER:      &'static str = r"api.soundcloud.com/users/([^\?&]+)";

pub fn extract_tracks(url: &str) -> Option<Vec<Track>> {
    let client = Client::new();
    let mut res = client.get(url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    if res.status.is_success() {
        let dom = parse_document(RcDom::default(), Default::default())
            .from_utf8()
            .read_from(&mut res)
            .unwrap();
        let mut tracks  = Vec::new();
        walk(0, dom.document, &mut tracks);
        return Some(tracks)
    } else {
        println!("Failed to get entry html {}: {}", res.status, url);
        return None
    }
}

// This is not proper HTML serialization, of course.
fn walk(indent: usize, handle: Handle, tracks: &mut Vec<Track>) {
    let node = handle.borrow();
    match node.node {
        Document         => (),
        Doctype(_, _, _) => (),
        Text(_)          => (),
        Comment(_)       => (),
        Element(ref name, _, ref attrs) => {
            let tag_name = name.local.as_ref();
            let ts: Vec<Track> = extract_tracks_from_tag(tag_name, attrs);
            for track in ts.iter().cloned() {
                if !(tracks).iter().any(|t| track == *t) {
                    (*tracks).push(track)
                }
            }
        }
    }
    for child in node.children.iter() {
        walk(indent+4, child.clone(), tracks);
    }
}

fn attr(attr_name: &str, attrs: &Vec<Attribute>) -> Option<String> {
    for attr in attrs.iter() {
        if attr.name.local.as_ref() == attr_name {
            return Some(attr.value.to_string())
        }
    }
    None
}

fn extract_identifier(value: &str, regex_str: &str) -> Option<String> {
    match Regex::new(regex_str) {
        Ok(re) => match re.captures(value) {
            Some(cap) => match cap.at(1) {
                Some(str) => {
                    let strs: Vec<&str> = str.split('?').collect();
                    return Some(strs[0].to_string())
                },
                None => None
            },
            None => None
        },
        Err(_) => None
    }
}

pub fn extract_tracks_from_tag(tag_name: &str,
                               attrs: &Vec<Attribute>) -> Vec<Track> {
    if tag_name == "iframe" {
        match attr("src", attrs) {
            Some(ref src) => extract_tracks_from_url(src.to_string()),
            None => vec![]
        }
    } else if tag_name == "a" || tag_name == "link" {
        match attr("href", attrs) {
            Some(ref href) => extract_tracks_from_url(href.to_string()),
            None => vec![]
        }
    } else {
        vec![]
    }
}

fn extract_tracks_from_url(url: String) -> Vec<Track> {
    let decoded = lossy_utf8_percent_decode(url.as_bytes());
    match extract_identifier(&decoded, YOUTUBE_EMBED) {
        Some(identifier) => {
            return vec![Track {
                        id: Uuid::new_v4(),
                  provider: Provider::YouTube,
                     title: "".to_string(),
                       url: url.to_string(),
                identifier: identifier
            }]
        },
        None => ()
    }
    match extract_identifier(&decoded, YOUTUBE_WATCH) {
        Some(identifier) => {
            return vec![Track {
                        id: Uuid::new_v4(),
                  provider: Provider::YouTube,
                     title: "".to_string(),
                       url: url.to_string(),
                identifier: identifier
            }]
        },
        None => ()
    }
    match extract_identifier(&decoded, YOUTUBE_LIST) {
        Some(identifier) => {
            return match youtube::fetch_playlist(&identifier) {
                Ok(res) => res.items.iter()
                                    .map(|ref i| Track::from_yt_playlist_item(i))
                                    .collect::<Vec<_>>(),
                Err(_)       => vec![]
            }
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_TRACK) {
        Some(identifier) => {
            return vec![Track {
                        id: Uuid::new_v4(),
                  provider: Provider::SoundCloud,
                     title: "".to_string(),
                       url: url.to_string(),
                identifier: identifier
            }]
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_PLAYLIST) {
        Some(identifier) => {
            return match soundcloud::fetch_playlist(&identifier) {
                Ok(playlist) => playlist.tracks
                                        .iter()
                                        .map(|ref t| Track::from_sc_track(t))
                                        .collect::<Vec<_>>(),
                Err(_)       => vec![]
            }
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_USER) {
        Some(identifier) => {
            print!("user {}", identifier);
            return match soundcloud::fetch_user_tracks(&identifier) {
                Ok(tracks) => tracks.iter()
                                    .map(|ref t| Track::from_sc_track(t))
                                    .collect::<Vec<_>>(),
                Err(_)     => vec![]
            }
        },
        None => ()
    }
    return vec![]
}

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

    #[test]
    fn test_extract_identifier() {
        let soundcloud_src = "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/195425494&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true";
        match extract_identifier(soundcloud_src, super::SOUNDCLOUD_TRACK) {
            Some(identifier) => assert_eq!(identifier, "195425494".to_string()),
            None             => assert!(false)
        }
        let youtube_embed = "https://www.youtube.com/embed/X8tOngmlES0?rel=0";
        match extract_identifier(youtube_embed, super::YOUTUBE_EMBED) {
            Some(identifier) => assert_eq!(identifier, "X8tOngmlES0".to_string()),
            None             => assert!(false)
        }

        let youtube_watch = "https://www.youtube.com/watch?v=oDuif301F-8";
        match extract_identifier(youtube_watch, super::YOUTUBE_WATCH) {
            Some(identifier) => assert_eq!(identifier, "oDuif301F-8".to_string()),
            None             => assert!(false)
        }

        let youtube_list = "https://www.youtube.com/embed/videoseries?list=PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX";
        match extract_identifier(youtube_list, super::YOUTUBE_LIST) {
            Some(identifier) => assert_eq!(identifier, "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string()),
            None             => assert!(false)
        }

        match extract_identifier(youtube_list, super::YOUTUBE_EMBED) {
            Some(identifier) => assert!(false),
            None             => assert!(true)
        }
    }
}
<commit_msg>Follow latest url<commit_after>extern crate html5ever;
extern crate tendril;
extern crate regex;
extern crate hyper;
extern crate string_cache;
extern crate url;

use html5ever::rcdom::{Document, Doctype, Text, Comment, Element};
use html5ever::rcdom::{RcDom, Handle};
use html5ever::{parse_document, Attribute};
use tendril::stream::TendrilSink;
use std::default::Default;
use uuid::Uuid;

use regex::Regex;
use hyper::Client;
use hyper::header::Connection;
use hyper::header::ConnectionOption;

use Provider;
use Track;
use soundcloud;
use youtube;

use url::percent_encoding::{percent_decode};

static YOUTUBE_EMBED:    &'static str = r"www.youtube.com/embed/([^\?&{videoseries}].+)";
static YOUTUBE_LIST:         &'static str = r"www.youtube.com/embed/videoseries\?list=([^\?]+)";
static YOUTUBE_WATCH:        &'static str = r"www.youtube.com/watch\?v=([^\?&]+)";
static SOUNDCLOUD_TRACK:     &'static str = r"api.soundcloud.com/tracks/([^\?&]+)";
static SOUNDCLOUD_PLAYLIST:  &'static str = r"api.soundcloud.com/playlists/([^\?&]+)";
static SOUNDCLOUD_USER:      &'static str = r"api.soundcloud.com/users/([^\?&]+)";

pub fn extract_tracks(url: &str) -> Option<Vec<Track>> {
    let client = Client::new();
    let mut res = client.get(url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    if res.status.is_success() {
        let dom = parse_document(RcDom::default(), Default::default())
            .from_utf8()
            .read_from(&mut res)
            .unwrap();
        let mut tracks  = Vec::new();
        walk(0, dom.document, &mut tracks);
        return Some(tracks)
    } else {
        println!("Failed to get entry html {}: {}", res.status, url);
        return None
    }
}

// This is not proper HTML serialization, of course.
fn walk(indent: usize, handle: Handle, tracks: &mut Vec<Track>) {
    let node = handle.borrow();
    match node.node {
        Document         => (),
        Doctype(_, _, _) => (),
        Text(_)          => (),
        Comment(_)       => (),
        Element(ref name, _, ref attrs) => {
            let tag_name = name.local.as_ref();
            let ts: Vec<Track> = extract_tracks_from_tag(tag_name, attrs);
            for track in ts.iter().cloned() {
                if !(tracks).iter().any(|t| track == *t) {
                    (*tracks).push(track)
                }
            }
        }
    }
    for child in node.children.iter() {
        walk(indent+4, child.clone(), tracks);
    }
}

fn attr(attr_name: &str, attrs: &Vec<Attribute>) -> Option<String> {
    for attr in attrs.iter() {
        if attr.name.local.as_ref() == attr_name {
            return Some(attr.value.to_string())
        }
    }
    None
}

fn extract_identifier(value: &str, regex_str: &str) -> Option<String> {
    match Regex::new(regex_str) {
        Ok(re) => match re.captures(value) {
            Some(cap) => match cap.at(1) {
                Some(str) => {
                    let strs: Vec<&str> = str.split('?').collect();
                    return Some(strs[0].to_string())
                },
                None => None
            },
            None => None
        },
        Err(_) => None
    }
}

pub fn extract_tracks_from_tag(tag_name: &str,
                               attrs: &Vec<Attribute>) -> Vec<Track> {
    if tag_name == "iframe" {
        match attr("src", attrs) {
            Some(ref src) => extract_tracks_from_url(src.to_string()),
            None => vec![]
        }
    } else if tag_name == "a" || tag_name == "link" {
        match attr("href", attrs) {
            Some(ref href) => extract_tracks_from_url(href.to_string()),
            None => vec![]
        }
    } else {
        vec![]
    }
}

fn extract_tracks_from_url(url: String) -> Vec<Track> {
    let decoded = percent_decode(url.as_bytes()).decode_utf8_lossy().into_owned();
    match extract_identifier(&decoded, YOUTUBE_EMBED) {
        Some(identifier) => {
            return vec![Track {
                        id: Uuid::new_v4(),
                  provider: Provider::YouTube,
                     title: "".to_string(),
                       url: url.to_string(),
                identifier: identifier
            }]
        },
        None => ()
    }
    match extract_identifier(&decoded, YOUTUBE_WATCH) {
        Some(identifier) => {
            return vec![Track {
                        id: Uuid::new_v4(),
                  provider: Provider::YouTube,
                     title: "".to_string(),
                       url: url.to_string(),
                identifier: identifier
            }]
        },
        None => ()
    }
    match extract_identifier(&decoded, YOUTUBE_LIST) {
        Some(identifier) => {
            return match youtube::fetch_playlist(&identifier) {
                Ok(res) => res.items.iter()
                                    .map(|ref i| Track::from_yt_playlist_item(i))
                                    .collect::<Vec<_>>(),
                Err(_)       => vec![]
            }
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_TRACK) {
        Some(identifier) => {
            return vec![Track {
                        id: Uuid::new_v4(),
                  provider: Provider::SoundCloud,
                     title: "".to_string(),
                       url: url.to_string(),
                identifier: identifier
            }]
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_PLAYLIST) {
        Some(identifier) => {
            return match soundcloud::fetch_playlist(&identifier) {
                Ok(playlist) => playlist.tracks
                                        .iter()
                                        .map(|ref t| Track::from_sc_track(t))
                                        .collect::<Vec<_>>(),
                Err(_)       => vec![]
            }
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_USER) {
        Some(identifier) => {
            print!("user {}", identifier);
            return match soundcloud::fetch_user_tracks(&identifier) {
                Ok(tracks) => tracks.iter()
                                    .map(|ref t| Track::from_sc_track(t))
                                    .collect::<Vec<_>>(),
                Err(_)     => vec![]
            }
        },
        None => ()
    }
    return vec![]
}

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

    #[test]
    fn test_extract_identifier() {
        let soundcloud_src = "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/195425494&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true";
        match extract_identifier(soundcloud_src, super::SOUNDCLOUD_TRACK) {
            Some(identifier) => assert_eq!(identifier, "195425494".to_string()),
            None             => assert!(false)
        }
        let youtube_embed = "https://www.youtube.com/embed/X8tOngmlES0?rel=0";
        match extract_identifier(youtube_embed, super::YOUTUBE_EMBED) {
            Some(identifier) => assert_eq!(identifier, "X8tOngmlES0".to_string()),
            None             => assert!(false)
        }

        let youtube_watch = "https://www.youtube.com/watch?v=oDuif301F-8";
        match extract_identifier(youtube_watch, super::YOUTUBE_WATCH) {
            Some(identifier) => assert_eq!(identifier, "oDuif301F-8".to_string()),
            None             => assert!(false)
        }

        let youtube_list = "https://www.youtube.com/embed/videoseries?list=PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX";
        match extract_identifier(youtube_list, super::YOUTUBE_LIST) {
            Some(identifier) => assert_eq!(identifier, "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string()),
            None             => assert!(false)
        }

        match extract_identifier(youtube_list, super::YOUTUBE_EMBED) {
            Some(identifier) => assert!(false),
            None             => assert!(true)
        }
    }
}
<|endoftext|>


<commit_before>extern crate git2;

use super::SubdirView;
use super::UnapplyView;
use super::View;
use super::replace_subtree;
use git2::*;
use shell::Shell;
use std::collections::HashMap;
use std::path::Path;

pub type ViewCache = HashMap<Oid, Oid>;
pub type ViewCaches = HashMap<String, ViewCache>;

// takes everything from base except it's tree and replaces it with the tree
// given
pub fn rewrite(repo: &Repository, base: &Commit, parents: &[&Commit], tree: &Tree) -> Oid
{
    let result = repo.commit(
        None,
        &base.author(),
        &base.committer(),
        &base.message().unwrap_or("no message"),
        tree,
        parents,
    ).expect("rewrite: can't commit {:?}");

    result
}

pub fn unapply_view(repo: &Repository, current: Oid, view: &View, old: Oid, new: Oid)
    -> UnapplyView
{
    if old == new {
        return UnapplyView::NoChanges;
    }

    match repo.graph_descendant_of(new, old) {
        Err(_) | Ok(false) => {
            debug!("graph_descendant_of({},{})", new, old);
            return UnapplyView::RejectNoFF;
        }
        Ok(true) => (),
    }

    debug!("==== walking commits from {} to {}", old, new);

    let walk = {
        let mut walk = repo.revwalk().expect("walk: can't create revwalk");
        walk.set_sorting(Sort::REVERSE | Sort::TOPOLOGICAL);
        let range = format!("{}..{}", old, new);
        walk.push_range(&range)
            .expect(&format!("walk: invalid range: {}", range));;
        walk.hide(old).expect("walk: can't hide");
        walk
    };

    let mut current = current;
    for rev in walk {
        let rev = rev.expect("walk: invalid rev");

        debug!("==== walking commit {}", rev);

        let module_commit = repo.find_commit(rev)
            .expect("walk: object is not actually a commit");

        if module_commit.parents().count() > 1 {
            // TODO: invectigate the possibility of allowing merge commits
            return UnapplyView::RejectMerge;
        }

        debug!("==== Rewriting commit {}", rev);

        let tree = module_commit.tree().expect("walk: commit has no tree");
        let parent = repo.find_commit(current)
            .expect("walk: current object is no commit");

        let new_tree =
            view.unapply(&repo, &tree, &parent.tree().expect("walk: parent has no tree"));

        current = rewrite(
            &repo,
            &module_commit,
            &vec![&parent],
            &repo.find_tree(new_tree).expect("can't find rewritten tree"),
        );
    }
    return UnapplyView::Done(current);
}

pub fn new(path: &Path) -> Repository
{
    Repository::init_bare(&path).expect("could not init scratch")
}

pub fn apply_view_to_branch(
    repo: &Repository,
    branchname: &str,
    view: &str,
    caches: &mut ViewCaches,
)
{
    if view == "." {
        return;
    }

    let view_cache = caches
        .entry(format!("{}--{}", &branchname, &view))
        .or_insert(ViewCache::new());

    let viewobj = SubdirView::new(&Path::new(&view));

    debug!("apply_view_to_branch {}", branchname);
    if let Ok(branch) = repo.find_branch(branchname, git2::BranchType::Local) {
        let r = branch.into_reference().target().expect("no ref");

        if let Some(view_commit) = apply_view_cached(&repo, &viewobj, r, view_cache) {
            println!("applied view to branch {}", branchname);

            let refname = format!("refs/namespaces/{}/refs/{}", &view, &branchname);
            repo.reference(&refname, view_commit, true, "apply_view")
                .expect("can't create reference");

            if branchname == "master" {

            repo.reference(&format!("refs/namespaces/{}/HEAD", &view), view_commit, true, "apply_view")
                .expect("can't create reference");
            }
        } else {
            println!("can't apply view to branch {}", branchname);
        };
    };
}

pub fn apply_view(repo: &Repository, view: &View, newrev: Oid) -> Option<Oid>
{
    return apply_view_cached(&repo, view, newrev, &mut ViewCache::new());
}

pub fn apply_view_cached(
    repo: &Repository,
    view: &View,
    newrev: Oid,
    view_cache: &mut ViewCache,
) -> Option<Oid>
{
    let walk = {
        let mut walk = repo.revwalk().expect("walk: can't create revwalk");
        walk.set_sorting(Sort::REVERSE | Sort::TOPOLOGICAL);
        walk.push(newrev).expect("walk.push");
        walk
    };

    if let Some(id) = view_cache.get(&newrev) {
        return Some(id.clone());
    }

    'walk: for commit in walk {
        let commit = repo.find_commit(commit.unwrap()).unwrap();
        if view_cache.contains_key(&commit.id()) {
            continue 'walk;
        }

        let tree = commit.tree().expect("commit has no tree");

        let new_tree = if let Some(tree_id) = view.apply(&tree) {
            repo.find_tree(tree_id)
                .expect("central_submit: can't find tree")
        } else {
            continue 'walk;
        };

        let mut parents = vec![];
        for parent in commit.parents() {
            if let Some(parent) = view_cache.get(&parent.id()){
                let parent = repo.find_commit(*parent).unwrap();
                parents.push(parent);
            };
        }

        let parent_refs: Vec<&_> = parents.iter().collect();

        if let [only_parent] = parent_refs.as_slice() {
            if new_tree.id() == only_parent.tree().unwrap().id() {
                view_cache.insert(commit.id(), only_parent.id());
                continue 'walk;
            }
        }
        view_cache.insert(commit.id(), rewrite(&repo, &commit, &parent_refs, &new_tree));
    }

    return view_cache.get(&newrev).map(|&id| id);
}

pub fn join_to_subdir(
    repo: &Repository,
    path: &Path,
    src: Oid,
) -> (Oid, Oid)
{
    let src = repo.find_commit(src).unwrap();

    let walk = {
        let mut walk = repo.revwalk().expect("walk: can't create revwalk");
        walk.set_sorting(Sort::REVERSE | Sort::TOPOLOGICAL);
        walk.push(src.id()).expect("walk.push");
        walk
    };

    let empty = repo.find_tree(repo.treebuilder(None).unwrap().write().unwrap())
        .unwrap();
    let mut map = HashMap::<Oid, Oid>::new();

    'walk: for commit in walk {
        let commit = repo.find_commit(commit.unwrap()).unwrap();
        let tree = commit.tree().expect("commit has no tree");
        let new_tree = repo.find_tree(replace_subtree(&repo, path, &tree, &empty))
            .expect("can't find tree");

        let mut parents = vec![];
        for parent in commit.parents() {
            let parent = map.get(&parent.id()).unwrap();
            let parent = repo.find_commit(*parent).unwrap();
            parents.push(parent);
        }

        let parent_refs: Vec<&_> = parents.iter().collect();
        map.insert(commit.id(), rewrite(&repo, &commit, &parent_refs, &new_tree));
    }

    let in_subdir = repo.find_commit(map[&src.id()]).unwrap();
    return (in_subdir.id(), in_subdir.id());
}
<commit_msg>Fix refname<commit_after>extern crate git2;

use super::SubdirView;
use super::UnapplyView;
use super::View;
use super::replace_subtree;
use git2::*;
use shell::Shell;
use std::collections::HashMap;
use std::path::Path;

pub type ViewCache = HashMap<Oid, Oid>;
pub type ViewCaches = HashMap<String, ViewCache>;

// takes everything from base except it's tree and replaces it with the tree
// given
pub fn rewrite(repo: &Repository, base: &Commit, parents: &[&Commit], tree: &Tree) -> Oid
{
    let result = repo.commit(
        None,
        &base.author(),
        &base.committer(),
        &base.message().unwrap_or("no message"),
        tree,
        parents,
    ).expect("rewrite: can't commit {:?}");

    result
}

pub fn unapply_view(repo: &Repository, current: Oid, view: &View, old: Oid, new: Oid)
    -> UnapplyView
{
    if old == new {
        return UnapplyView::NoChanges;
    }

    match repo.graph_descendant_of(new, old) {
        Err(_) | Ok(false) => {
            debug!("graph_descendant_of({},{})", new, old);
            return UnapplyView::RejectNoFF;
        }
        Ok(true) => (),
    }

    debug!("==== walking commits from {} to {}", old, new);

    let walk = {
        let mut walk = repo.revwalk().expect("walk: can't create revwalk");
        walk.set_sorting(Sort::REVERSE | Sort::TOPOLOGICAL);
        let range = format!("{}..{}", old, new);
        walk.push_range(&range)
            .expect(&format!("walk: invalid range: {}", range));;
        walk.hide(old).expect("walk: can't hide");
        walk
    };

    let mut current = current;
    for rev in walk {
        let rev = rev.expect("walk: invalid rev");

        debug!("==== walking commit {}", rev);

        let module_commit = repo.find_commit(rev)
            .expect("walk: object is not actually a commit");

        if module_commit.parents().count() > 1 {
            // TODO: invectigate the possibility of allowing merge commits
            return UnapplyView::RejectMerge;
        }

        debug!("==== Rewriting commit {}", rev);

        let tree = module_commit.tree().expect("walk: commit has no tree");
        let parent = repo.find_commit(current)
            .expect("walk: current object is no commit");

        let new_tree =
            view.unapply(&repo, &tree, &parent.tree().expect("walk: parent has no tree"));

        current = rewrite(
            &repo,
            &module_commit,
            &vec![&parent],
            &repo.find_tree(new_tree).expect("can't find rewritten tree"),
        );
    }
    return UnapplyView::Done(current);
}

pub fn new(path: &Path) -> Repository
{
    Repository::init_bare(&path).expect("could not init scratch")
}

pub fn apply_view_to_branch(
    repo: &Repository,
    branchname: &str,
    view: &str,
    caches: &mut ViewCaches,
)
{
    if view == "." {
        return;
    }

    let view_cache = caches
        .entry(format!("{}--{}", &branchname, &view))
        .or_insert(ViewCache::new());

    let viewobj = SubdirView::new(&Path::new(&view));

    debug!("apply_view_to_branch {}", branchname);
    if let Ok(branch) = repo.find_branch(branchname, git2::BranchType::Local) {
        let r = branch.into_reference().target().expect("no ref");

        if let Some(view_commit) = apply_view_cached(&repo, &viewobj, r, view_cache) {
            println!("applied view to branch {}", branchname);

            let refname = format!("refs/namespaces/{}/refs/heads/{}", &view, &branchname);
            repo.reference(&refname, view_commit, true, "apply_view")
                .expect("can't create reference");

            if branchname == "master" {

            repo.reference(&format!("refs/namespaces/{}/HEAD", &view), view_commit, true, "apply_view")
                .expect("can't create reference");
            }
        } else {
            println!("can't apply view to branch {}", branchname);
        };
    };
}

pub fn apply_view(repo: &Repository, view: &View, newrev: Oid) -> Option<Oid>
{
    return apply_view_cached(&repo, view, newrev, &mut ViewCache::new());
}

pub fn apply_view_cached(
    repo: &Repository,
    view: &View,
    newrev: Oid,
    view_cache: &mut ViewCache,
) -> Option<Oid>
{
    let walk = {
        let mut walk = repo.revwalk().expect("walk: can't create revwalk");
        walk.set_sorting(Sort::REVERSE | Sort::TOPOLOGICAL);
        walk.push(newrev).expect("walk.push");
        walk
    };

    if let Some(id) = view_cache.get(&newrev) {
        return Some(id.clone());
    }

    'walk: for commit in walk {
        let commit = repo.find_commit(commit.unwrap()).unwrap();
        if view_cache.contains_key(&commit.id()) {
            continue 'walk;
        }

        let tree = commit.tree().expect("commit has no tree");

        let new_tree = if let Some(tree_id) = view.apply(&tree) {
            repo.find_tree(tree_id)
                .expect("central_submit: can't find tree")
        } else {
            continue 'walk;
        };

        let mut parents = vec![];
        for parent in commit.parents() {
            if let Some(parent) = view_cache.get(&parent.id()){
                let parent = repo.find_commit(*parent).unwrap();
                parents.push(parent);
            };
        }

        let parent_refs: Vec<&_> = parents.iter().collect();

        if let [only_parent] = parent_refs.as_slice() {
            if new_tree.id() == only_parent.tree().unwrap().id() {
                view_cache.insert(commit.id(), only_parent.id());
                continue 'walk;
            }
        }
        view_cache.insert(commit.id(), rewrite(&repo, &commit, &parent_refs, &new_tree));
    }

    return view_cache.get(&newrev).map(|&id| id);
}

pub fn join_to_subdir(
    repo: &Repository,
    path: &Path,
    src: Oid,
) -> (Oid, Oid)
{
    let src = repo.find_commit(src).unwrap();

    let walk = {
        let mut walk = repo.revwalk().expect("walk: can't create revwalk");
        walk.set_sorting(Sort::REVERSE | Sort::TOPOLOGICAL);
        walk.push(src.id()).expect("walk.push");
        walk
    };

    let empty = repo.find_tree(repo.treebuilder(None).unwrap().write().unwrap())
        .unwrap();
    let mut map = HashMap::<Oid, Oid>::new();

    'walk: for commit in walk {
        let commit = repo.find_commit(commit.unwrap()).unwrap();
        let tree = commit.tree().expect("commit has no tree");
        let new_tree = repo.find_tree(replace_subtree(&repo, path, &tree, &empty))
            .expect("can't find tree");

        let mut parents = vec![];
        for parent in commit.parents() {
            let parent = map.get(&parent.id()).unwrap();
            let parent = repo.find_commit(*parent).unwrap();
            parents.push(parent);
        }

        let parent_refs: Vec<&_> = parents.iter().collect();
        map.insert(commit.id(), rewrite(&repo, &commit, &parent_refs, &new_tree));
    }

    let in_subdir = repo.find_commit(map[&src.id()]).unwrap();
    return (in_subdir.id(), in_subdir.id());
}
<|endoftext|>


<commit_before>/*
 * partially (c) 2016 Google Inc. (Lewin Bormann, lewinb@google.com)
 *
 * See project root for licensing information.
 */

extern crate serde_json;

use std::collections::HashMap;
use std::hash::Hasher;
use std::error::Error;
use std::fmt;
use std::fs;
use std::io;
use std::io::{Read, Write};

use common::Token;

/// Implements a specialized storage to set and retrieve `Token` instances.
/// The `scope_hash` represents the signature of the scopes for which the given token
/// should be stored or retrieved.
/// For completeness, the underlying, sorted scopes are provided as well. They might be
/// useful for presentation to the user.
pub trait TokenStorage {
    type Error: 'static + Error;

    /// If `token` is None, it is invalid or revoked and should be removed from storage.
    /// Otherwise, it should be saved.
    fn set(&mut self,
           scope_hash: u64,
           scopes: &Vec<&str>,
           token: Option<Token>)
           -> Result<(), Self::Error>;
    /// A `None` result indicates that there is no token for the given scope_hash.
    fn get(&self, scope_hash: u64, scopes: &Vec<&str>) -> Result<Option<Token>, Self::Error>;
}

/// A storage that remembers nothing.
#[derive(Default)]
pub struct NullStorage;
#[derive(Debug)]
pub struct NullError;

impl Error for NullError {
    fn description(&self) -> &str {
        "NULL"
    }
}

impl fmt::Display for NullError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        "NULL-ERROR".fmt(f)
    }
}

impl TokenStorage for NullStorage {
    type Error = NullError;
    fn set(&mut self, _: u64, _: &Vec<&str>, _: Option<Token>) -> Result<(), NullError> {
        Ok(())
    }
    fn get(&self, _: u64, _: &Vec<&str>) -> Result<Option<Token>, NullError> {
        Ok(None)
    }
}

/// A storage that remembers values for one session only.
#[derive(Default)]
pub struct MemoryStorage {
    pub tokens: HashMap<u64, Token>,
}

impl TokenStorage for MemoryStorage {
    type Error = NullError;

    fn set(&mut self,
           scope_hash: u64,
           _: &Vec<&str>,
           token: Option<Token>)
           -> Result<(), NullError> {
        match token {
            Some(t) => self.tokens.insert(scope_hash, t),
            None => self.tokens.remove(&scope_hash),
        };
        Ok(())
    }

    fn get(&self, scope_hash: u64, _: &Vec<&str>) -> Result<Option<Token>, NullError> {
        match self.tokens.get(&scope_hash) {
            Some(t) => Ok(Some(t.clone())),
            None => Ok(None),
        }
    }
}

/// A single stored token.
#[derive(Serialize, Deserialize)]
struct JSONToken {
    pub hash: u64,
    pub token: Token,
}

/// List of tokens in a JSON object
#[derive(Serialize, Deserialize)]
struct JSONTokens {
    pub tokens: Vec<JSONToken>,
}

/// Serializes tokens to a JSON file on disk.
#[derive(Default)]
pub struct DiskTokenStorage {
    location: String,
    tokens: HashMap<u64, Token>,
}

impl DiskTokenStorage {
    pub fn new(location: &String) -> DiskTokenStorage {
        use std::fs;
        let mut dts = DiskTokenStorage {
            location: location.clone(),
            tokens: HashMap::new(),
        };

        // best-effort
        let _ = dts.load_from_file();
        dts
    }

    fn load_from_file(&mut self) -> Result<(), io::Error> {
        let mut f = try!(fs::OpenOptions::new().read(true).open(&self.location));
        let mut contents = String::new();

        match f.read_to_string(&mut contents) {
            Result::Err(e) => return Result::Err(e),
            Result::Ok(_sz) => (),
        }

        let tokens: JSONTokens;

        match serde_json::from_str(&contents) {
            Result::Err(e) => return Result::Err(io::Error::new(io::ErrorKind::InvalidData, e)),
            Result::Ok(t) => tokens = t,
        }

        for t in tokens.tokens {
            self.tokens.insert(t.hash, t.token);
        }
        return Result::Ok(());
    }

    pub fn dump_to_file(&mut self) -> Result<(), io::Error> {
        let mut jsontokens = JSONTokens { tokens: Vec::new() };

        for (hash, token) in self.tokens.iter() {
            jsontokens.tokens.push(JSONToken {
                hash: *hash,
                token: token.clone(),
            });
        }

        let serialized;;

        match serde_json::to_string(&jsontokens) {
            Result::Err(e) => return Result::Err(io::Error::new(io::ErrorKind::InvalidData, e)),
            Result::Ok(s) => serialized = s,
        }

        let mut f = try!(fs::OpenOptions::new()
                             .create(true)
                             .write(true)
                             .truncate(true)
                             .open(&self.location));
        f.write(serialized.as_ref()).map(|_| ())
    }
}

impl TokenStorage for DiskTokenStorage {
    type Error = io::Error;
    fn set(&mut self,
           scope_hash: u64,
           _: &Vec<&str>,
           token: Option<Token>)
           -> Result<(), Self::Error> {
        match token {
            None => {
                self.tokens.remove(&scope_hash);
                ()
            }
            Some(t) => {
                self.tokens.insert(scope_hash, t.clone());
                ()
            }
        }
        self.dump_to_file()
    }
    fn get(&self, scope_hash: u64, _: &Vec<&str>) -> Result<Option<Token>, Self::Error> {
        Result::Ok(self.tokens.get(&scope_hash).map(|tok| tok.clone()))
    }
}
<commit_msg>fix(DiskTokenStorage): make DiskTokenStorage::new() return a Result<><commit_after>/*
 * partially (c) 2016 Google Inc. (Lewin Bormann, lewinb@google.com)
 *
 * See project root for licensing information.
 */

extern crate serde_json;

use std::collections::HashMap;
use std::hash::Hasher;
use std::error::Error;
use std::fmt;
use std::fs;
use std::io;
use std::io::{Read, Write};

use common::Token;

/// Implements a specialized storage to set and retrieve `Token` instances.
/// The `scope_hash` represents the signature of the scopes for which the given token
/// should be stored or retrieved.
/// For completeness, the underlying, sorted scopes are provided as well. They might be
/// useful for presentation to the user.
pub trait TokenStorage {
    type Error: 'static + Error;

    /// If `token` is None, it is invalid or revoked and should be removed from storage.
    /// Otherwise, it should be saved.
    fn set(&mut self,
           scope_hash: u64,
           scopes: &Vec<&str>,
           token: Option<Token>)
           -> Result<(), Self::Error>;
    /// A `None` result indicates that there is no token for the given scope_hash.
    fn get(&self, scope_hash: u64, scopes: &Vec<&str>) -> Result<Option<Token>, Self::Error>;
}

/// A storage that remembers nothing.
#[derive(Default)]
pub struct NullStorage;
#[derive(Debug)]
pub struct NullError;

impl Error for NullError {
    fn description(&self) -> &str {
        "NULL"
    }
}

impl fmt::Display for NullError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        "NULL-ERROR".fmt(f)
    }
}

impl TokenStorage for NullStorage {
    type Error = NullError;
    fn set(&mut self, _: u64, _: &Vec<&str>, _: Option<Token>) -> Result<(), NullError> {
        Ok(())
    }
    fn get(&self, _: u64, _: &Vec<&str>) -> Result<Option<Token>, NullError> {
        Ok(None)
    }
}

/// A storage that remembers values for one session only.
#[derive(Default)]
pub struct MemoryStorage {
    pub tokens: HashMap<u64, Token>,
}

impl TokenStorage for MemoryStorage {
    type Error = NullError;

    fn set(&mut self,
           scope_hash: u64,
           _: &Vec<&str>,
           token: Option<Token>)
           -> Result<(), NullError> {
        match token {
            Some(t) => self.tokens.insert(scope_hash, t),
            None => self.tokens.remove(&scope_hash),
        };
        Ok(())
    }

    fn get(&self, scope_hash: u64, _: &Vec<&str>) -> Result<Option<Token>, NullError> {
        match self.tokens.get(&scope_hash) {
            Some(t) => Ok(Some(t.clone())),
            None => Ok(None),
        }
    }
}

/// A single stored token.
#[derive(Serialize, Deserialize)]
struct JSONToken {
    pub hash: u64,
    pub token: Token,
}

/// List of tokens in a JSON object
#[derive(Serialize, Deserialize)]
struct JSONTokens {
    pub tokens: Vec<JSONToken>,
}

/// Serializes tokens to a JSON file on disk.
#[derive(Default)]
pub struct DiskTokenStorage {
    location: String,
    tokens: HashMap<u64, Token>,
}

impl DiskTokenStorage {
    pub fn new(location: &String) -> Result<DiskTokenStorage, io::Error> {
        use std::fs;
        let mut dts = DiskTokenStorage {
            location: location.clone(),
            tokens: HashMap::new(),
        };

        // best-effort
        let read_result = dts.load_from_file();

        match read_result {
            Result::Ok(()) => Result::Ok(dts),
            Result::Err(e) => {
                match e.kind() {
                    io::ErrorKind::NotFound => Result::Ok(dts), // File not found; ignore and create new one
                    _ => Result::Err(e), // e.g. PermissionDenied
                }
            }
        }
    }

    fn load_from_file(&mut self) -> Result<(), io::Error> {
        let mut f = try!(fs::OpenOptions::new().read(true).open(&self.location));
        let mut contents = String::new();

        match f.read_to_string(&mut contents) {
            Result::Err(e) => return Result::Err(e),
            Result::Ok(_sz) => (),
        }

        let tokens: JSONTokens;

        match serde_json::from_str(&contents) {
            Result::Err(e) => return Result::Err(io::Error::new(io::ErrorKind::InvalidData, e)),
            Result::Ok(t) => tokens = t,
        }

        for t in tokens.tokens {
            self.tokens.insert(t.hash, t.token);
        }
        return Result::Ok(());
    }

    pub fn dump_to_file(&mut self) -> Result<(), io::Error> {
        let mut jsontokens = JSONTokens { tokens: Vec::new() };

        for (hash, token) in self.tokens.iter() {
            jsontokens.tokens.push(JSONToken {
                hash: *hash,
                token: token.clone(),
            });
        }

        let serialized;;

        match serde_json::to_string(&jsontokens) {
            Result::Err(e) => return Result::Err(io::Error::new(io::ErrorKind::InvalidData, e)),
            Result::Ok(s) => serialized = s,
        }

        let mut f = try!(fs::OpenOptions::new()
                             .create(true)
                             .write(true)
                             .truncate(true)
                             .open(&self.location));
        f.write(serialized.as_ref()).map(|_| ())
    }
}

impl TokenStorage for DiskTokenStorage {
    type Error = io::Error;
    fn set(&mut self,
           scope_hash: u64,
           _: &Vec<&str>,
           token: Option<Token>)
           -> Result<(), Self::Error> {
        match token {
            None => {
                self.tokens.remove(&scope_hash);
                ()
            }
            Some(t) => {
                self.tokens.insert(scope_hash, t.clone());
                ()
            }
        }
        self.dump_to_file()
    }
    fn get(&self, scope_hash: u64, _: &Vec<&str>) -> Result<Option<Token>, Self::Error> {
        Result::Ok(self.tokens.get(&scope_hash).map(|tok| tok.clone()))
    }
}
<|endoftext|>


<commit_before>use serde_json;
use reqwest;
use std;
use std::fs::File;
use std::io::Read;
use toml;

#[derive(Deserialize, Debug, Clone)]
pub struct Config {
    pub token: String,
    pub org: String,
    pub team: String,
    #[serde(default = "default_endpoint")]
    pub endpoint: String,
    #[serde(default = "default_home")]
    pub home: String,
    #[serde(default = "default_gid")]
    pub gid: u64,
    #[serde(default = "default_sh")]
    pub sh: String,
    pub group: Option<String>,
    #[serde(default = "default_cache_duration")]
    pub cache_duration: u64,
    #[serde(default = "default_cert_path")]
    pub cert_path: String,
}

fn default_endpoint() -> String { String::from("https://api.github.com") }
fn default_home() -> String { String::from("/home/{}") }
fn default_gid() -> u64 { 2000 }
fn default_sh() -> String { String::from("/bin/bash") }
fn default_cache_duration() -> u64 { 3600 }
fn default_cert_path() -> String { String::from("/etc/ssl/certs/ca-certificates.crt") }

impl Config {
    pub fn new(configpath: &str) -> Result<Self, std::io::Error> {
        let mut file = File::open(configpath)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(toml::from_str::<Config>(contents.as_str()).unwrap())
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Team {
    pub id: u64,
    pub name: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Member {
    pub id: u64,
    pub login: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PublicKey {
    pub id: u64,
    pub key: String,
}

#[derive(Debug)]
pub enum CliError {
    Serde(serde_json::Error),
    Reqwest(reqwest::Error),
    Io(std::io::Error),
}

impl From<serde_json::Error> for CliError {
    fn from(err: serde_json::Error) -> CliError { CliError::Serde(err) }
}
impl From<reqwest::Error> for CliError {
    fn from(err: reqwest::Error) -> CliError { CliError::Reqwest(err) }
}
impl From<std::io::Error> for CliError {
    fn from(err: std::io::Error) -> CliError { CliError::Io(err) }
}
<commit_msg>Handle the toml error as part of CliError<commit_after>use serde_json;
use reqwest;
use std;
use std::fs::File;
use std::io::Read;
use toml;

#[derive(Deserialize, Debug, Clone)]
pub struct Config {
    pub token: String,
    pub org: String,
    pub team: String,
    #[serde(default = "default_endpoint")]
    pub endpoint: String,
    #[serde(default = "default_home")]
    pub home: String,
    #[serde(default = "default_gid")]
    pub gid: u64,
    #[serde(default = "default_sh")]
    pub sh: String,
    pub group: Option<String>,
    #[serde(default = "default_cache_duration")]
    pub cache_duration: u64,
    #[serde(default = "default_cert_path")]
    pub cert_path: String,
}

fn default_endpoint() -> String { String::from("https://api.github.com") }
fn default_home() -> String { String::from("/home/{}") }
fn default_gid() -> u64 { 2000 }
fn default_sh() -> String { String::from("/bin/bash") }
fn default_cache_duration() -> u64 { 3600 }
fn default_cert_path() -> String { String::from("/etc/ssl/certs/ca-certificates.crt") }

impl Config {
    pub fn new(configpath: &str) -> Result<Self, CliError> {
        let mut file = File::open(configpath)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(toml::from_str::<Config>(contents.as_str())?)
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Team {
    pub id: u64,
    pub name: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Member {
    pub id: u64,
    pub login: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PublicKey {
    pub id: u64,
    pub key: String,
}

#[derive(Debug)]
pub enum CliError {
    Serde(serde_json::Error),
    Reqwest(reqwest::Error),
    Io(std::io::Error),
    Toml(toml::de::Error),
}

impl From<serde_json::Error> for CliError {
    fn from(err: serde_json::Error) -> CliError { CliError::Serde(err) }
}
impl From<reqwest::Error> for CliError {
    fn from(err: reqwest::Error) -> CliError { CliError::Reqwest(err) }
}
impl From<std::io::Error> for CliError {
    fn from(err: std::io::Error) -> CliError { CliError::Io(err) }
}
impl From<toml::de::Error> for CliError {
    fn from(err: toml::de::Error) -> CliError { CliError::Toml(err) }
}
<|endoftext|>


<commit_before>//! Various APRS data types
//!
//! Data is broken down into objects depending on its purpose. See each struct definition for its
//! description.

use constants;
use functions;
use geo_util;

pub struct Frame {
    pub source: Callsign,
    pub destination: Callsign,
    pub path: Vec<Callsign>,
    pub info: InformationField,
}

impl Frame {
    pub fn new() -> Frame {
        Frame {
            source: Callsign::new(),
            destination: Callsign::new(),
            path: Vec::new(),
            info: InformationField::new()
        }
    }
}

impl Frame {
    pub fn set_source(&mut self, source: &[u8]) {
        self.source = functions::parse_callsign(source);
    }
    pub fn set_destination(&mut self, dest: &[u8]) {
        self.destination = functions::parse_callsign(dest);
    }
    pub fn set_path(&mut self, path: Vec<Vec<u8>>) {
        for pth in path {
            let byts: &[u8] = pth.as_slice();
            self.path.push(functions::parse_callsign(byts));
        }
    }
    pub fn set_info(&mut self, info: &[u8]) {
        self.info = functions::parse_info_field(info);
    }
    pub fn encode_ax25(&self) -> Vec<u8> {
        // TODO: find a way to return raw bytes
        let mut encoded_frame: Vec<u8> = Vec::new();
        encoded_frame.push(constants::AX25_FLAG);
        encoded_frame.extend(self.destination.encode_ax25());
        encoded_frame.extend(self.source.encode_ax25());
        for path_call in self.path.iter() {
            encoded_frame.extend(path_call.encode_ax25());
        }
        encoded_frame.extend(self.info.data.as_slice());
        encoded_frame
    }
}

pub struct PositionFrame {
    pub source: Callsign,
    pub destination: Callsign,
    pub path: Vec<Callsign>,
    pub info: InformationField,
    pub comment: Vec<u8>,
    pub table: Vec<u8>,
    pub symbol: u8,
    pub lat: f32,
    pub lng: f32,
    pub ambiguity: usize
}

impl PositionFrame {
    pub fn new() -> PositionFrame {
        PositionFrame {
            source: Callsign::new(),
            destination: Callsign::new(),
            path: Vec::new(),
            info: InformationField::new(),
            comment: Vec::new(),
            table: Vec::new(),
            symbol: 0,
            lat: 0.0,
            lng: 0.0,
            ambiguity: 0
        }
    }
}

impl PositionFrame {
    pub fn set_source(&mut self, source: &[u8]) {
        self.source = functions::parse_callsign(source);
    }
    pub fn set_destination(&mut self, dest: &[u8]) {
        self.destination = functions::parse_callsign(dest);
    }
    pub fn set_path(&mut self, path: Vec<Vec<u8>>) {
        for pth in path {
            let byts: &[u8] = pth.as_slice();
            self.path.push(functions::parse_callsign(byts));
        }
    }
    pub fn update_info(&mut self) {
        self.info = functions::parse_info_field(&self.create_info_field());
    }
    pub fn create_info_field(&self) -> Vec<u8> {
        let lat     = geo_util::dec2dm_lat(self.lat);
        let lat_enc = geo_util::ambiguate(&lat, self.ambiguity);
        let lng     = geo_util::dec2dm_lng(self.lng);
        let lng_enc = geo_util::ambiguate(&lng, self.ambiguity);

        let mut frame: Vec<u8> = Vec::new();
        frame.push(b'=');
        frame.extend(lat_enc.as_bytes());
        frame.extend(&self.table);
        frame.extend(lng_enc.as_bytes());
        frame.push(self.symbol);
        frame.extend(&self.comment);

        frame
    }
}

pub struct Callsign {
    pub callsign: String,
    pub ssid: u8,
    pub digi: bool,
}

impl Callsign {
    pub fn new() -> Callsign {
        Callsign {
            callsign: String::new(),
            ssid: 0,
            digi: false,
        }
    }
}

impl Callsign {
    pub fn set_callsign(&mut self, callsign: String) {
        self.callsign = callsign;
        // self.callsign = String::from_utf8(callsign.to_vec()).unwrap();
    }
    pub fn set_ssid(&mut self, ssid: u8) {
        self.ssid = ssid;
    }
    pub fn set_digi(&mut self, digi: bool) {
        self.digi = digi;
    }
    pub fn encode_ax25(&self) -> Vec<u8> {
        // TODO: find a way to return raw bytes
        let mut encoded_callsign: Vec<u8> = Vec::new();
        let mut encoded_ssid = (self.ssid << 1) | 0x60;
        let mut _callsign: String = String::new();

        if self.digi {
            encoded_ssid = encoded_ssid | 0x80;
        }
        for chr in self.callsign.chars() {
            _callsign.push(chr);
        }
        while _callsign.len() < 6 {
            _callsign.push(' ');
        }
        for byt in _callsign.bytes() {
            encoded_callsign.push(byt << 1);
        }
        encoded_callsign.push(encoded_ssid);

        encoded_callsign
    }
}

pub struct InformationField {
    pub data: Vec<u8>,
    pub data_type: String,
    pub safe: bool,
}

impl InformationField {
    pub fn new() -> InformationField {
        InformationField {
            data: Vec::new(),
            data_type: String::new(),
            safe: false
        }
    }
}

impl InformationField {
    pub fn set_data(&mut self, raw_data: &[u8]) {
        self.data = raw_data.to_vec();
    }
    pub fn set_data_type(&mut self, data_type: &str) {
        self.data_type = data_type.to_string();
    }
    pub fn set_safe(&mut self, safe: bool) {
        self.safe = safe;
    }
}

pub struct APRS;

pub struct TCP;

pub struct UDP;

pub struct HTTP;
<commit_msg>Complete structs with FCS implementation.<commit_after>//! Various APRS data types
//!
//! Data is broken down into objects depending on its purpose. See each struct definition for its
//! description.

use constants;
use functions;
use geo_util;
use fcs::FCS;

pub struct Frame {
    pub source: Callsign,
    pub destination: Callsign,
    pub path: Vec<Callsign>,
    pub info: InformationField,
}

impl Frame {
    pub fn new() -> Frame {
        Frame {
            source: Callsign::new(),
            destination: Callsign::new(),
            path: Vec::new(),
            info: InformationField::new()
        }
    }
}

impl Frame {
    pub fn set_source(&mut self, source: &[u8]) {
        self.source = functions::parse_callsign(source);
    }
    pub fn set_destination(&mut self, dest: &[u8]) {
        self.destination = functions::parse_callsign(dest);
    }
    pub fn set_path(&mut self, path: Vec<Vec<u8>>) {
        for pth in path {
            let byts: &[u8] = pth.as_slice();
            self.path.push(functions::parse_callsign(byts));
        }
    }
    pub fn set_info(&mut self, info: &[u8]) {
        self.info = functions::parse_info_field(info);
    }
    pub fn encode_ax25(&self) -> Vec<u8> {
        let mut encoded_frame: Vec<u8> = Vec::new();
        encoded_frame.push(constants::AX25_FLAG);
        encoded_frame.extend(self.destination.encode_ax25());
        encoded_frame.extend(self.source.encode_ax25());
        for path_call in self.path.iter() {
            encoded_frame.extend(path_call.encode_ax25());
        }
        encoded_frame.extend(self.info.data.as_slice());

        let mut fcs: FCS = FCS::new();
        fcs.update_bytes(&encoded_frame);

        encoded_frame.extend(fcs.digest());
        encoded_frame.push(constants::AX25_FLAG);

        encoded_frame
    }
}

pub struct PositionFrame {
    pub source: Callsign,
    pub destination: Callsign,
    pub path: Vec<Callsign>,
    pub info: InformationField,
    pub comment: Vec<u8>,
    pub table: Vec<u8>,
    pub symbol: u8,
    pub lat: f32,
    pub lng: f32,
    pub ambiguity: usize
}

impl PositionFrame {
    pub fn new() -> PositionFrame {
        PositionFrame {
            source: Callsign::new(),
            destination: Callsign::new(),
            path: Vec::new(),
            info: InformationField::new(),
            comment: Vec::new(),
            table: Vec::new(),
            symbol: 0,
            lat: 0.0,
            lng: 0.0,
            ambiguity: 0
        }
    }
}

impl PositionFrame {
    pub fn set_source(&mut self, source: &[u8]) {
        self.source = functions::parse_callsign(source);
    }
    pub fn set_destination(&mut self, dest: &[u8]) {
        self.destination = functions::parse_callsign(dest);
    }
    pub fn set_path(&mut self, path: Vec<Vec<u8>>) {
        for pth in path {
            let byts: &[u8] = pth.as_slice();
            self.path.push(functions::parse_callsign(byts));
        }
    }
    pub fn update_info(&mut self) {
        self.info = functions::parse_info_field(&self.create_info_field());
    }
    pub fn create_info_field(&self) -> Vec<u8> {
        let lat     = geo_util::dec2dm_lat(self.lat);
        let lat_enc = geo_util::ambiguate(&lat, self.ambiguity);
        let lng     = geo_util::dec2dm_lng(self.lng);
        let lng_enc = geo_util::ambiguate(&lng, self.ambiguity);

        let mut frame: Vec<u8> = Vec::new();
        frame.push(b'=');
        frame.extend(lat_enc.as_bytes());
        frame.extend(&self.table);
        frame.extend(lng_enc.as_bytes());
        frame.push(self.symbol);
        frame.extend(&self.comment);

        frame
    }
}

pub struct Callsign {
    pub callsign: String,
    pub ssid: u8,
    pub digi: bool,
}

impl Callsign {
    pub fn new() -> Callsign {
        Callsign {
            callsign: String::new(),
            ssid: 0,
            digi: false,
        }
    }
}

impl Callsign {
    pub fn set_callsign(&mut self, callsign: String) {
        self.callsign = callsign;
        // self.callsign = String::from_utf8(callsign.to_vec()).unwrap();
    }
    pub fn set_ssid(&mut self, ssid: u8) {
        self.ssid = ssid;
    }
    pub fn set_digi(&mut self, digi: bool) {
        self.digi = digi;
    }
    pub fn encode_ax25(&self) -> Vec<u8> {
        // TODO: find a way to return raw bytes
        let mut encoded_callsign: Vec<u8> = Vec::new();
        let mut encoded_ssid = (self.ssid << 1) | 0x60;
        let mut _callsign: String = String::new();

        if self.digi {
            encoded_ssid = encoded_ssid | 0x80;
        }
        for chr in self.callsign.chars() {
            _callsign.push(chr);
        }
        while _callsign.len() < 6 {
            _callsign.push(' ');
        }
        for byt in _callsign.bytes() {
            encoded_callsign.push(byt << 1);
        }
        encoded_callsign.push(encoded_ssid);

        encoded_callsign
    }
}

pub struct InformationField {
    pub data: Vec<u8>,
    pub data_type: String,
    pub safe: bool,
}

impl InformationField {
    pub fn new() -> InformationField {
        InformationField {
            data: Vec::new(),
            data_type: String::new(),
            safe: false
        }
    }
}

impl InformationField {
    pub fn set_data(&mut self, raw_data: &[u8]) {
        self.data = raw_data.to_vec();
    }
    pub fn set_data_type(&mut self, data_type: &str) {
        self.data_type = data_type.to_string();
    }
    pub fn set_safe(&mut self, safe: bool) {
        self.safe = safe;
    }
}

pub struct APRS;

pub struct TCP;

pub struct UDP;

pub struct HTTP;
<|endoftext|>


<commit_before>pub mod block {
    pub const FULL: &str = "█";
    pub const SEVEN_EIGHTHS: &str = "▉";
    pub const THREE_QUATERS: &str = "▊";
    pub const FIVE_EIGHTHS: &str = "▋";
    pub const HALF: &str = "▌";
    pub const THREE_EIGHTHS: &str = "▍";
    pub const ONE_QUATER: &str = "▎";
    pub const ONE_EIGHTH: &str = "▏";
}

pub mod bar {
    pub const FULL: &str = "█";
    pub const SEVEN_EIGHTHS: &str = "▇";
    pub const THREE_QUATERS: &str = "▆";
    pub const FIVE_EIGHTHS: &str = "▅";
    pub const HALF: &str = "▄";
    pub const THREE_EIGHTHS: &str = "▃";
    pub const ONE_QUATER: &str = "▂";
    pub const ONE_EIGHTH: &str = "▁";
}

pub mod line {
    pub const TOP_RIGHT: &str = "┐";
    pub const VERTICAL: &str = "│";
    pub const HORIZONTAL: &str = "─";
    pub const TOP_LEFT: &str = "┌";
    pub const BOTTOM_RIGHT: &str = "┘";
    pub const BOTTOM_LEFT: &str = "└";
    pub const VERTICAL_LEFT: &str = "┤";
    pub const VERTICAL_RIGHT: &str = "├";
    pub const HORIZONTAL_DOWN: &str = "┬";
    pub const HORIZONTAL_UP: &str = "┴";
}

pub const DOT: &str = "•";
<commit_msg>fixed typo in symbols.rs<commit_after>pub mod block {
    pub const FULL: &str = "█";
    pub const SEVEN_EIGHTHS: &str = "▉";
    pub const THREE_QUARTERS: &str = "▊";
    pub const FIVE_EIGHTHS: &str = "▋";
    pub const HALF: &str = "▌";
    pub const THREE_EIGHTHS: &str = "▍";
    pub const ONE_QUARTER: &str = "▎";
    pub const ONE_EIGHTH: &str = "▏";
}

pub mod bar {
    pub const FULL: &str = "█";
    pub const SEVEN_EIGHTHS: &str = "▇";
    pub const THREE_QUARTERS: &str = "▆";
    pub const FIVE_EIGHTHS: &str = "▅";
    pub const HALF: &str = "▄";
    pub const THREE_EIGHTHS: &str = "▃";
    pub const ONE_QUARTER: &str = "▂";
    pub const ONE_EIGHTH: &str = "▁";
}

pub mod line {
    pub const TOP_RIGHT: &str = "┐";
    pub const VERTICAL: &str = "│";
    pub const HORIZONTAL: &str = "─";
    pub const TOP_LEFT: &str = "┌";
    pub const BOTTOM_RIGHT: &str = "┘";
    pub const BOTTOM_LEFT: &str = "└";
    pub const VERTICAL_LEFT: &str = "┤";
    pub const VERTICAL_RIGHT: &str = "├";
    pub const HORIZONTAL_DOWN: &str = "┬";
    pub const HORIZONTAL_UP: &str = "┴";
}

pub const DOT: &str = "•";
<|endoftext|>


<commit_before>
use std::vec::Vec;

pub enum TagTree<Leaf, Node, Edge> {
    Leaf(Leaf),
    Node(Node, Vec<(Edge, Box<TagTree<Leaf, Node, Edge>>)>)
}

impl<Leaf, Node, Edge> TagTree<Leaf, Node, Edge> {

    pub fn fold_tag_tree<T, FL, FN, FE> (
        &self,
        ref reduce_leaf: FL,
        ref reduce_node: FN,
        ref reduce_edge: FE) -> T
        where
            FL: Fn(&Leaf) -> T,
            FN: Fn(&Node, Vec<T>) -> T,
            FE: Fn(&Edge, T) -> T
            {
                match self {
                    &TagTree::Leaf(ref leaf) => reduce_leaf(leaf),
                    &TagTree::Node(ref node, ref children) => {
                        let subs = children.iter().map(|edge_child| {
                            match edge_child {
                                &(ref edge, box ref child) => {
                                    let sub = child.fold_tag_tree(reduce_leaf, reduce_node, reduce_edge);
                                    reduce_edge(edge, sub)
                                }
                            }
                        }).collect();
                        reduce_node(node, subs)
                    }
                }
            }
}
<commit_msg>second kind of fold<commit_after>
use std::vec::Vec;

pub enum TagTree<Leaf, Node, Edge> {
    Leaf(Leaf),
    Node(Node, Vec<(Edge, Box<TagTree<Leaf, Node, Edge>>)>)
}

impl<Leaf, Node, Edge> TagTree<Leaf, Node, Edge> {

    pub fn fold_tag_tree<T, FL, FN> (
        &self,
        ref reduce_leaf: FL,
        ref reduce_node: FN) -> T
        where
        FL: Fn(&Leaf) -> T,
        FN: Fn(&Node, Vec<(&Edge, T)>) -> T
        {
            match self {
                &TagTree::Leaf(ref leaf) => reduce_leaf(leaf),
                &TagTree::Node(ref node, ref children) => {
                    let edge_subs = children.iter().map(|edge_child| {
                        match edge_child {
                            &(ref edge, box ref child) => {
                                let sub = child.fold_tag_tree(reduce_leaf, reduce_node);
                                (edge, sub)
                            }
                        }
                    }).collect();
                    reduce_node(node, edge_subs)
                }
            }
        }

    pub fn fold_tag_tree2<T, FL, FN, FE> (
        &self,
        ref reduce_leaf: FL,
        ref reduce_node: FN,
        ref reduce_edge: FE) -> T
        where
        FL: Fn(&Leaf) -> T,
        FN: Fn(&Node, Vec<T>) -> T,
        FE: Fn(&Edge, T) -> T
        {
            match self {
                &TagTree::Leaf(ref leaf) => reduce_leaf(leaf),
                &TagTree::Node(ref node, ref children) => {
                    let subs = children.iter().map(|edge_child| {
                        match edge_child {
                            &(ref edge, box ref child) => {
                                let sub = child.fold_tag_tree2(reduce_leaf, reduce_node, reduce_edge);
                                reduce_edge(edge, sub)
                            }
                        }
                    }).collect();
                    reduce_node(node, subs)
                }
            }
        }
}
<|endoftext|>


<commit_before>use std::{env, thread, time};
use std::sync::mpsc;

use reqwest;
use crossbeam;

use bot;
use command_handler::CommandHandler;
use update::Update;

const BASE_URL: &'static str = "https://api.telegram.org/bot";

pub struct Updater {
    token: String,
    last_update_id: i32,
    pub running: bool,
    pub is_idle: bool,
}

impl Updater {
    /// Creates a new Updater struct.
    pub fn start(token: Option<String>,
                 poll_interval: Option<u64>,
                 timeout: Option<i32>,
                 network_delay: Option<i32>,
                 command_handler: CommandHandler) {
        let token = token.or_else(|| env::var("TELEGRAM_BOT_TOKEN").ok())
            .expect("You should pass in a token to new or set TELEGRAM_BOT_TOKEN");

        let bot_url = [BASE_URL, &token].concat();
        let updater = Updater {
            token: token,
            last_update_id: 0,
            running: false,
            is_idle: false,
        };

        updater.start_polling(poll_interval, timeout, network_delay, command_handler);
    }

    pub fn start_polling(mut self,
                         poll_interval: Option<u64>,
                         timeout: Option<i32>,
                         network_delay: Option<i32>,
                         mut command_handler: CommandHandler) {
        if !self.running {
            self.running = true;

            let (tx, rx) = mpsc::channel();
            let bot = bot::Bot::new([BASE_URL, &self.token].concat()).unwrap();

            // Spawn scoped threads
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    self.start_polling_thread(poll_interval, timeout, network_delay, &bot, tx)
                });
                scope.spawn(|| {
                    command_handler.start_command_handling(rx, &bot);
                });
            });
        }
    }

    fn start_polling_thread(&mut self,
                            poll_interval: Option<u64>,
                            timeout: Option<i32>,
                            network_delay: Option<i32>,
                            bot: &bot::Bot,
                            tx: mpsc::Sender<Update>) {
        let poll_interval = time::Duration::from_secs(poll_interval.unwrap_or(0));

        while self.running {
            let updates = bot.get_updates(self.last_update_id, None, timeout, network_delay);

            match updates {
                Ok(Some(ref v)) => {
                    if let Some(u) = v.last() {
                        for update in v {
                            tx.send(update.clone()).unwrap();
                        }
                        let update_id_store = u.update_id + 1;
                        self.last_update_id = update_id_store as i32;
                    } else {
                        // Do nothing, the vector is empty
                        continue;
                    }
                }
                Ok(None) => {
                    // Do nothing, we have nothing
                    continue;
                }
                Err(err) => {
                    // Handle error
                    continue;
                }
            };

            thread::sleep(poll_interval);
        }
    }
}
<commit_msg>Removing bot_url from updater<commit_after>use std::{env, thread, time};
use std::sync::mpsc;

use reqwest;
use crossbeam;

use bot;
use command_handler::CommandHandler;
use update::Update;

const BASE_URL: &'static str = "https://api.telegram.org/bot";

pub struct Updater {
    token: String,
    last_update_id: i32,
    pub running: bool,
    pub is_idle: bool,
}

impl Updater {
    /// Creates a new Updater struct.
    pub fn start(token: Option<String>,
                 poll_interval: Option<u64>,
                 timeout: Option<i32>,
                 network_delay: Option<i32>,
                 command_handler: CommandHandler) {
        let token = token.or_else(|| env::var("TELEGRAM_BOT_TOKEN").ok())
            .expect("You should pass in a token to new or set TELEGRAM_BOT_TOKEN");

        let updater = Updater {
            token: token,
            last_update_id: 0,
            running: false,
            is_idle: false,
        };

        updater.start_polling(poll_interval, timeout, network_delay, command_handler);
    }

    pub fn start_polling(mut self,
                         poll_interval: Option<u64>,
                         timeout: Option<i32>,
                         network_delay: Option<i32>,
                         mut command_handler: CommandHandler) {
        if !self.running {
            self.running = true;

            let (tx, rx) = mpsc::channel();
            let bot = bot::Bot::new([BASE_URL, &self.token].concat()).unwrap();

            // Spawn scoped threads
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    self.start_polling_thread(poll_interval, timeout, network_delay, &bot, tx)
                });
                scope.spawn(|| {
                    command_handler.start_command_handling(rx, &bot);
                });
            });
        }
    }

    fn start_polling_thread(&mut self,
                            poll_interval: Option<u64>,
                            timeout: Option<i32>,
                            network_delay: Option<i32>,
                            bot: &bot::Bot,
                            tx: mpsc::Sender<Update>) {
        let poll_interval = time::Duration::from_secs(poll_interval.unwrap_or(0));

        while self.running {
            let updates = bot.get_updates(self.last_update_id, None, timeout, network_delay);

            match updates {
                Ok(Some(ref v)) => {
                    if let Some(u) = v.last() {
                        for update in v {
                            tx.send(update.clone()).unwrap();
                        }
                        let update_id_store = u.update_id + 1;
                        self.last_update_id = update_id_store as i32;
                    } else {
                        // Do nothing, the vector is empty
                        continue;
                    }
                }
                Ok(None) => {
                    // Do nothing, we have nothing
                    continue;
                }
                Err(err) => {
                    // Handle error
                    continue;
                }
            };

            thread::sleep(poll_interval);
        }
    }
}
<|endoftext|>


<commit_before>
//! Various methods for computing with vectors.

use {
    Line,
    Matrix2d,
    Ray,
    Rectangle,
    Vec2d,
    Triangle
};
use modular_index::{previous};

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(
    &Matrix2d(m): &Matrix2d,
    &Matrix2d(b): &Matrix2d
) -> Matrix2d {
    Matrix2d(
        [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
         m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
    )
}

/// Creates a translation matrix.
#[inline(always)]
pub fn translate(x: f64, y: f64) -> Matrix2d {
    Matrix2d(
        [1.0, 0.0, x,
         0.0, 1.0, y]
    )
}

/// Creates a rotation matrix.
#[inline(always)]
pub fn rotate_radians(angle: f64) -> Matrix2d {
    let c = angle.cos();
    let s = angle.sin();
    Matrix2d(
        [c, -s, 0.0,
         s,  c, 0.0]
    )
}

/// Orients x axis to look at point.
///
/// Leaves x axis unchanged if the point to look at is the origin.
#[inline(always)]
pub fn orient(x: f64, y: f64) -> Matrix2d {
    let len = x * x + y * y;
    if len == 0.0 {
         return Matrix2d(
            [1.0, 0.0, 0.0,
             0.0, 1.0, 0.0]
         );
    }

    let len = len.sqrt();
    let c = x / len;
    let s = y / len;
    Matrix2d(
        [c, -s, 0.0,
         s,  c, 0.0]
    )
}

/// Create a scale matrix.
#[inline(always)]
pub fn scale(sx: f64, sy: f64) -> Matrix2d {
    Matrix2d(
        [sx, 0.0, 0.0,
         0.0, sy, 0.0]
    )
}

/// Create a shear matrix.
#[inline(always)]
pub fn shear(sx: f64, sy: f64) -> Matrix2d {
    Matrix2d(
        [1.0, sx, 0.0,
         sy, 1.0, 0.0]
    )
}

/// Create an identity matrix.
#[inline(always)]
pub fn identity() -> Matrix2d {
    Matrix2d(
        [1.0, 0.0, 0.0,
         0.0, 1.0, 0.0]
    )
}

/// Compute the shortest vector from point to ray.
/// A ray stores starting point and directional vector.
#[inline(always)]
pub fn separation(
    Ray(ray): Ray,
    x: f64,
    y: f64) -> Vec2d {
    // Get the directional vector.
    let (dir_x, dir_y) = (ray[2], ray[3]);
    // Get displacement vector from point.
    let (dx, dy) = (ray[0] - x, ray[1] - y);
    // Compute the component of position in ray direction.
    let dot = dir_x * x + dir_y * y;
    // The directional vector multiplied with the dot gives us a parallel vector.
    // When we subtract this from the displacement we get a vector normal to the ray.
    // This is the shortest vector from the point to the ray.
    Vec2d([dx - dot * dir_x, dy - dot * dir_y])
}

/// Returns the least separation out of four.
/// Each seperation can be computed using `separation` function.
/// The separation returned can be used to solve collision of rectangles.
#[inline(always)]
pub fn least_separation_4(
    Vec2d(sep1): Vec2d,
    Vec2d(sep2): Vec2d,
    Vec2d(sep3): Vec2d,
    Vec2d(sep4): Vec2d
) -> Vec2d {
    let dot1 = sep1[0] * sep1[0] + sep1[1] * sep1[1];
    let dot2 = sep2[0] * sep2[0] + sep2[1] * sep2[1];
    let dot3 = sep3[0] * sep3[0] + sep3[1] * sep3[1];
    let dot4 = sep4[0] * sep4[0] + sep4[1] * sep4[1];
    // Search for the smallest dot product.
    Vec2d(
        if dot1 < dot2 {
            if dot3 < dot4 {
                if dot1 < dot3 { sep1 } else { sep3 }
            } else {
                if dot1 < dot4 { sep1 } else { sep4 }
            }
        } else {
            if dot3 < dot4 {
                if dot2 < dot3 { sep2 } else { sep3 }
            } else {
                if dot2 < dot4 { sep2 } else { sep4 }
            }
        }
    )
}

/// Shrinks a rectangle by a factor on all sides.
#[inline(always)]
pub fn margin_rectangle(
    &Rectangle(rect): &Rectangle,
    m: f64
) -> Rectangle {
    let w = rect[2] - 2.0 * m;
    let h = rect[3] - 2.0 * m;
    let (x, w) = if w < 0.0 { (rect[0] + 0.5 * rect[2], 0.0) } else { (rect[0] + m, w) };
    let (y, h) = if h < 0.0 { (rect[1] + 0.5 * rect[3], 0.0) } else { (rect[1] + m, h) };
    Rectangle([x, y, w, h])
}

/// Computes a relative rectangle using the rectangle as a tile.
#[inline(always)]
pub fn relative_rectangle(
    &Rectangle(rect): &Rectangle,
    x: f64,
    y: f64
) -> Rectangle {
    Rectangle([rect[0] + x * rect[2], rect[1] + y * rect[3], rect[2], rect[3]])
}

/// Computes modular offset safely for numbers.
#[inline(always)]
pub fn modular_offset<T: Add<T, T> + Rem<T, T>>(n: &T, i: &T, off: &T) -> T {
    (*i + (*off % *n + *n)) % *n
}

#[test]
fn test_modular_offset() {
    assert_eq!(modular_offset(&3.0_f64, &0.0_f64, &-1.0_f64), 2.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &1.0_f64, &-1.0_f64), 0.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &2.0_f64, &-1.0_f64), 1.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &3.0_f64, &-1.0_f64), 2.0_f64);

    assert_eq!(modular_offset(&3.0_f64, &0.0_f64, &1.0_f64), 1.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &1.0_f64, &1.0_f64), 2.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &2.0_f64, &1.0_f64), 0.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &3.0_f64, &1.0_f64), 1.0_f64);
}

/// Computes the area and centroid of a simple polygon.
///
/// A simple polygon is one that does not intersect itself.
/// Source: http://en.wikipedia.org/wiki/Polygon_area#Simple_polygons
pub fn area_centroid(polygon: &[f64]) -> (f64, Vec2d) {
    let n = polygon.len() / 2;
    let mut sum = 0.0_f64;
    let (mut cx, mut cy) = (0.0_f64, 0.0_f64);
    for i in range(0, n) {
        let (qx, qy) = (polygon[i * 2], polygon[i * 2 + 1]);
        let p_i = previous(n, i);
        let (px, py) = (polygon[p_i * 2], polygon[p_i * 2 + 1]);
        let cross = px * qy - qx * py;
        cx += (px + qx) * cross;
        cy += (py + qy) * cross;
        sum += cross;
    }

    let area = 0.5 * sum;
    // 'cx / (6.0 * area)' = 'cx / (3.0 * sum)'
    let centroid = Vec2d([cx / (3.0 * sum), cy / (3.0 * sum)]);
    (area, centroid)
}

/// Computes area of a simple polygon.
///
/// A simple polygon is one that does not intersect itself.
#[inline(always)]
pub fn area(polygon: &[f64]) -> f64 {
    let (res, _) = area_centroid(polygon);
    res
}

/// Computes centroid of a simple polygon.
///
/// A simple polygon is one that does not intersect itself.
#[inline(always)]
pub fn centroid(polygon: &[f64]) -> Vec2d {
    let (_, res) = area_centroid(polygon);
    res
}

/// Returns a number that tells which side it is relative to a line.
///
/// Computes the cross product of the vector that gives the line
/// with the vector between point and starting point of line.
/// One side of the line has opposite sign of the other.
#[inline(always)]
pub fn line_side(
    &Line(line): &Line,
    x: f64,
    y: f64
) -> f64 {
    let (ax, ay) = (line[0], line[1]);
    let (bx, by) = (line[2], line[3]);
    (bx - ax) * (y - ay) - (by - ay) * (x - ax)
}

/// Returns true if point is inside triangle.
///
/// This is done by computing a `side` number for each edge.
/// If the number is inside if it is on the same side for all edges.
/// Might break for very small triangles.
pub fn inside_triangle(
    &Triangle(triangle): &Triangle,
    x: f64,
    y: f64
) -> bool {
    let (ax, ay) = (triangle[0], triangle[1]);
    let (bx, by) = (triangle[2], triangle[3]);
    let (cx, cy) = (triangle[4], triangle[5]);

    let ab_side = line_side(&Line([ax, ay, bx, by]), x, y);
    let bc_side = line_side(&Line([bx, by, cx, cy]), x, y);
    let ca_side = line_side(&Line([cx, cy, ax, ay]), x, y);

    let ab_positive = ab_side.is_positive();
    let bc_positive = bc_side.is_positive();
    let ca_positive = ca_side.is_positive();

    ab_positive == bc_positive
    && bc_positive == ca_positive
}

/// Returns true if triangle is clockwise.
///
/// This is done by computing which side the third vertex is relative to
/// the line starting from the first vertex to second vertex.
pub fn triangle_face(
    &Triangle(triangle): &Triangle
) -> bool {
    let (ax, ay) = (triangle[0], triangle[1]);
    let (bx, by) = (triangle[2], triangle[3]);
    let (cx, cy) = (triangle[4], triangle[5]);

    let ab_side = line_side(&Line([ax, ay, bx, by]), cx, cy);

    ab_side.is_negative()
}

#[test]
fn test_triangle() {
    // Triangle counter clock-wise.
    let tri_1 = Triangle([0.0, 0.0, 1.0, 0.0, 1.0, 1.0]);
    // Triangle clock-wise.
    let tri_2 = Triangle([0.0, 0.0, 1.0, 1.0, 1.0, 0.0]);
    let (x, y) = (0.5, 0.25);
    assert_eq!(inside_triangle(&tri_1, x, y), true);
    assert_eq!(inside_triangle(&tri_2, x, y), true);
    assert_eq!(triangle_face(&tri_1), false);
    assert_eq!(triangle_face(&tri_2), true);
}
<commit_msg>Changed `Vec2d` to `&Vec2d` for consistency<commit_after>
//! Various methods for computing with vectors.

use {
    Line,
    Matrix2d,
    Ray,
    Rectangle,
    Vec2d,
    Triangle
};
use modular_index::{previous};

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(
    &Matrix2d(m): &Matrix2d,
    &Matrix2d(b): &Matrix2d
) -> Matrix2d {
    Matrix2d(
        [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
         m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
    )
}

/// Creates a translation matrix.
#[inline(always)]
pub fn translate(x: f64, y: f64) -> Matrix2d {
    Matrix2d(
        [1.0, 0.0, x,
         0.0, 1.0, y]
    )
}

/// Creates a rotation matrix.
#[inline(always)]
pub fn rotate_radians(angle: f64) -> Matrix2d {
    let c = angle.cos();
    let s = angle.sin();
    Matrix2d(
        [c, -s, 0.0,
         s,  c, 0.0]
    )
}

/// Orients x axis to look at point.
///
/// Leaves x axis unchanged if the point to look at is the origin.
#[inline(always)]
pub fn orient(x: f64, y: f64) -> Matrix2d {
    let len = x * x + y * y;
    if len == 0.0 {
         return Matrix2d(
            [1.0, 0.0, 0.0,
             0.0, 1.0, 0.0]
         );
    }

    let len = len.sqrt();
    let c = x / len;
    let s = y / len;
    Matrix2d(
        [c, -s, 0.0,
         s,  c, 0.0]
    )
}

/// Create a scale matrix.
#[inline(always)]
pub fn scale(sx: f64, sy: f64) -> Matrix2d {
    Matrix2d(
        [sx, 0.0, 0.0,
         0.0, sy, 0.0]
    )
}

/// Create a shear matrix.
#[inline(always)]
pub fn shear(sx: f64, sy: f64) -> Matrix2d {
    Matrix2d(
        [1.0, sx, 0.0,
         sy, 1.0, 0.0]
    )
}

/// Create an identity matrix.
#[inline(always)]
pub fn identity() -> Matrix2d {
    Matrix2d(
        [1.0, 0.0, 0.0,
         0.0, 1.0, 0.0]
    )
}

/// Compute the shortest vector from point to ray.
/// A ray stores starting point and directional vector.
#[inline(always)]
pub fn separation(
    Ray(ray): Ray,
    x: f64,
    y: f64) -> Vec2d {
    // Get the directional vector.
    let (dir_x, dir_y) = (ray[2], ray[3]);
    // Get displacement vector from point.
    let (dx, dy) = (ray[0] - x, ray[1] - y);
    // Compute the component of position in ray direction.
    let dot = dir_x * x + dir_y * y;
    // The directional vector multiplied with the dot gives us a parallel vector.
    // When we subtract this from the displacement we get a vector normal to the ray.
    // This is the shortest vector from the point to the ray.
    Vec2d([dx - dot * dir_x, dy - dot * dir_y])
}

/// Returns the least separation out of four.
/// Each seperation can be computed using `separation` function.
/// The separation returned can be used to solve collision of rectangles.
#[inline(always)]
pub fn least_separation_4(
    &Vec2d(sep1): &Vec2d,
    &Vec2d(sep2): &Vec2d,
    &Vec2d(sep3): &Vec2d,
    &Vec2d(sep4): &Vec2d
) -> Vec2d {
    let dot1 = sep1[0] * sep1[0] + sep1[1] * sep1[1];
    let dot2 = sep2[0] * sep2[0] + sep2[1] * sep2[1];
    let dot3 = sep3[0] * sep3[0] + sep3[1] * sep3[1];
    let dot4 = sep4[0] * sep4[0] + sep4[1] * sep4[1];
    // Search for the smallest dot product.
    Vec2d(
        if dot1 < dot2 {
            if dot3 < dot4 {
                if dot1 < dot3 { sep1 } else { sep3 }
            } else {
                if dot1 < dot4 { sep1 } else { sep4 }
            }
        } else {
            if dot3 < dot4 {
                if dot2 < dot3 { sep2 } else { sep3 }
            } else {
                if dot2 < dot4 { sep2 } else { sep4 }
            }
        }
    )
}

/// Shrinks a rectangle by a factor on all sides.
#[inline(always)]
pub fn margin_rectangle(
    &Rectangle(rect): &Rectangle,
    m: f64
) -> Rectangle {
    let w = rect[2] - 2.0 * m;
    let h = rect[3] - 2.0 * m;
    let (x, w) = if w < 0.0 { (rect[0] + 0.5 * rect[2], 0.0) } else { (rect[0] + m, w) };
    let (y, h) = if h < 0.0 { (rect[1] + 0.5 * rect[3], 0.0) } else { (rect[1] + m, h) };
    Rectangle([x, y, w, h])
}

/// Computes a relative rectangle using the rectangle as a tile.
#[inline(always)]
pub fn relative_rectangle(
    &Rectangle(rect): &Rectangle,
    x: f64,
    y: f64
) -> Rectangle {
    Rectangle([rect[0] + x * rect[2], rect[1] + y * rect[3], rect[2], rect[3]])
}

/// Computes modular offset safely for numbers.
#[inline(always)]
pub fn modular_offset<T: Add<T, T> + Rem<T, T>>(n: &T, i: &T, off: &T) -> T {
    (*i + (*off % *n + *n)) % *n
}

#[test]
fn test_modular_offset() {
    assert_eq!(modular_offset(&3.0_f64, &0.0_f64, &-1.0_f64), 2.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &1.0_f64, &-1.0_f64), 0.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &2.0_f64, &-1.0_f64), 1.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &3.0_f64, &-1.0_f64), 2.0_f64);

    assert_eq!(modular_offset(&3.0_f64, &0.0_f64, &1.0_f64), 1.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &1.0_f64, &1.0_f64), 2.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &2.0_f64, &1.0_f64), 0.0_f64);
    assert_eq!(modular_offset(&3.0_f64, &3.0_f64, &1.0_f64), 1.0_f64);
}

/// Computes the area and centroid of a simple polygon.
///
/// A simple polygon is one that does not intersect itself.
/// Source: http://en.wikipedia.org/wiki/Polygon_area#Simple_polygons
pub fn area_centroid(polygon: &[f64]) -> (f64, Vec2d) {
    let n = polygon.len() / 2;
    let mut sum = 0.0_f64;
    let (mut cx, mut cy) = (0.0_f64, 0.0_f64);
    for i in range(0, n) {
        let (qx, qy) = (polygon[i * 2], polygon[i * 2 + 1]);
        let p_i = previous(n, i);
        let (px, py) = (polygon[p_i * 2], polygon[p_i * 2 + 1]);
        let cross = px * qy - qx * py;
        cx += (px + qx) * cross;
        cy += (py + qy) * cross;
        sum += cross;
    }

    let area = 0.5 * sum;
    // 'cx / (6.0 * area)' = 'cx / (3.0 * sum)'
    let centroid = Vec2d([cx / (3.0 * sum), cy / (3.0 * sum)]);
    (area, centroid)
}

/// Computes area of a simple polygon.
///
/// A simple polygon is one that does not intersect itself.
#[inline(always)]
pub fn area(polygon: &[f64]) -> f64 {
    let (res, _) = area_centroid(polygon);
    res
}

/// Computes centroid of a simple polygon.
///
/// A simple polygon is one that does not intersect itself.
#[inline(always)]
pub fn centroid(polygon: &[f64]) -> Vec2d {
    let (_, res) = area_centroid(polygon);
    res
}

/// Returns a number that tells which side it is relative to a line.
///
/// Computes the cross product of the vector that gives the line
/// with the vector between point and starting point of line.
/// One side of the line has opposite sign of the other.
#[inline(always)]
pub fn line_side(
    &Line(line): &Line,
    x: f64,
    y: f64
) -> f64 {
    let (ax, ay) = (line[0], line[1]);
    let (bx, by) = (line[2], line[3]);
    (bx - ax) * (y - ay) - (by - ay) * (x - ax)
}

/// Returns true if point is inside triangle.
///
/// This is done by computing a `side` number for each edge.
/// If the number is inside if it is on the same side for all edges.
/// Might break for very small triangles.
pub fn inside_triangle(
    &Triangle(triangle): &Triangle,
    x: f64,
    y: f64
) -> bool {
    let (ax, ay) = (triangle[0], triangle[1]);
    let (bx, by) = (triangle[2], triangle[3]);
    let (cx, cy) = (triangle[4], triangle[5]);

    let ab_side = line_side(&Line([ax, ay, bx, by]), x, y);
    let bc_side = line_side(&Line([bx, by, cx, cy]), x, y);
    let ca_side = line_side(&Line([cx, cy, ax, ay]), x, y);

    let ab_positive = ab_side.is_positive();
    let bc_positive = bc_side.is_positive();
    let ca_positive = ca_side.is_positive();

    ab_positive == bc_positive
    && bc_positive == ca_positive
}

/// Returns true if triangle is clockwise.
///
/// This is done by computing which side the third vertex is relative to
/// the line starting from the first vertex to second vertex.
pub fn triangle_face(
    &Triangle(triangle): &Triangle
) -> bool {
    let (ax, ay) = (triangle[0], triangle[1]);
    let (bx, by) = (triangle[2], triangle[3]);
    let (cx, cy) = (triangle[4], triangle[5]);

    let ab_side = line_side(&Line([ax, ay, bx, by]), cx, cy);

    ab_side.is_negative()
}

#[test]
fn test_triangle() {
    // Triangle counter clock-wise.
    let tri_1 = Triangle([0.0, 0.0, 1.0, 0.0, 1.0, 1.0]);
    // Triangle clock-wise.
    let tri_2 = Triangle([0.0, 0.0, 1.0, 1.0, 1.0, 0.0]);
    let (x, y) = (0.5, 0.25);
    assert_eq!(inside_triangle(&tri_1, x, y), true);
    assert_eq!(inside_triangle(&tri_2, x, y), true);
    assert_eq!(triangle_face(&tri_1), false);
    assert_eq!(triangle_face(&tri_2), true);
}
<|endoftext|>