<commit_before>use std::collections::HashMap;
use std::cell::RefCell;

use conf::{RemoteBranch};
use constants::{CHANGED_KEY,NEW_KEY,STAGED_KEY,CONFLICTS_KEY};

use git2::*;

struct Cache {
    current_branch_name: RefCell<Option<String>>,
    // TODO: Reference can't be cached (can't be cloned)
    //       implement via OID
    // head: RefCell<Option<Oid>>,
}

pub struct Backend {
    cache: Cache,
    pub repo: Repository,
    pub debug: bool,
}

pub struct BranchAheadBehind {
    pub local_branch_name: Option<String>,
    pub remote_branch_name: Option<String>,
    pub remote_name: Option<String>,
    pub ahead: usize,
    pub behind: usize
}

impl BranchAheadBehind {
    fn new(l: Option<String>) -> BranchAheadBehind {
        BranchAheadBehind{ local_branch_name: l, remote_branch_name: None, remote_name: None,
                           ahead: 0, behind: 0 }
    }
}

#[derive(Clone)]
struct RefPair {
    remote_name: String,
    branch_name: String,
    oid: Oid,
}

impl Cache {
    pub fn new() -> Cache {
        Cache{ current_branch_name: RefCell::new(None) }
    }

    fn set_current_branch_name(&self, n: Option<String>) {
        let mut c = self.current_branch_name.borrow_mut();
        *c = n;
    }

    fn is_current_branch_set(&self) -> bool {
        self.current_branch_name.borrow().is_some()
    }

    fn get_current_branch(&self) -> Option<String> {
        self.current_branch_name.borrow().clone()
    }
}

impl Backend {
    pub fn new(repo: Repository, debug: bool) -> Backend {
        Backend{ repo: repo, debug: debug, cache: Cache::new() }
    }

    fn get_head(&self) -> Option<Reference> {
        match self.repo.head() {
            Ok(head) => Some(head),
            Err(e2) => {
                log!(self, "Can't get HEAD: {}", e2);
                match self.repo.find_reference("HEAD") {
                    Ok(x) => {
                        log!(self, "Found HEAD directly: {:?}", x.name());
                        Some(x)
                    },
                    Err(e) => {
                        log!(self, "reference HEAD: {}", e);
                        None
                    },
                }
            },
        }
    }

    fn get_current_branch_oid(&self) -> Option<Oid> {
        let head = self.get_head();
        match head {
            Some(v) => v.target(),
            None => {
                log!(self, "Failed to find Oid for HEAD.");
                None
            },
        }
    }

    fn resolve_symbolic_reference<'a>(&self, reference: Option<Reference<'a>>) -> Option<Reference<'a>> {
        let s_reference = match reference {
            Some(v) => {
                match v.resolve() {
                    Ok(y) => {
                        log!(self, "Branch name is {:?}", y.name());
                        y
                    },
                    Err(e) => {
                        log!(self, "Branch name is {:?}, error: {:?}", v.name(), e);
                        v
                    }
                }
            }
            None => {
                log!(self, "No branch name found");
                return None;
            }
        };
        Some(s_reference)
    }

    fn get_branch_name_for_reference(&self, r: Reference) -> Option<String> {
        if let Some(ref_name_string) = r.shorthand() {
            if ref_name_string != "HEAD" {
                let s = ref_name_string.to_string();
                log!(self, "Shorthand for reference is: {}", s);
                return Some(s);
            } else {
                if let Some(ref_name) = r.symbolic_target() {
                    let ref_name_string = ref_name.to_string();
                    log!(self, "shorthand = HEAD, links to: {}", ref_name_string);
                    let mut path: Vec<&str> = ref_name_string.split('/').collect();
                    if let Some(branch_short) = path.pop() {
                        let s = branch_short.to_string();
                        log!(self, "Last part of full name is: {}", s);
                        return Some(s);
                    }
                }
            }
        }

        // we're getting the commit hash as name
        match r.target() {
            Some(v) => {
                let hash_str = v.to_string();
                if hash_str.len() >= 8 {
                    let (s, _) = hash_str.split_at(7);
                    Some(s.to_string())
                } else {
                    Some(hash_str)
                }
            },
            None => None,
        }
    }

    pub fn get_current_branch_name(&mut self) -> Option<String> {
        if self.cache.is_current_branch_set() {
            return self.cache.get_current_branch();
        }
        let mut head: Option<Reference> = None;
        if head.is_none() {
            head = self.get_head();
        }
        let h = match self.resolve_symbolic_reference(head) {
            Some(v) => v,
            None => return None,
        };
        let current_branch_name = self.get_branch_name_for_reference(h);
        self.cache.set_current_branch_name(current_branch_name.clone());
        current_branch_name
    }

    fn get_branch_remote(&self, reference: Reference) -> Option<RefPair> {
        let b = Branch::wrap(reference);
        let upstream = match b.upstream() {
            Ok(u) => u,
            Err(e) => {
                log!(self, "Can't get upstream branch for {:?}: {:?}", b.name(), e);
                return None;
            }
        };
        let branch_name = match upstream.name() {
            Ok(o_n) => match o_n {
                Some(n) => n,
                None => {
                    log!(self, "Invalid branch name");
                    return None;
                },
            },
            Err(e) => {
                log!(self, "Error while getting name for upstream branch: {:?}", e);
                return None;
            }
        };
        let upstream_reference = upstream.get();
        let oid = match upstream_reference.target() {
            Some(o) => o,
            None => {
                log!(self, "Can't get oid of upstream branch");
                return None;
            }
        };
        let remote_name = match upstream_reference.name() {
            Some(n) => {
                let v: Vec<&str> = n.splitn(3, "/").collect();
                if v.len() >= 3 {
                    v[1]
                } else {
                    log!(self, "Can't figure out remote name: {:?}", v);
                    return None;
                }
            },
            None => {
                log!(self, "Can't get full name of upstream branch.");
                return None;
            }
        };
        Some(RefPair{ remote_name: remote_name.to_string(),
                      branch_name: branch_name.to_string(), oid: oid })
    }

    fn get_current_branch_remote_oid(&self) -> Option<RefPair> {
        match self.get_head() {
            Some(r) => self.get_branch_remote(r),
            None => None
        }
    }

    pub fn get_branch_ahead_behind(&mut self, remote_branch: Option<RemoteBranch>) -> Option<BranchAheadBehind> {
        let current_branch_name = self.get_current_branch_name();
        log!(self, "Current branch name = {:?}", current_branch_name);
        let mut ab = BranchAheadBehind::new(current_branch_name);
        let ref_pair_option = self.get_remote_branch(remote_branch);
        let ref_pair = match ref_pair_option {
            Some(u) => {
                u.clone()
            },
            None => return Some(ab),
        };
        ab.remote_branch_name = Some(ref_pair.branch_name.clone());
        ab.remote_name = Some(ref_pair.remote_name);

        let oid = match self.get_current_branch_oid() {
            Some(r) => r,
            None => return None
        };
        let res = self.repo.graph_ahead_behind(oid, ref_pair.oid);
        match res {
            Ok((a, b)) => {
                ab.ahead = a;
                ab.behind = b;
            },
            Err(e) => {
                log!(self, "Can't get ahead & behind stats for branch {}: {:?}", ref_pair.branch_name, e);
            }
        };
        Some(ab)
    }

    // find remote branch if branch_name is specified
    // if not, get remote tracking branch for current branch
    fn get_remote_branch(&self, remote_branch: Option<RemoteBranch>) -> Option<RefPair> {
        match remote_branch {
            Some(b) => {
                match self.repo.find_branch(&b.remote_branch, BranchType::Remote) {
                    Ok(o) => Some(RefPair{ branch_name: b.remote_branch_name,
                                           remote_name: b.remote_name,
                                           oid: o.into_reference().target().unwrap() }),
                    Err(e) => {
                        // don't panic here - it doesn't exist, we don't care
                        log!(self, "No remote branch found for {}: {:?}", b.remote_branch_name, e);
                        None
                    }
                }
            },
            None => {
                self.get_current_branch_remote_oid()
            }
        }
    }

    pub fn get_status(&self) -> Option<Statuses> {
        let mut so = StatusOptions::new();
        let mut opts = so.show(StatusShow::IndexAndWorkdir);
        opts.include_untracked(true);
        match self.repo.statuses(Some(&mut opts)) {
            Ok(s) => Some(s),
            Err(e) => {
                log!(self, "Unable to get status of repository: {:?}", e);
                None
            }
        }
    }

    pub fn get_repository_state(&self) -> String {
        let state = self.repo.state();
        match state {
            RepositoryState::Clean => String::from(""),  // XXX: this seems to be hardcoded
            RepositoryState::Merge => String::from("merge"),
            RepositoryState::Revert | RepositoryState::RevertSequence => String::from("revert"),
            RepositoryState::CherryPick | RepositoryState::CherryPickSequence => String::from("cherry-pick"),
            RepositoryState::Bisect => String::from("bisect"),
            RepositoryState::Rebase |
                RepositoryState::RebaseInteractive |
                RepositoryState::RebaseMerge => String::from("rebase"),
            RepositoryState::ApplyMailbox | RepositoryState::ApplyMailboxOrRebase => String::from("apply"),
        }
    }

    pub fn get_file_status(&self) -> Option<HashMap<&str, u32>> {
        let mut d = HashMap::new();

        let changed = STATUS_WT_MODIFIED | STATUS_WT_DELETED | STATUS_WT_TYPECHANGE | STATUS_WT_RENAMED;
        let staged = STATUS_INDEX_MODIFIED | STATUS_INDEX_DELETED | STATUS_INDEX_TYPECHANGE | STATUS_INDEX_RENAMED | STATUS_INDEX_NEW;

        let statuses = match self.get_status() {
            Some(x) => x,
            None => return None,
        };

        for s in statuses.iter() {
            let file_status = s.status();
            log!(self, "{}", s.path().unwrap());

            if file_status.intersects(changed) {
                let counter = d.entry(CHANGED_KEY).or_insert(0);
                *counter += 1;
            };
            if file_status.contains(STATUS_WT_NEW) {
                let counter = d.entry(NEW_KEY).or_insert(0);
                *counter += 1;
            };
            if file_status.intersects(staged) {
                let counter = d.entry(STAGED_KEY).or_insert(0);
                *counter += 1;
            };
            if file_status.intersects(STATUS_CONFLICTED) {
                let counter = d.entry(CONFLICTS_KEY).or_insert(0);
                *counter += 1;
            };
        }
        Some(d)
    }
}
<commit_msg>clippy: else if let<commit_after>use std::collections::HashMap;
use std::cell::RefCell;

use conf::{RemoteBranch};
use constants::{CHANGED_KEY,NEW_KEY,STAGED_KEY,CONFLICTS_KEY};

use git2::*;

struct Cache {
    current_branch_name: RefCell<Option<String>>,
    // TODO: Reference can't be cached (can't be cloned)
    //       implement via OID
    // head: RefCell<Option<Oid>>,
}

pub struct Backend {
    cache: Cache,
    pub repo: Repository,
    pub debug: bool,
}

pub struct BranchAheadBehind {
    pub local_branch_name: Option<String>,
    pub remote_branch_name: Option<String>,
    pub remote_name: Option<String>,
    pub ahead: usize,
    pub behind: usize
}

impl BranchAheadBehind {
    fn new(l: Option<String>) -> BranchAheadBehind {
        BranchAheadBehind{ local_branch_name: l, remote_branch_name: None, remote_name: None,
                           ahead: 0, behind: 0 }
    }
}

#[derive(Clone)]
struct RefPair {
    remote_name: String,
    branch_name: String,
    oid: Oid,
}

impl Cache {
    pub fn new() -> Cache {
        Cache{ current_branch_name: RefCell::new(None) }
    }

    fn set_current_branch_name(&self, n: Option<String>) {
        let mut c = self.current_branch_name.borrow_mut();
        *c = n;
    }

    fn is_current_branch_set(&self) -> bool {
        self.current_branch_name.borrow().is_some()
    }

    fn get_current_branch(&self) -> Option<String> {
        self.current_branch_name.borrow().clone()
    }
}

impl Backend {
    pub fn new(repo: Repository, debug: bool) -> Backend {
        Backend{ repo: repo, debug: debug, cache: Cache::new() }
    }

    fn get_head(&self) -> Option<Reference> {
        match self.repo.head() {
            Ok(head) => Some(head),
            Err(e2) => {
                log!(self, "Can't get HEAD: {}", e2);
                match self.repo.find_reference("HEAD") {
                    Ok(x) => {
                        log!(self, "Found HEAD directly: {:?}", x.name());
                        Some(x)
                    },
                    Err(e) => {
                        log!(self, "reference HEAD: {}", e);
                        None
                    },
                }
            },
        }
    }

    fn get_current_branch_oid(&self) -> Option<Oid> {
        let head = self.get_head();
        match head {
            Some(v) => v.target(),
            None => {
                log!(self, "Failed to find Oid for HEAD.");
                None
            },
        }
    }

    fn resolve_symbolic_reference<'a>(&self, reference: Option<Reference<'a>>) -> Option<Reference<'a>> {
        let s_reference = match reference {
            Some(v) => {
                match v.resolve() {
                    Ok(y) => {
                        log!(self, "Branch name is {:?}", y.name());
                        y
                    },
                    Err(e) => {
                        log!(self, "Branch name is {:?}, error: {:?}", v.name(), e);
                        v
                    }
                }
            }
            None => {
                log!(self, "No branch name found");
                return None;
            }
        };
        Some(s_reference)
    }

    fn get_branch_name_for_reference(&self, r: Reference) -> Option<String> {
        if let Some(ref_name_string) = r.shorthand() {
            if ref_name_string != "HEAD" {
                let s = ref_name_string.to_string();
                log!(self, "Shorthand for reference is: {}", s);
                return Some(s);
            } else if let Some(ref_name) = r.symbolic_target() {
                let ref_name_string = ref_name.to_string();
                log!(self, "shorthand = HEAD, links to: {}", ref_name_string);
                let mut path: Vec<&str> = ref_name_string.split('/').collect();
                if let Some(branch_short) = path.pop() {
                    let s = branch_short.to_string();
                    log!(self, "Last part of full name is: {}", s);
                    return Some(s);
                }
            }
        }

        // we're getting the commit hash as name
        match r.target() {
            Some(v) => {
                let hash_str = v.to_string();
                if hash_str.len() >= 8 {
                    let (s, _) = hash_str.split_at(7);
                    Some(s.to_string())
                } else {
                    Some(hash_str)
                }
            },
            None => None,
        }
    }

    pub fn get_current_branch_name(&mut self) -> Option<String> {
        if self.cache.is_current_branch_set() {
            return self.cache.get_current_branch();
        }
        let mut head: Option<Reference> = None;
        if head.is_none() {
            head = self.get_head();
        }
        let h = match self.resolve_symbolic_reference(head) {
            Some(v) => v,
            None => return None,
        };
        let current_branch_name = self.get_branch_name_for_reference(h);
        self.cache.set_current_branch_name(current_branch_name.clone());
        current_branch_name
    }

    fn get_branch_remote(&self, reference: Reference) -> Option<RefPair> {
        let b = Branch::wrap(reference);
        let upstream = match b.upstream() {
            Ok(u) => u,
            Err(e) => {
                log!(self, "Can't get upstream branch for {:?}: {:?}", b.name(), e);
                return None;
            }
        };
        let branch_name = match upstream.name() {
            Ok(o_n) => match o_n {
                Some(n) => n,
                None => {
                    log!(self, "Invalid branch name");
                    return None;
                },
            },
            Err(e) => {
                log!(self, "Error while getting name for upstream branch: {:?}", e);
                return None;
            }
        };
        let upstream_reference = upstream.get();
        let oid = match upstream_reference.target() {
            Some(o) => o,
            None => {
                log!(self, "Can't get oid of upstream branch");
                return None;
            }
        };
        let remote_name = match upstream_reference.name() {
            Some(n) => {
                let v: Vec<&str> = n.splitn(3, "/").collect();
                if v.len() >= 3 {
                    v[1]
                } else {
                    log!(self, "Can't figure out remote name: {:?}", v);
                    return None;
                }
            },
            None => {
                log!(self, "Can't get full name of upstream branch.");
                return None;
            }
        };
        Some(RefPair{ remote_name: remote_name.to_string(),
                      branch_name: branch_name.to_string(), oid: oid })
    }

    fn get_current_branch_remote_oid(&self) -> Option<RefPair> {
        match self.get_head() {
            Some(r) => self.get_branch_remote(r),
            None => None
        }
    }

    pub fn get_branch_ahead_behind(&mut self, remote_branch: Option<RemoteBranch>) -> Option<BranchAheadBehind> {
        let current_branch_name = self.get_current_branch_name();
        log!(self, "Current branch name = {:?}", current_branch_name);
        let mut ab = BranchAheadBehind::new(current_branch_name);
        let ref_pair_option = self.get_remote_branch(remote_branch);
        let ref_pair = match ref_pair_option {
            Some(u) => {
                u.clone()
            },
            None => return Some(ab),
        };
        ab.remote_branch_name = Some(ref_pair.branch_name.clone());
        ab.remote_name = Some(ref_pair.remote_name);

        let oid = match self.get_current_branch_oid() {
            Some(r) => r,
            None => return None
        };
        let res = self.repo.graph_ahead_behind(oid, ref_pair.oid);
        match res {
            Ok((a, b)) => {
                ab.ahead = a;
                ab.behind = b;
            },
            Err(e) => {
                log!(self, "Can't get ahead & behind stats for branch {}: {:?}", ref_pair.branch_name, e);
            }
        };
        Some(ab)
    }

    // find remote branch if branch_name is specified
    // if not, get remote tracking branch for current branch
    fn get_remote_branch(&self, remote_branch: Option<RemoteBranch>) -> Option<RefPair> {
        match remote_branch {
            Some(b) => {
                match self.repo.find_branch(&b.remote_branch, BranchType::Remote) {
                    Ok(o) => Some(RefPair{ branch_name: b.remote_branch_name,
                                           remote_name: b.remote_name,
                                           oid: o.into_reference().target().unwrap() }),
                    Err(e) => {
                        // don't panic here - it doesn't exist, we don't care
                        log!(self, "No remote branch found for {}: {:?}", b.remote_branch_name, e);
                        None
                    }
                }
            },
            None => {
                self.get_current_branch_remote_oid()
            }
        }
    }

    pub fn get_status(&self) -> Option<Statuses> {
        let mut so = StatusOptions::new();
        let mut opts = so.show(StatusShow::IndexAndWorkdir);
        opts.include_untracked(true);
        match self.repo.statuses(Some(&mut opts)) {
            Ok(s) => Some(s),
            Err(e) => {
                log!(self, "Unable to get status of repository: {:?}", e);
                None
            }
        }
    }

    pub fn get_repository_state(&self) -> String {
        let state = self.repo.state();
        match state {
            RepositoryState::Clean => String::from(""),  // XXX: this seems to be hardcoded
            RepositoryState::Merge => String::from("merge"),
            RepositoryState::Revert | RepositoryState::RevertSequence => String::from("revert"),
            RepositoryState::CherryPick | RepositoryState::CherryPickSequence => String::from("cherry-pick"),
            RepositoryState::Bisect => String::from("bisect"),
            RepositoryState::Rebase |
                RepositoryState::RebaseInteractive |
                RepositoryState::RebaseMerge => String::from("rebase"),
            RepositoryState::ApplyMailbox | RepositoryState::ApplyMailboxOrRebase => String::from("apply"),
        }
    }

    pub fn get_file_status(&self) -> Option<HashMap<&str, u32>> {
        let mut d = HashMap::new();

        let changed = STATUS_WT_MODIFIED | STATUS_WT_DELETED | STATUS_WT_TYPECHANGE | STATUS_WT_RENAMED;
        let staged = STATUS_INDEX_MODIFIED | STATUS_INDEX_DELETED | STATUS_INDEX_TYPECHANGE | STATUS_INDEX_RENAMED | STATUS_INDEX_NEW;

        let statuses = match self.get_status() {
            Some(x) => x,
            None => return None,
        };

        for s in statuses.iter() {
            let file_status = s.status();
            log!(self, "{}", s.path().unwrap());

            if file_status.intersects(changed) {
                let counter = d.entry(CHANGED_KEY).or_insert(0);
                *counter += 1;
            };
            if file_status.contains(STATUS_WT_NEW) {
                let counter = d.entry(NEW_KEY).or_insert(0);
                *counter += 1;
            };
            if file_status.intersects(staged) {
                let counter = d.entry(STAGED_KEY).or_insert(0);
                *counter += 1;
            };
            if file_status.intersects(STATUS_CONFLICTED) {
                let counter = d.entry(CONFLICTS_KEY).or_insert(0);
                *counter += 1;
            };
        }
        Some(d)
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// 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.
//

//! KRPC DHT service as described in
//! [BEP 0005](http://www.bittorrent.org/beps/bep_0005.html).

use std::sync;

use super::super::base;

/// Implementation of basic KRPC DHT on which BitTorrent DHT is based.
///
/// No peer retrival is supported: just finding and pinging nodes.
pub struct KRpcService<TNodeTable: base::GenericNodeTable> {
    this_node: base::Node,
    node_table: sync::Arc<sync::RWLock<TNodeTable>>,
}
<commit_msg>bt::krpc: new() and new_default()<commit_after>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// 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.
//

//! KRPC DHT service as described in
//! [BEP 0005](http://www.bittorrent.org/beps/bep_0005.html).
//!
//! Create as:
//! ```
//! let service = dht::bt::KRpcService::new(this_node);
//! ```

use std::sync;

use super::super::base;
use super::super::knodetable;

/// Implementation of basic KRPC DHT on which BitTorrent DHT is based.
///
/// No peer retrival is supported: just finding and pinging nodes.
pub struct KRpcService<TNodeTable: base::GenericNodeTable> {
    this_node: base::Node,
    node_table: sync::Arc<sync::RWLock<TNodeTable>>,
}

impl KRpcService<knodetable::KNodeTable> {
    /// New service with default node table.
    pub fn new_default(this_node: base::Node)
            -> KRpcService<knodetable::KNodeTable> {
        let node_table = knodetable::KNodeTable::new(this_node.id.clone());
        KRpcService::new(this_node, node_table)
    }
}

impl<TNodeTable: base::GenericNodeTable> KRpcService<TNodeTable> {
    /// New service with given node table.
    pub fn new(this_node: base::Node, node_table: TNodeTable)
            -> KRpcService<TNodeTable> {
        KRpcService {
            this_node: this_node,
            node_table: sync::Arc::new(sync::RWLock::new(node_table)),
        }
    }

    /// Get lock guarding access to a node table.
    pub fn node_table_lock(&self) -> &sync::RWLock<TNodeTable> {
        self.node_table.deref()
    }
}

#[cfg(test)]
mod test {
    use num;

    use super::super::super::base::{mod, GenericNodeTable};
    use super::super::super::utils::test;

    use super::KRpcService;

    struct DummyNodeTable {
        last_node: Option<base::Node>,
    }

    impl GenericNodeTable for DummyNodeTable {
        fn random_id(&self) -> num::BigUint {
            // This number is random, I promise :)
            test::uint_to_id(42)
        }

        fn update(&mut self, node: &base::Node) -> bool {
            self.last_node = Some(node.clone());
            true
        }
        #[allow(unused_variable)]
        fn find(&self, id: &num::BigUint, count: uint) -> Vec<base::Node> {
            match self.last_node {
                Some(ref n) if n.id == *id => vec![n.clone()],
                _ => vec![]
            }
        }
        fn pop_oldest(&mut self) -> Vec<base::Node> {
            vec![]
        }
    }

    #[test]
    fn test_new() {
        let n = test::new_node(42);
        let s = KRpcService::new(n.clone(),
                                 DummyNodeTable { last_node: None });
        assert_eq!(n.id, s.this_node.id);
        let mut nt = s.node_table_lock().write();
        nt.update(&test::new_node(1));
        let nt2 = nt.downgrade();
        assert_eq!(nt2.random_id().to_u8().unwrap(), 42);
    }

    #[test]
    fn test_new_default() {
        let n = test::new_node(42);
        let s = KRpcService::new_default(n.clone());
        assert_eq!(n.id, s.this_node.id);
        let nt = s.node_table_lock().read();
        assert_eq!(0, nt.find(&test::uint_to_id(1), 1).len());
    }
}
<|endoftext|>


<commit_before>use std::{thread, time};
use std::env;
use std::io::prelude::*;
use std::fs::File;

/// Chipate Module
/// Rust emulation of the Chip-8
/// http://www.multigesturearticles/how-to-write-an-emulator-chip-8-interpreter/
#[allow(dead_code)]
pub struct Chipate {
    // Opcodes
    opcode: u16,

    // 4K Memory
    memory: [u8; 4096],
    // The systems memory map:
    // 0x000-0x1FF - Chip 8 interpreter (contains font set in emu)
    // 0x050-0x0A0 - Used for the built in 4x5 pixel font set (0-F)
    // 0x200-0xFFF - Program ROM and work RAM

    // Registers
    v: [u8; 16],

    // Index
    i: u16,

    // Program Counter
    pc: u16,

    gfx: [u8; 64 * 32],

    // Timers
    delay_timer: u8,
    sound_timer: u8,

    // Stack
    stack: [u8; 16],
    sp: u8,

    // Keypad
    key: [u8; 16],

    program: &'static str,
}

impl Chipate {
    pub fn init(&mut self) {
        debug!("Initialize Chip");
        // pc     = 0x200;  // Program counter starts at 0x200
        self.pc = 0x200;
        // opcode = 0;      // Reset current opcode
        self.opcode = 0x0;
        // I      = 0;      // Reset index register
        self.i = 0x0;
        // sp     = 0;      // Reset stack pointer
        self.sp = 0x0;

        // // Clear display
        // // Clear stack
        // // Clear registers V0-VF
        // // Clear memory

        // // Load fontset
        // for(int i = 0; i < 80; ++i)
        //     memory[i] = chip8_fontset[i];

        // // Reset timers
    }

    pub fn load_program(&mut self, program: &str) {
        debug!("Loading program {}", program);

        // We assume that we are in a valid directory.
        let mut p = env::current_dir().unwrap();
        p.push("programs");
        p.push(program);

        debug!("The current directory is {}", p.display());

        let mut f = File::open(p).expect("Unable to open file");

        let mut b = Vec::new();

        f.read_to_end(&mut b).expect("Unable to read file");

        debug!("Length {}", b.len());

        for i in 0..b.len() {
            self.memory[i + 512] = b[i];
        }

    }

    pub fn emulate_cycle(&mut self) {
        debug!("Cycle Begin");

        self.fetch_opcode();
        self.decode_opcode();

        let one_second = time::Duration::from_secs(1);
        thread::sleep(one_second);

        debug!("Cycle End");
    }

    pub fn draw_screen(&mut self) {
        debug!("Drawing to Screen")
    }

    pub fn set_keys(&mut self) {
        debug!("Saving Key State")
    }

    pub fn setup_testing_memory(&mut self) {
        debug!("Setting test memory");

        self.memory[self.pc as usize] = 0xA2;
        self.memory[(self.pc + 1) as usize] = 0xF0;

        debug!("Location: 0x{:X} data: 0x{:X}",
               self.pc,
               self.memory[self.pc as usize]);
        debug!("Location: 0x{:X} data: 0x{:X}",
               self.pc + 1,
               self.memory[(self.pc + 1) as usize]);
    }

    pub fn fetch_opcode(&mut self) {
        let op_a = self.memory[self.pc as usize];
        self.opcode = op_a as u16;
        self.opcode = self.opcode << 8;
        // debug!("location: 0x{:X} data: 0x{:X}", self.pc, self.opcode);

        let op_b = self.memory[(self.pc + 1) as usize] as u16;
        // debug!("location: 0x{:X} data: 0x{:X}", self.pc, op_b);

        self.opcode = self.opcode | op_b;
        debug!("Opcode: 0x{:X}", self.opcode);
    }

    pub fn decode_opcode(&mut self) {
        let op = self.opcode & 0xF000;
        debug!("Decode: 0x{:X}", op);

        match op {
            0xA000 => self.annn_opcode(),
            _ => {
                debug!("Catch all: 0x{:X}", self.opcode);
            }
        }
    }

    pub fn increase_pc(&mut self) {
        self.pc += 2;
        debug!("Program Counter: 0x{:X}", self.pc);
    }

    pub fn annn_opcode(&mut self) {
        debug!("ANNN: 0x{:X}", self.opcode);
        self.i = self.opcode & 0x0FFF;
        self.increase_pc();
    }

    pub fn new() -> Chipate {
        debug!("Creating New Chip");

        let chip = Chipate {
            opcode: 0,
            memory: [0; 4096],
            v: [0; 16],
            i: 0,
            pc: 0,
            gfx: [0; 64 * 32],
            delay_timer: 0,
            sound_timer: 0,
            stack: [0; 16],
            sp: 0,
            key: [0; 16],
            program: "",
        };

        return chip;
    }
}
<commit_msg>Catchall opcode being used as a NOOP<commit_after>use std::{thread, time};
use std::env;
use std::io::prelude::*;
use std::fs::File;

/// Chipate Module
/// Rust emulation of the Chip-8
/// http://www.multigesturearticles/how-to-write-an-emulator-chip-8-interpreter/
#[allow(dead_code)]
pub struct Chipate {
    // Opcodes
    opcode: u16,

    // 4K Memory
    memory: [u8; 4096],
    // The systems memory map:
    // 0x000-0x1FF - Chip 8 interpreter (contains font set in emu)
    // 0x050-0x0A0 - Used for the built in 4x5 pixel font set (0-F)
    // 0x200-0xFFF - Program ROM and work RAM

    // Registers
    v: [u8; 16],

    // Index
    i: u16,

    // Program Counter
    pc: u16,

    gfx: [u8; 64 * 32],

    // Timers
    delay_timer: u8,
    sound_timer: u8,

    // Stack
    stack: [u8; 16],
    sp: u8,

    // Keypad
    key: [u8; 16],

    program: &'static str,
}

impl Chipate {
    pub fn init(&mut self) {
        debug!("Initialize Chip");
        // pc     = 0x200;  // Program counter starts at 0x200
        self.pc = 0x200;
        // opcode = 0;      // Reset current opcode
        self.opcode = 0x0;
        // I      = 0;      // Reset index register
        self.i = 0x0;
        // sp     = 0;      // Reset stack pointer
        self.sp = 0x0;

        // // Clear display
        // // Clear stack
        // // Clear registers V0-VF
        // // Clear memory

        // // Load fontset
        // for(int i = 0; i < 80; ++i)
        //     memory[i] = chip8_fontset[i];

        // // Reset timers
    }

    pub fn load_program(&mut self, program: &str) {
        debug!("Loading program {}", program);

        // We assume that we are in a valid directory.
        let mut p = env::current_dir().unwrap();
        p.push("programs");
        p.push(program);

        debug!("The current directory is {}", p.display());

        let mut f = File::open(p).expect("Unable to open file");

        let mut b = Vec::new();

        f.read_to_end(&mut b).expect("Unable to read file");

        debug!("Length {}", b.len());

        for i in 0..b.len() {
            self.memory[i + 512] = b[i];
        }

    }

    pub fn emulate_cycle(&mut self) {
        debug!("Cycle Begin");

        self.fetch_opcode();
        self.decode_opcode();

        let one_second = time::Duration::from_secs(1);
        thread::sleep(one_second);

        debug!("Cycle End");
    }

    pub fn draw_screen(&mut self) {
        debug!("Drawing to Screen")
    }

    pub fn set_keys(&mut self) {
        debug!("Saving Key State")
    }

    pub fn setup_testing_memory(&mut self) {
        debug!("Setting test memory");

        self.memory[self.pc as usize] = 0xA2;
        self.memory[(self.pc + 1) as usize] = 0xF0;

        debug!("Location: 0x{:X} data: 0x{:X}",
               self.pc,
               self.memory[self.pc as usize]);
        debug!("Location: 0x{:X} data: 0x{:X}",
               self.pc + 1,
               self.memory[(self.pc + 1) as usize]);
    }

    pub fn fetch_opcode(&mut self) {
        let op_a = self.memory[self.pc as usize];
        self.opcode = op_a as u16;
        self.opcode = self.opcode << 8;
        // debug!("location: 0x{:X} data: 0x{:X}", self.pc, self.opcode);

        let op_b = self.memory[(self.pc + 1) as usize] as u16;
        // debug!("location: 0x{:X} data: 0x{:X}", self.pc, op_b);

        self.opcode = self.opcode | op_b;
        debug!("Opcode: 0x{:X}", self.opcode);
    }

    pub fn decode_opcode(&mut self) {
        let op = self.opcode & 0xF000;
        debug!("Decode: 0x{:X}", op);

        match op {
            0xA000 => self.annn_opcode(),
            _ => {
                // Using the catch all as a NOOP
                debug!("Catch all: 0x{:X}", self.opcode);
                self.increase_pc();
            }
        }
    }

    pub fn increase_pc(&mut self) {
        self.pc += 2;
        debug!("Program Counter: 0x{:X}", self.pc);
    }

    pub fn annn_opcode(&mut self) {
        debug!("ANNN: 0x{:X}", self.opcode);
        self.i = self.opcode & 0x0FFF;
        self.increase_pc();
    }

    pub fn new() -> Chipate {
        debug!("Creating New Chip");

        let chip = Chipate {
            opcode: 0,
            memory: [0; 4096],
            v: [0; 16],
            i: 0,
            pc: 0,
            gfx: [0; 64 * 32],
            delay_timer: 0,
            sound_timer: 0,
            stack: [0; 16],
            sp: 0,
            key: [0; 16],
            program: "",
        };

        return chip;
    }
}
<|endoftext|>


<commit_before>//! The compiler code necessary to implement the `#[derive(RustcEncodable)]`
//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that
//! type-defining items may be tagged with
//! `#[derive(RustcEncodable, RustcDecodable)]`.
//!
//! For example, a type like:
//!
//! ```
//! #[derive(RustcEncodable, RustcDecodable)]
//! struct Node { id: usize }
//! ```
//!
//! would generate two implementations like:
//!
//! ```
//! # struct Node { id: usize }
//! impl<S: Encoder<E>, E> Encodable<S, E> for Node {
//!     fn encode(&self, s: &mut S) -> Result<(), E> {
//!         s.emit_struct("Node", 1, |this| {
//!             this.emit_struct_field("id", 0, |this| {
//!                 Encodable::encode(&self.id, this)
//!                 /* this.emit_usize(self.id) can also be used */
//!             })
//!         })
//!     }
//! }
//!
//! impl<D: Decoder<E>, E> Decodable<D, E> for Node {
//!     fn decode(d: &mut D) -> Result<Node, E> {
//!         d.read_struct("Node", 1, |this| {
//!             match this.read_struct_field("id", 0, |this| Decodable::decode(this)) {
//!                 Ok(id) => Ok(Node { id: id }),
//!                 Err(e) => Err(e),
//!             }
//!         })
//!     }
//! }
//! ```
//!
//! Other interesting scenarios are when the item has type parameters or
//! references other non-built-in types. A type definition like:
//!
//! ```
//! # #[derive(RustcEncodable, RustcDecodable)]
//! # struct Span;
//! #[derive(RustcEncodable, RustcDecodable)]
//! struct Spanned<T> { node: T, span: Span }
//! ```
//!
//! would yield functions like:
//!
//! ```
//! # #[derive(RustcEncodable, RustcDecodable)]
//! # struct Span;
//! # struct Spanned<T> { node: T, span: Span }
//! impl<
//!     S: Encoder<E>,
//!     E,
//!     T: Encodable<S, E>
//! > Encodable<S, E> for Spanned<T> {
//!     fn encode(&self, s: &mut S) -> Result<(), E> {
//!         s.emit_struct("Spanned", 2, |this| {
//!             this.emit_struct_field("node", 0, |this| self.node.encode(this))
//!                 .unwrap();
//!             this.emit_struct_field("span", 1, |this| self.span.encode(this))
//!         })
//!     }
//! }
//!
//! impl<
//!     D: Decoder<E>,
//!     E,
//!     T: Decodable<D, E>
//! > Decodable<D, E> for Spanned<T> {
//!     fn decode(d: &mut D) -> Result<Spanned<T>, E> {
//!         d.read_struct("Spanned", 2, |this| {
//!             Ok(Spanned {
//!                 node: this.read_struct_field("node", 0, |this| Decodable::decode(this))
//!                     .unwrap(),
//!                 span: this.read_struct_field("span", 1, |this| Decodable::decode(this))
//!                     .unwrap(),
//!             })
//!         })
//!     }
//! }
//! ```

use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::pathvec_std;

use rustc_ast::ptr::P;
use rustc_ast::{Expr, ExprKind, MetaItem, Mutability};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;

pub fn expand_deriving_rustc_encodable(
    cx: &mut ExtCtxt<'_>,
    span: Span,
    mitem: &MetaItem,
    item: &Annotatable,
    push: &mut dyn FnMut(Annotatable),
) {
    let krate = sym::rustc_serialize;
    let typaram = sym::__S;

    let trait_def = TraitDef {
        span,
        attributes: Vec::new(),
        path: Path::new_(vec![krate, sym::Encodable], None, vec![], PathKind::Global),
        additional_bounds: Vec::new(),
        generics: Bounds::empty(),
        is_unsafe: false,
        supports_unions: false,
        methods: vec![MethodDef {
            name: sym::encode,
            generics: Bounds {
                bounds: vec![(
                    typaram,
                    vec![Path::new_(vec![krate, sym::Encoder], None, vec![], PathKind::Global)],
                )],
            },
            explicit_self: borrowed_explicit_self(),
            args: vec![(
                Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
                // FIXME: we could use `sym::s` here, but making `s` a static
                // symbol changes the symbol index ordering in a way that makes
                // ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
                // fail. The linting code should be fixed so that its output
                // does not depend on the symbol index ordering.
                Symbol::intern("s"),
            )],
            ret_ty: Literal(Path::new_(
                pathvec_std!(result::Result),
                None,
                vec![
                    Box::new(Tuple(Vec::new())),
                    Box::new(Literal(Path::new_(
                        vec![typaram, sym::Error],
                        None,
                        vec![],
                        PathKind::Local,
                    ))),
                ],
                PathKind::Std,
            )),
            attributes: Vec::new(),
            is_unsafe: false,
            unify_fieldless_variants: false,
            combine_substructure: combine_substructure(Box::new(|a, b, c| {
                encodable_substructure(a, b, c, krate)
            })),
        }],
        associated_types: Vec::new(),
    };

    trait_def.expand(cx, mitem, item, push)
}

fn encodable_substructure(
    cx: &mut ExtCtxt<'_>,
    trait_span: Span,
    substr: &Substructure<'_>,
    krate: Symbol,
) -> P<Expr> {
    let encoder = substr.nonself_args[0].clone();
    // throw an underscore in front to suppress unused variable warnings
    let blkarg = Ident::new(sym::_e, trait_span);
    let blkencoder = cx.expr_ident(trait_span, blkarg);
    let fn_path = cx.expr_path(cx.path_global(
        trait_span,
        vec![
            Ident::new(krate, trait_span),
            Ident::new(sym::Encodable, trait_span),
            Ident::new(sym::encode, trait_span),
        ],
    ));

    match *substr.fields {
        Struct(_, ref fields) => {
            let emit_struct_field = Ident::new(sym::emit_struct_field, trait_span);
            let mut stmts = Vec::new();
            for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
                let name = match name {
                    Some(id) => id.name,
                    None => Symbol::intern(&format!("_field{}", i)),
                };
                let self_ref = cx.expr_addr_of(span, self_.clone());
                let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]);
                let lambda = cx.lambda1(span, enc, blkarg);
                let call = cx.expr_method_call(
                    span,
                    blkencoder.clone(),
                    emit_struct_field,
                    vec![cx.expr_str(span, name), cx.expr_usize(span, i), lambda],
                );

                // last call doesn't need a try!
                let last = fields.len() - 1;
                let call = if i != last {
                    cx.expr_try(span, call)
                } else {
                    cx.expr(span, ExprKind::Ret(Some(call)))
                };

                let stmt = cx.stmt_expr(call);
                stmts.push(stmt);
            }

            // unit structs have no fields and need to return Ok()
            let blk = if stmts.is_empty() {
                let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, vec![]));
                cx.lambda1(trait_span, ok, blkarg)
            } else {
                cx.lambda_stmts_1(trait_span, stmts, blkarg)
            };

            cx.expr_method_call(
                trait_span,
                encoder,
                Ident::new(sym::emit_struct, trait_span),
                vec![
                    cx.expr_str(trait_span, substr.type_ident.name),
                    cx.expr_usize(trait_span, fields.len()),
                    blk,
                ],
            )
        }

        EnumMatching(idx, _, variant, ref fields) => {
            // We're not generating an AST that the borrow checker is expecting,
            // so we need to generate a unique local variable to take the
            // mutable loan out on, otherwise we get conflicts which don't
            // actually exist.
            let me = cx.stmt_let(trait_span, false, blkarg, encoder);
            let encoder = cx.expr_ident(trait_span, blkarg);
            let emit_variant_arg = Ident::new(sym::emit_enum_variant_arg, trait_span);
            let mut stmts = Vec::new();
            if !fields.is_empty() {
                let last = fields.len() - 1;
                for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() {
                    let self_ref = cx.expr_addr_of(span, self_.clone());
                    let enc =
                        cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]);
                    let lambda = cx.lambda1(span, enc, blkarg);
                    let call = cx.expr_method_call(
                        span,
                        blkencoder.clone(),
                        emit_variant_arg,
                        vec![cx.expr_usize(span, i), lambda],
                    );
                    let call = if i != last {
                        cx.expr_try(span, call)
                    } else {
                        cx.expr(span, ExprKind::Ret(Some(call)))
                    };
                    stmts.push(cx.stmt_expr(call));
                }
            } else {
                let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, vec![]));
                let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok)));
                stmts.push(cx.stmt_expr(ret_ok));
            }

            let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
            let name = cx.expr_str(trait_span, variant.ident.name);
            let call = cx.expr_method_call(
                trait_span,
                blkencoder,
                Ident::new(sym::emit_enum_variant, trait_span),
                vec![
                    name,
                    cx.expr_usize(trait_span, idx),
                    cx.expr_usize(trait_span, fields.len()),
                    blk,
                ],
            );
            let blk = cx.lambda1(trait_span, call, blkarg);
            let ret = cx.expr_method_call(
                trait_span,
                encoder,
                Ident::new(sym::emit_enum, trait_span),
                vec![cx.expr_str(trait_span, substr.type_ident.name), blk],
            );
            cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)]))
        }

        _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"),
    }
}
<commit_msg>use ufcs in derive(RustEncodable)<commit_after>//! The compiler code necessary to implement the `#[derive(RustcEncodable)]`
//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that
//! type-defining items may be tagged with
//! `#[derive(RustcEncodable, RustcDecodable)]`.
//!
//! For example, a type like:
//!
//! ```
//! #[derive(RustcEncodable, RustcDecodable)]
//! struct Node { id: usize }
//! ```
//!
//! would generate two implementations like:
//!
//! ```
//! # struct Node { id: usize }
//! impl<S: Encoder<E>, E> Encodable<S, E> for Node {
//!     fn encode(&self, s: &mut S) -> Result<(), E> {
//!         s.emit_struct("Node", 1, |this| {
//!             this.emit_struct_field("id", 0, |this| {
//!                 Encodable::encode(&self.id, this)
//!                 /* this.emit_usize(self.id) can also be used */
//!             })
//!         })
//!     }
//! }
//!
//! impl<D: Decoder<E>, E> Decodable<D, E> for Node {
//!     fn decode(d: &mut D) -> Result<Node, E> {
//!         d.read_struct("Node", 1, |this| {
//!             match this.read_struct_field("id", 0, |this| Decodable::decode(this)) {
//!                 Ok(id) => Ok(Node { id: id }),
//!                 Err(e) => Err(e),
//!             }
//!         })
//!     }
//! }
//! ```
//!
//! Other interesting scenarios are when the item has type parameters or
//! references other non-built-in types. A type definition like:
//!
//! ```
//! # #[derive(RustcEncodable, RustcDecodable)]
//! # struct Span;
//! #[derive(RustcEncodable, RustcDecodable)]
//! struct Spanned<T> { node: T, span: Span }
//! ```
//!
//! would yield functions like:
//!
//! ```
//! # #[derive(RustcEncodable, RustcDecodable)]
//! # struct Span;
//! # struct Spanned<T> { node: T, span: Span }
//! impl<
//!     S: Encoder<E>,
//!     E,
//!     T: Encodable<S, E>
//! > Encodable<S, E> for Spanned<T> {
//!     fn encode(&self, s: &mut S) -> Result<(), E> {
//!         s.emit_struct("Spanned", 2, |this| {
//!             this.emit_struct_field("node", 0, |this| self.node.encode(this))
//!                 .unwrap();
//!             this.emit_struct_field("span", 1, |this| self.span.encode(this))
//!         })
//!     }
//! }
//!
//! impl<
//!     D: Decoder<E>,
//!     E,
//!     T: Decodable<D, E>
//! > Decodable<D, E> for Spanned<T> {
//!     fn decode(d: &mut D) -> Result<Spanned<T>, E> {
//!         d.read_struct("Spanned", 2, |this| {
//!             Ok(Spanned {
//!                 node: this.read_struct_field("node", 0, |this| Decodable::decode(this))
//!                     .unwrap(),
//!                 span: this.read_struct_field("span", 1, |this| Decodable::decode(this))
//!                     .unwrap(),
//!             })
//!         })
//!     }
//! }
//! ```

use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::pathvec_std;

use rustc_ast::ptr::P;
use rustc_ast::{Expr, ExprKind, MetaItem, Mutability};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;

pub fn expand_deriving_rustc_encodable(
    cx: &mut ExtCtxt<'_>,
    span: Span,
    mitem: &MetaItem,
    item: &Annotatable,
    push: &mut dyn FnMut(Annotatable),
) {
    let krate = sym::rustc_serialize;
    let typaram = sym::__S;

    let trait_def = TraitDef {
        span,
        attributes: Vec::new(),
        path: Path::new_(vec![krate, sym::Encodable], None, vec![], PathKind::Global),
        additional_bounds: Vec::new(),
        generics: Bounds::empty(),
        is_unsafe: false,
        supports_unions: false,
        methods: vec![MethodDef {
            name: sym::encode,
            generics: Bounds {
                bounds: vec![(
                    typaram,
                    vec![Path::new_(vec![krate, sym::Encoder], None, vec![], PathKind::Global)],
                )],
            },
            explicit_self: borrowed_explicit_self(),
            args: vec![(
                Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
                // FIXME: we could use `sym::s` here, but making `s` a static
                // symbol changes the symbol index ordering in a way that makes
                // ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
                // fail. The linting code should be fixed so that its output
                // does not depend on the symbol index ordering.
                Symbol::intern("s"),
            )],
            ret_ty: Literal(Path::new_(
                pathvec_std!(result::Result),
                None,
                vec![
                    Box::new(Tuple(Vec::new())),
                    Box::new(Literal(Path::new_(
                        vec![typaram, sym::Error],
                        None,
                        vec![],
                        PathKind::Local,
                    ))),
                ],
                PathKind::Std,
            )),
            attributes: Vec::new(),
            is_unsafe: false,
            unify_fieldless_variants: false,
            combine_substructure: combine_substructure(Box::new(|a, b, c| {
                encodable_substructure(a, b, c, krate)
            })),
        }],
        associated_types: Vec::new(),
    };

    trait_def.expand(cx, mitem, item, push)
}

fn encodable_substructure(
    cx: &mut ExtCtxt<'_>,
    trait_span: Span,
    substr: &Substructure<'_>,
    krate: Symbol,
) -> P<Expr> {
    let encoder = substr.nonself_args[0].clone();
    // throw an underscore in front to suppress unused variable warnings
    let blkarg = Ident::new(sym::_e, trait_span);
    let blkencoder = cx.expr_ident(trait_span, blkarg);
    let fn_path = cx.expr_path(cx.path_global(
        trait_span,
        vec![
            Ident::new(krate, trait_span),
            Ident::new(sym::Encodable, trait_span),
            Ident::new(sym::encode, trait_span),
        ],
    ));

    match *substr.fields {
        Struct(_, ref fields) => {
            let fn_emit_struct_field_path =
                cx.def_site_path(&[sym::rustc_serialize, sym::Encodable, sym::emit_struct_field]);
            let mut stmts = Vec::new();
            for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
                let name = match name {
                    Some(id) => id.name,
                    None => Symbol::intern(&format!("_field{}", i)),
                };
                let self_ref = cx.expr_addr_of(span, self_.clone());
                let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]);
                let lambda = cx.lambda1(span, enc, blkarg);
                let call = cx.expr_call_global(
                    span,
                    fn_emit_struct_field_path.clone(),
                    vec![
                        blkencoder.clone(),
                        cx.expr_str(span, name),
                        cx.expr_usize(span, i),
                        lambda,
                    ],
                );

                // last call doesn't need a try!
                let last = fields.len() - 1;
                let call = if i != last {
                    cx.expr_try(span, call)
                } else {
                    cx.expr(span, ExprKind::Ret(Some(call)))
                };

                let stmt = cx.stmt_expr(call);
                stmts.push(stmt);
            }

            // unit structs have no fields and need to return Ok()
            let blk = if stmts.is_empty() {
                let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, vec![]));
                cx.lambda1(trait_span, ok, blkarg)
            } else {
                cx.lambda_stmts_1(trait_span, stmts, blkarg)
            };

            let fn_emit_struct_path =
                cx.def_site_path(&[sym::rustc_serialize, sym::Encodable, sym::emit_struct]);

            cx.expr_call_global(
                trait_span,
                fn_emit_struct_path,
                vec![
                    encoder,
                    cx.expr_str(trait_span, substr.type_ident.name),
                    cx.expr_usize(trait_span, fields.len()),
                    blk,
                ],
            )
        }

        EnumMatching(idx, _, variant, ref fields) => {
            // We're not generating an AST that the borrow checker is expecting,
            // so we need to generate a unique local variable to take the
            // mutable loan out on, otherwise we get conflicts which don't
            // actually exist.
            let me = cx.stmt_let(trait_span, false, blkarg, encoder);
            let encoder = cx.expr_ident(trait_span, blkarg);

            let fn_emit_enum_variant_arg_path: Vec<_> = cx.def_site_path(&[
                sym::rustc_serialize,
                sym::Encodable,
                sym::emit_enum_variant_arg,
            ]);

            let mut stmts = Vec::new();
            if !fields.is_empty() {
                let last = fields.len() - 1;
                for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() {
                    let self_ref = cx.expr_addr_of(span, self_.clone());
                    let enc =
                        cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]);
                    let lambda = cx.lambda1(span, enc, blkarg);

                    let call = cx.expr_call_global(
                        span,
                        fn_emit_enum_variant_arg_path.clone(),
                        vec![blkencoder.clone(), cx.expr_usize(span, i), lambda],
                    );
                    let call = if i != last {
                        cx.expr_try(span, call)
                    } else {
                        cx.expr(span, ExprKind::Ret(Some(call)))
                    };
                    stmts.push(cx.stmt_expr(call));
                }
            } else {
                let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, vec![]));
                let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok)));
                stmts.push(cx.stmt_expr(ret_ok));
            }

            let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
            let name = cx.expr_str(trait_span, variant.ident.name);

            let fn_emit_enum_variant_path: Vec<_> =
                cx.def_site_path(&[sym::rustc_serialize, sym::Encodable, sym::emit_enum_variant]);

            let call = cx.expr_call_global(
                trait_span,
                fn_emit_enum_variant_path,
                vec![
                    blkencoder,
                    name,
                    cx.expr_usize(trait_span, idx),
                    cx.expr_usize(trait_span, fields.len()),
                    blk,
                ],
            );

            let blk = cx.lambda1(trait_span, call, blkarg);
            let fn_emit_enum_path: Vec<_> =
                cx.def_site_path(&[sym::rustc_serialize, sym::Encodable, sym::emit_enum]);
            let ret = cx.expr_call_global(
                trait_span,
                fn_emit_enum_path,
                vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk],
            );
            cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)]))
        }

        _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"),
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

//! Archiver variant which uses S3 (or an API compatible clone) for
//! log storage.
//!
//! Has been tested against both AWS S3 and [Minio](https://minio.io).
//!
//! All job logs are stored in a single bucket, using the job's ID
//! (with a `.log` extension) as the key.
//!
//! # Configuration
//!
//! Currently the archiver must be configured with both an access key
//! ID and a secret access key.
//!
use VERSION;
use aws_sdk_rust::aws::common::credentials::{DefaultCredentialsProvider, ParametersProvider};
use aws_sdk_rust::aws::common::region::Region;
use aws_sdk_rust::aws::s3::endpoint::{Endpoint, Signature};
use aws_sdk_rust::aws::s3::object::{GetObjectRequest, PutObjectRequest};
use aws_sdk_rust::aws::s3::s3client::S3Client;
use config::ArchiveCfg;
use error::{Result, Error};
use extern_url;
use hyper::client::Client as HyperClient;
use std::fs::OpenOptions;
use std::io::Read;
use std::panic::{self, AssertUnwindSafe};
use std::path::PathBuf;
use std::str::FromStr;

use super::LogArchiver;

pub struct S3Archiver {
    client: S3Client<DefaultCredentialsProvider, HyperClient>,
    bucket: String,
}

impl S3Archiver {
    pub fn new(config: ArchiveCfg) -> Result<S3Archiver> {
        let region = Region::from_str(config.region.as_str()).unwrap();
        let param_provider: Option<ParametersProvider>;
        param_provider = Some(
            ParametersProvider::with_parameters(
                config.key.expect("Missing S3 key!"),
                config.secret.expect("Missing S3 secret!").as_str(),
                None,
            ).unwrap(),
        );
        // If given an endpoint, don't use virtual buckets... if not,
        // assume AWS and use virtual buckets.
        //
        // There may be a way to set Minio up to use virtual buckets,
        // but I haven't been able to find it... if there is, then we
        // can go ahead and make this a configuration parameter as well.
        let use_virtual_buckets = !config.endpoint.is_some();

        // Parameterize this if anyone ends up needing V2 signatures
        let signature_type = Signature::V4;
        let final_endpoint = match config.endpoint {
            Some(url) => Some(extern_url::Url::parse(url.as_str())?),
            None => None,
        };
        let user_agent = format!("Habitat-Builder/{}", VERSION);

        let provider = DefaultCredentialsProvider::new(param_provider).unwrap();
        let endpoint = Endpoint::new(
            region,
            signature_type,
            final_endpoint,
            None,
            Some(user_agent),
            Some(use_virtual_buckets),
        );

        let client = S3Client::new(provider, endpoint);

        Ok(S3Archiver {
            client: client,
            bucket: config.bucket.expect("Missing Bucket Name!"),
        })
    }

    /// Generates the bucket key under which the job log will be
    /// stored.
    fn key(job_id: u64) -> String {
        format!("{}.log", job_id)
    }
}

impl LogArchiver for S3Archiver {
    fn archive(&self, job_id: u64, file_path: &PathBuf) -> Result<()> {
        let mut buffer = Vec::new();
        let mut put_object = PutObjectRequest::default();
        put_object.bucket = self.bucket.clone();
        put_object.key = Self::key(job_id);

        let mut file = OpenOptions::new().read(true).open(file_path)?;
        file.read_to_end(&mut buffer)?;
        put_object.body = Some(buffer.as_slice());

        // This panics if it can't resolve the URL (e.g.,
        // there's a netsplit, your Minio goes down, S3 goes down (!)).
        // We have to catch it, otherwise no more logs get captured!
        //
        // The code in the S3 library we're currently using isn't
        // UnwindSafe, so we need to deal with that, too.
        let result = panic::catch_unwind(AssertUnwindSafe(
            || self.client.put_object(&put_object, None),
        ));

        match result {
            Ok(Ok(_)) => Ok(()), // normal result
            Ok(Err(e)) => {
                // This is a "normal", non-panicking error, e.g.,
                // they're configured with a non-existent bucket.
                Err(Error::JobLogArchive(job_id, e))
            }
            Err(e) => {
                let source = match e.downcast_ref::<String>() {
                    Some(string) => string.to_string(),
                    None => format!("{:?}", e),
                };
                Err(Error::CaughtPanic(
                    format!("Failure to archive log for job {}", job_id),
                    source,
                ))
            }
        }
    }

    fn retrieve(&self, job_id: u64) -> Result<Vec<String>> {
        let mut request = GetObjectRequest::default();
        request.bucket = self.bucket.clone();
        request.key = Self::key(job_id);

        // As above when uploading a job file, we currently need to
        // catch a potential panic if the object store cannot be reached
        let result =
            panic::catch_unwind(AssertUnwindSafe(|| self.client.get_object(&request, None)));

        let body = match result {
            Ok(Ok(response)) => response.body, // normal result
            Ok(Err(e)) => {
                // This is a "normal", non-panicking error, e.g.,
                // they're configured with a non-existent bucket.
                return Err(Error::JobLogRetrieval(job_id, e));
            }
            Err(e) => {
                let source = match e.downcast_ref::<String>() {
                    Some(string) => string.to_string(),
                    None => format!("{:?}", e),
                };
                return Err(Error::CaughtPanic(
                    format!(
                        "Failure to retrieve archived log for job {}",
                        job_id
                    ),
                    source,
                ));
            }
        };

        let lines = String::from_utf8_lossy(body.as_slice())
            .lines()
            .map(|l| l.to_string())
            .collect();

        Ok(lines)
    }
}
<commit_msg>Provide better feedback given an invalid endpoint URL<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

//! Archiver variant which uses S3 (or an API compatible clone) for
//! log storage.
//!
//! Has been tested against both AWS S3 and [Minio](https://minio.io).
//!
//! All job logs are stored in a single bucket, using the job's ID
//! (with a `.log` extension) as the key.
//!
//! # Configuration
//!
//! Currently the archiver must be configured with both an access key
//! ID and a secret access key.
//!
use VERSION;
use aws_sdk_rust::aws::common::credentials::{DefaultCredentialsProvider, ParametersProvider};
use aws_sdk_rust::aws::common::region::Region;
use aws_sdk_rust::aws::s3::endpoint::{Endpoint, Signature};
use aws_sdk_rust::aws::s3::object::{GetObjectRequest, PutObjectRequest};
use aws_sdk_rust::aws::s3::s3client::S3Client;
use config::ArchiveCfg;
use error::{Result, Error};
use extern_url;
use hyper::client::Client as HyperClient;
use std::fs::OpenOptions;
use std::io::Read;
use std::panic::{self, AssertUnwindSafe};
use std::path::PathBuf;
use std::str::FromStr;

use super::LogArchiver;

pub struct S3Archiver {
    client: S3Client<DefaultCredentialsProvider, HyperClient>,
    bucket: String,
}

impl S3Archiver {
    pub fn new(config: ArchiveCfg) -> Result<S3Archiver> {
        let region = Region::from_str(config.region.as_str()).unwrap();
        let param_provider: Option<ParametersProvider>;
        param_provider = Some(
            ParametersProvider::with_parameters(
                config.key.expect("Missing S3 key!"),
                config.secret.expect("Missing S3 secret!").as_str(),
                None,
            ).unwrap(),
        );
        // If given an endpoint, don't use virtual buckets... if not,
        // assume AWS and use virtual buckets.
        //
        // There may be a way to set Minio up to use virtual buckets,
        // but I haven't been able to find it... if there is, then we
        // can go ahead and make this a configuration parameter as well.
        let use_virtual_buckets = !config.endpoint.is_some();

        // Parameterize this if anyone ends up needing V2 signatures
        let signature_type = Signature::V4;
        let final_endpoint = match config.endpoint {
            Some(url) => {
                let url = extern_url::Url::parse(url.as_str())
                    .expect("Invalid endpoint URL given");
                Some(url)
            },
            None => None,
        };
        let user_agent = format!("Habitat-Builder/{}", VERSION);

        let provider = DefaultCredentialsProvider::new(param_provider).unwrap();
        let endpoint = Endpoint::new(
            region,
            signature_type,
            final_endpoint,
            None,
            Some(user_agent),
            Some(use_virtual_buckets),
        );

        let client = S3Client::new(provider, endpoint);

        Ok(S3Archiver {
            client: client,
            bucket: config.bucket.expect("Missing Bucket Name!"),
        })
    }

    /// Generates the bucket key under which the job log will be
    /// stored.
    fn key(job_id: u64) -> String {
        format!("{}.log", job_id)
    }
}

impl LogArchiver for S3Archiver {
    fn archive(&self, job_id: u64, file_path: &PathBuf) -> Result<()> {
        let mut buffer = Vec::new();
        let mut put_object = PutObjectRequest::default();
        put_object.bucket = self.bucket.clone();
        put_object.key = Self::key(job_id);

        let mut file = OpenOptions::new().read(true).open(file_path)?;
        file.read_to_end(&mut buffer)?;
        put_object.body = Some(buffer.as_slice());

        // This panics if it can't resolve the URL (e.g.,
        // there's a netsplit, your Minio goes down, S3 goes down (!)).
        // We have to catch it, otherwise no more logs get captured!
        //
        // The code in the S3 library we're currently using isn't
        // UnwindSafe, so we need to deal with that, too.
        let result = panic::catch_unwind(AssertUnwindSafe(
            || self.client.put_object(&put_object, None),
        ));

        match result {
            Ok(Ok(_)) => Ok(()), // normal result
            Ok(Err(e)) => {
                // This is a "normal", non-panicking error, e.g.,
                // they're configured with a non-existent bucket.
                Err(Error::JobLogArchive(job_id, e))
            }
            Err(e) => {
                let source = match e.downcast_ref::<String>() {
                    Some(string) => string.to_string(),
                    None => format!("{:?}", e),
                };
                Err(Error::CaughtPanic(
                    format!("Failure to archive log for job {}", job_id),
                    source,
                ))
            }
        }
    }

    fn retrieve(&self, job_id: u64) -> Result<Vec<String>> {
        let mut request = GetObjectRequest::default();
        request.bucket = self.bucket.clone();
        request.key = Self::key(job_id);

        // As above when uploading a job file, we currently need to
        // catch a potential panic if the object store cannot be reached
        let result =
            panic::catch_unwind(AssertUnwindSafe(|| self.client.get_object(&request, None)));

        let body = match result {
            Ok(Ok(response)) => response.body, // normal result
            Ok(Err(e)) => {
                // This is a "normal", non-panicking error, e.g.,
                // they're configured with a non-existent bucket.
                return Err(Error::JobLogRetrieval(job_id, e));
            }
            Err(e) => {
                let source = match e.downcast_ref::<String>() {
                    Some(string) => string.to_string(),
                    None => format!("{:?}", e),
                };
                return Err(Error::CaughtPanic(
                    format!(
                        "Failure to retrieve archived log for job {}",
                        job_id
                    ),
                    source,
                ));
            }
        };

        let lines = String::from_utf8_lossy(body.as_slice())
            .lines()
            .map(|l| l.to_string())
            .collect();

        Ok(lines)
    }
}
<|endoftext|>


<commit_before>use raw::*;
use function::UncompiledFunction;
use function::Abi::CDecl;
use types::get;
use libc::c_long;
use types::{consts, CowType, Type};
use util::from_ptr;
use value::Val;
use std::ffi::CStr;
use std::mem;
/// A type that can be compiled into a LibJIT representation
///
/// The lifetime is the context's lifetime
pub trait Compile<'a> {
    /// Get a JIT representation of this value
    fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val;
    /// Get the type descriptor that represents this type
    fn get_type() -> CowType<'a>;
}
impl<'a> Compile<'a> for () {
    #[inline(always)]
    fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val {
        Val::new(func, consts::get_void())
    }
    #[inline(always)]
    fn get_type() -> CowType<'a> {
        consts::get_void().into()
    }
}
compile_prims!{
    (f64, f64) => (get_float64, jit_value_create_float64_constant),
    (f32, f32) => (get_float32, jit_value_create_float32_constant),
    (isize, c_long) => (get_nint, jit_value_create_nint_constant),
    (usize, c_long) => (get_nuint, jit_value_create_nint_constant),
    (i64, c_long) => (get_long, jit_value_create_long_constant),
    (u64, c_long) => (get_ulong, jit_value_create_long_constant),
    (i32, c_long) => (get_int, jit_value_create_nint_constant),
    (u32, c_long) => (get_uint, jit_value_create_nint_constant),
    (i16, c_long) => (get_short, jit_value_create_nint_constant),
    (u16, c_long) => (get_ushort, jit_value_create_nint_constant),
    (i8, c_long) => (get_sbyte, jit_value_create_nint_constant),
    (u8, c_long) => (get_ubyte, jit_value_create_nint_constant),
    (bool, c_long) => (get_sys_bool, jit_value_create_nint_constant),
    (char, c_long) => (get_sys_char, jit_value_create_nint_constant)
}
impl<'a, T> Compile<'a> for &'a T where T:Compile<'a>+Sized {
    #[inline(always)]
    fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val {
        unsafe {
            let ty = <&'a T as Compile<'a>>::get_type();
            from_ptr(jit_value_create_nint_constant(
                func.into(),
                (&*ty).into(),
                mem::transmute(self)
            ))
        }
    }
    #[inline(always)]
    fn get_type() -> CowType<'a> {
        Type::new_pointer(&get::<T>()).into()
    }
}

impl<'a> Compile<'a> for &'a str {
    #[inline(always)]
    fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val {
        unsafe {
            use std::raw::Repr;
            use std::mem::transmute as cast;
            let slice = self.repr();
            let ty = <Self as Compile<'a>>::get_type();
            let structure = Val::new(func, &ty);
            let offset_data = cast::<_, usize>(&slice.data) - cast(&slice);
            let offset_len = cast::<_, usize>(&slice.len) - cast(&slice);
            func.insn_store_relative(structure, offset_data, func.insn_of(mem::transmute::<_, isize>(slice.data)));
            func.insn_store_relative(structure, offset_len, func.insn_of(slice.len));
            structure
        }
    }
    #[inline(always)]
    fn get_type() -> CowType<'a> {
        use std::raw::Slice;
        let ty = Type::new_struct(&mut [&get::<&'static u8>(), &get::<usize>()]);
        unsafe {
            jit_type_set_size_and_alignment((&ty).into(), mem::size_of::<Slice<u8>>() as i64, mem::align_of::<Slice<u8>>() as i64);
        }
        ty.into()
    }
}
impl<'a> Compile<'a> for &'a CStr {
    #[inline(always)]
    fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val {
        let bytes = self.to_bytes();
        unsafe { mem::transmute::<_, isize>(bytes.as_ptr()) }.compile(func)
    }
    #[inline(always)]
    fn get_type() -> CowType<'a> {
        Type::new_pointer(consts::get_sys_char()).into()
    }
}
compile_tuple!(A, B => a, b);
compile_tuple!(A, B, C => a, b, c);
compile_tuple!(A, B, C, D => a, b, c, d);
compile_tuple!(A, B, C, D, E => a, b, c, d, e);
compile_func!(fn() -> R, fn() -> R, extern fn() -> R);
compile_func!(fn(A) -> R, fn(A) -> R, extern fn(A) -> R);
compile_func!(fn(A, B) -> R, fn(A, B) -> R, extern fn(A, B) -> R);
compile_func!(fn(A, B, C) -> R, fn(A, B, C) -> R, extern fn(A, B, C) -> R);
compile_func!(fn(A, B, C, D) -> R, fn(A, B, C, D) -> R, extern fn(A, B, C, D) -> R);
<commit_msg>Fix ICE and cast errors<commit_after>use raw::*;
use function::UncompiledFunction;
use function::Abi::CDecl;
use types::get;
use libc::c_long;
use types::{consts, CowType, Type};
use util::from_ptr;
use value::Val;
use std::ffi::CStr;
use std::mem;
/// A type that can be compiled into a LibJIT representation
///
/// The lifetime is the context's lifetime
pub trait Compile<'a> {
    /// Get a JIT representation of this value
    fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val;
    /// Get the type descriptor that represents this type
    fn get_type() -> CowType<'a>;
}
impl<'a> Compile<'a> for () {
    #[inline(always)]
    fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val {
        Val::new(func, consts::get_void())
    }
    #[inline(always)]
    fn get_type() -> CowType<'a> {
        consts::get_void().into()
    }
}
compile_prims!{
    (f64, f64) => (get_float64, jit_value_create_float64_constant),
    (f32, f32) => (get_float32, jit_value_create_float32_constant),
    (isize, c_long) => (get_nint, jit_value_create_nint_constant),
    (usize, c_long) => (get_nuint, jit_value_create_nint_constant),
    (i64, c_long) => (get_long, jit_value_create_long_constant),
    (u64, c_long) => (get_ulong, jit_value_create_long_constant),
    (i32, c_long) => (get_int, jit_value_create_nint_constant),
    (u32, c_long) => (get_uint, jit_value_create_nint_constant),
    (i16, c_long) => (get_short, jit_value_create_nint_constant),
    (u16, c_long) => (get_ushort, jit_value_create_nint_constant),
    (i8, c_long) => (get_sbyte, jit_value_create_nint_constant),
    (u8, c_long) => (get_ubyte, jit_value_create_nint_constant),
    (bool, c_long) => (get_sys_bool, jit_value_create_nint_constant),
    (char, c_long) => (get_sys_char, jit_value_create_nint_constant)
}
impl<'a, T> Compile<'a> for &'a T where T:Compile<'a>+Sized {
    #[inline(always)]
    fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val {
        unsafe {
            let ty = <&'a T as Compile<'a>>::get_type();
            from_ptr(jit_value_create_nint_constant(
                func.into(),
                (&*ty).into(),
                mem::transmute(self)
            ))
        }
    }
    #[inline(always)]
    fn get_type() -> CowType<'a> {
        Type::new_pointer(&get::<T>()).into()
    }
}

impl<'a> Compile<'a> for &'a str {
    #[inline(always)]
    fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val {
        unsafe {
            use std::raw::Repr;
            use std::mem::transmute as cast;
            let slice = self.repr();
            let ty = <&'a str as Compile<'a>>::get_type();
            let structure = Val::new(func, &ty);
            let offset_data = cast::<_, usize>(&slice.data) - cast::<_, usize>(&slice);
            let offset_len = cast::<_, usize>(&slice.len) - cast::<_, usize>(&slice);
            func.insn_store_relative(structure, offset_data, func.insn_of(mem::transmute::<_, isize>(slice.data)));
            func.insn_store_relative(structure, offset_len, func.insn_of(slice.len));
            structure
        }
    }
    #[inline(always)]
    fn get_type() -> CowType<'a> {
        use std::raw::Slice;
        let ty = Type::new_struct(&mut [&get::<&'static u8>(), &get::<usize>()]);
        unsafe {
            jit_type_set_size_and_alignment((&ty).into(), mem::size_of::<Slice<u8>>() as i64, mem::align_of::<Slice<u8>>() as i64);
        }
        ty.into()
    }
}
impl<'a> Compile<'a> for &'a CStr {
    #[inline(always)]
    fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val {
        let bytes = self.to_bytes();
        unsafe { mem::transmute::<_, isize>(bytes.as_ptr()) }.compile(func)
    }
    #[inline(always)]
    fn get_type() -> CowType<'a> {
        Type::new_pointer(consts::get_sys_char()).into()
    }
}
compile_tuple!(A, B => a, b);
compile_tuple!(A, B, C => a, b, c);
compile_tuple!(A, B, C, D => a, b, c, d);
compile_tuple!(A, B, C, D, E => a, b, c, d, e);
compile_func!(fn() -> R, fn() -> R, extern fn() -> R);
compile_func!(fn(A) -> R, fn(A) -> R, extern fn(A) -> R);
compile_func!(fn(A, B) -> R, fn(A, B) -> R, extern fn(A, B) -> R);
compile_func!(fn(A, B, C) -> R, fn(A, B, C) -> R, extern fn(A, B, C) -> R);
compile_func!(fn(A, B, C, D) -> R, fn(A, B, C, D) -> R, extern fn(A, B, C, D) -> R);
<|endoftext|>


<commit_before>use std::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
use libc::{size_t, malloc, sockaddr, sockaddr_in, sockaddr_in6, in_addr, in6_addr, c_int, c_char, socklen_t, AF_INET, AF_INET6};
use std::mem::{size_of, transmute};
use std::string;

/*
 const char *
     inet_ntop(int af, const void * restrict src, char * restrict dst,
         socklen_t size);
*/
extern {
    fn getnameinfo(sa: *const sockaddr, salen: socklen_t,
                   host: *mut c_char, hostlen: socklen_t,
                   serv: *mut c_char, servlen: socklen_t,
                   flags: c_int) -> c_int;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn new_sockaddr_in(port: u16, addr: in_addr) -> sockaddr_in {
    sockaddr_in {
        sin_family: AF_INET as u16,
        sin_port: port,
        sin_addr: addr,
        sin_zero: [0, ..8]
    }
}
#[cfg(target_os = "macos")]
fn new_sockaddr_in(port: u16, addr: in_addr) -> sockaddr_in {
    sockaddr_in {
        sin_len: size_of::<sockaddr_in>() as u8,
        sin_family: AF_INET as u8,
        sin_port: port,
        sin_addr: addr,
        sin_zero: [0, ..8]
    }
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn new_sockaddr_in6(port: u16, addr: in6_addr) -> sockaddr_in6 {
    sockaddr_in6 {
        sin6_family: AF_INET6 as u16,
        sin6_port: port,
        sin6_flowinfo: 0,
        sin6_addr: addr,
        sin6_scope_id: 0,
    }
}
#[cfg(target_os = "macos")]
fn new_sockaddr_in6(port: u16, addr: in6_addr) -> sockaddr_in6 {
    sockaddr_in6 {
        sin6_len: size_of::<sockaddr_in6>() as u8,
        sin6_family: AF_INET6 as u8,
        sin6_port: port,
        sin6_flowinfo: 0,
        sin6_addr: addr,
        sin6_scope_id: 0,
    }
}

//static NI_NUMERICHOST: c_int = 0x00000002;
//static NI_NAMEREQD: c_int = 0x00000004;

/// Returns the hostname for an ip address
/// TODO: make this safe, see manpage
pub fn get_nameinfo(peer_socket: SocketAddr) -> String {
    let SocketAddr { ip: ip, port: port } = peer_socket;
    let buf: *mut i8;
    let _ = unsafe {
        let hostlen = 80;
        buf = transmute(malloc(hostlen as size_t + 1));
        match ip {
            Ipv4Addr(a, b, c, d) => {
                let addr = in_addr {
                    s_addr: a as u32 << 24
                          | b as u32 << 16
                          | c as u32 << 8
                          | d as u32
                };
                let sockaddr = new_sockaddr_in(port, addr);
                getnameinfo(transmute(&sockaddr), size_of::<sockaddr_in>() as socklen_t,
                            buf, hostlen, transmute(0u), 0, 0)
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let addr = in6_addr {
                    s6_addr: [a, b, c, d, e, f, g, h]
                };
                let sockaddr = new_sockaddr_in6(port, addr);
                getnameinfo(transmute(&sockaddr), size_of::<sockaddr_in6>() as socklen_t,
                            buf, hostlen, transmute(0u), 0, 0)
            },
        }

    };
    unsafe {string::raw::from_buf(transmute(buf))}

}
<commit_msg>update to new destructuring syntax<commit_after>use std::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
use libc::{size_t, malloc, sockaddr, sockaddr_in, sockaddr_in6, in_addr, in6_addr, c_int, c_char, socklen_t, AF_INET, AF_INET6};
use std::mem::{size_of, transmute};
use std::string;

/*
 const char *
     inet_ntop(int af, const void * restrict src, char * restrict dst,
         socklen_t size);
*/
extern {
    fn getnameinfo(sa: *const sockaddr, salen: socklen_t,
                   host: *mut c_char, hostlen: socklen_t,
                   serv: *mut c_char, servlen: socklen_t,
                   flags: c_int) -> c_int;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn new_sockaddr_in(port: u16, addr: in_addr) -> sockaddr_in {
    sockaddr_in {
        sin_family: AF_INET as u16,
        sin_port: port,
        sin_addr: addr,
        sin_zero: [0, ..8]
    }
}
#[cfg(target_os = "macos")]
fn new_sockaddr_in(port: u16, addr: in_addr) -> sockaddr_in {
    sockaddr_in {
        sin_len: size_of::<sockaddr_in>() as u8,
        sin_family: AF_INET as u8,
        sin_port: port,
        sin_addr: addr,
        sin_zero: [0, ..8]
    }
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn new_sockaddr_in6(port: u16, addr: in6_addr) -> sockaddr_in6 {
    sockaddr_in6 {
        sin6_family: AF_INET6 as u16,
        sin6_port: port,
        sin6_flowinfo: 0,
        sin6_addr: addr,
        sin6_scope_id: 0,
    }
}
#[cfg(target_os = "macos")]
fn new_sockaddr_in6(port: u16, addr: in6_addr) -> sockaddr_in6 {
    sockaddr_in6 {
        sin6_len: size_of::<sockaddr_in6>() as u8,
        sin6_family: AF_INET6 as u8,
        sin6_port: port,
        sin6_flowinfo: 0,
        sin6_addr: addr,
        sin6_scope_id: 0,
    }
}

//static NI_NUMERICHOST: c_int = 0x00000002;
//static NI_NAMEREQD: c_int = 0x00000004;

/// Returns the hostname for an ip address
/// TODO: make this safe, see manpage
pub fn get_nameinfo(peer_socket: SocketAddr) -> String {
    let SocketAddr { ip, port } = peer_socket;
    let buf: *mut i8;
    let _ = unsafe {
        let hostlen = 80;
        buf = transmute(malloc(hostlen as size_t + 1));
        match ip {
            Ipv4Addr(a, b, c, d) => {
                let addr = in_addr {
                    s_addr: a as u32 << 24
                          | b as u32 << 16
                          | c as u32 << 8
                          | d as u32
                };
                let sockaddr = new_sockaddr_in(port, addr);
                getnameinfo(transmute(&sockaddr), size_of::<sockaddr_in>() as socklen_t,
                            buf, hostlen, transmute(0u), 0, 0)
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let addr = in6_addr {
                    s6_addr: [a, b, c, d, e, f, g, h]
                };
                let sockaddr = new_sockaddr_in6(port, addr);
                getnameinfo(transmute(&sockaddr), size_of::<sockaddr_in6>() as socklen_t,
                            buf, hostlen, transmute(0u), 0, 0)
            },
        }

    };
    unsafe {string::raw::from_buf(transmute(buf))}

}
<|endoftext|>