<commit_before>/// The tokenizer for the query interpreter

use error::*;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
    Identifier {
        ident: String,
        next: Option<Box<Token>>
    },

    Index {
        idx: usize,
        next: Option<Box<Token>>
    }
}

impl Token {

    pub fn next(&self) -> Option<&Box<Token>> {
        match self {
            &Token::Identifier { ref next, .. } => next.as_ref(),
            &Token::Index { ref next, .. }      => next.as_ref(),
        }
    }

    pub fn set_next(&mut self, token: Token) {
        match self {
            &mut Token::Identifier { ref mut next, .. } => *next = Some(Box::new(token)),
            &mut Token::Index { ref mut next, .. }      => *next = Some(Box::new(token)),
        }
    }

    /// Pop the last token from the chain of tokens
    ///
    /// Returns None if the current Token has no next token
    pub fn pop_last(&mut self) -> Option<Box<Token>> {
        unimplemented!()
    }

    #[cfg(test)]
    pub fn identifier(&self) -> &String {
        match self {
            &Token::Identifier { ref ident, .. } => &ident,
            _ => unreachable!(),
        }
    }

}

pub fn tokenize_with_seperator(query: &String, seperator: char) -> Result<Token> {
    use std::str::Split;

    /// Creates a Token object from a string
    ///
    /// # Panics
    ///
    /// * If the internal regex does not compile (should never happen)
    /// * If the token is non-valid (that is, a array index with a non-i64)
    /// * If the regex does not find anything
    /// * If the integer in the brackets (`[]`) cannot be parsed to a valid i64
    ///
    /// # Incorrect behaviour
    ///
    /// * If the regex finds multiple captures
    ///
    /// # Returns
    ///
    /// The `Token` object with the correct identifier/index for this token and no next token.
    ///
    fn mk_token_object(s: &str) -> Result<Token> {
        use regex::Regex;
        use std::str::FromStr;

        lazy_static! {
            static ref RE: Regex = Regex::new(r"^\[\d+\]$").unwrap();
        }

        if !has_array_brackets(s) {
            return Ok(Token::Identifier { ident: String::from(s), next: None });
        }

        match RE.captures(s) {
            None => return Err(Error::from(ErrorKind::ArrayAccessWithoutIndex)),
            Some(captures) => {
                match captures.get(0) {
                    None => Ok(Token::Identifier { ident: String::from(s), next: None }),
                    Some(mtch) => {
                        let mtch = without_array_brackets(mtch.as_str());
                        let i : usize = FromStr::from_str(&mtch).unwrap(); // save because regex
                        Ok(Token::Index {
                            idx: i,
                            next: None,
                        })
                    }
                }
            }
        }
    }

    /// Check whether a str begins with '[' and ends with ']'
    fn has_array_brackets(s: &str) -> bool {
        s.as_bytes()[0] == b'[' && s.as_bytes()[s.len() - 1] == b']'
    }

    /// Remove '[' and ']' from a str
    fn without_array_brackets(s: &str) -> String {
        s.replace("[","").replace("]","")
    }

    fn build_token_tree(split: &mut Split<char>, last: &mut Token) -> Result<()> {
        match split.next() {
            None        => { /* No more tokens */ }
            Some(token) => {
                if token.len() == 0 {
                    return Err(Error::from(ErrorKind::EmptyIdentifier));
                }
                let mut token = try!(mk_token_object(token));
                try!(build_token_tree(split, &mut token));
                last.set_next(token);
            }
        }
        Ok(())
    }

    if query.is_empty() {
        return Err(Error::from(ErrorKind::EmptyQueryError));
    }

    let mut tokens = query.split(seperator);

    match tokens.next() {
        None        => Err(Error::from(ErrorKind::EmptyQueryError)),
        Some(token) => {
            if token.len() == 0 {
                return Err(Error::from(ErrorKind::EmptyIdentifier));
            }
            let mut tok = try!(mk_token_object(token));
            let _       = try!(build_token_tree(&mut tokens, &mut tok));
            Ok(tok)
        }
    }
}

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

    use std::ops::Deref;

    #[test]
    fn test_tokenize_empty_query_to_error() {
        let tokens = tokenize_with_seperator(&String::from(""), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyQueryError { .. }));
    }

    #[test]
    fn test_tokenize_seperator_only() {
        let tokens = tokenize_with_seperator(&String::from("."), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    #[test]
    fn test_tokenize_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_with_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_in_array_brackets() {
        let tokens = tokenize_with_seperator(&String::from("[a]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_single_token_query() {
        let tokens = tokenize_with_seperator(&String::from("example"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { ref ident, next: None } => {
                assert_eq!("example", ident);
                true
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_double_token_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                assert_eq!("b", next.deref().identifier());
                match next.deref() {
                    &Token::Identifier { next: None, .. } => true,
                    _ => false
                }
            },
            _ => false,
        });
        assert_eq!("a", tokens.identifier());
    }

    #[test]
    fn test_tokenize_ident_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.[0]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());
        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                match next.deref() {
                    &Token::Index { idx: 0, next: None } => true,
                    _ => false
                }
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_many_idents_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[1000]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());

        let expected =
            Token::Identifier {
                ident: String::from("a"),
                next: Some(Box::new(Token::Identifier {
                    ident: String::from("b"),
                    next: Some(Box::new(Token::Identifier {
                        ident: String::from("c"),
                        next: Some(Box::new(Token::Index {
                            idx: 1000,
                            next: None,
                        })),
                    })),
                })),
            };

        assert_eq!(expected, tokens);
    }

    #[test]
    fn test_tokenize_empty_token_after_good_token() {
        let tokens = tokenize_with_seperator(&String::from("a..b"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    quickcheck! {
        fn test_array_index(i: usize) -> bool {
            match tokenize_with_seperator(&format!("[{}]", i), '.') {
                Ok(Token::Index { next: None, ..  }) => true,
                _                                    => false,
            }
        }
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_none() {
        let mut token = Token::Identifier {
            ident: String::from("something"),
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_none() {
        let mut token = Token::Index {
            idx: 0,
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_one() {
        let mut token = Token::Identifier {
            ident: String::from("some"),
            next: Some(Box::new(Token::Identifier {
                ident: String::from("thing"),
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Identifier { .. }));
        match *last {
            Token::Identifier { ident: ident, .. } => {
                assert_eq!("thing", ident);
            }
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_one() {
        let mut token = Token::Index {
            idx: 0,
            next: Some(Box::new(Token::Index {
                idx: 1,
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Index { idx: 1, .. }));
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_one_token() {
        let tokens = tokenize_with_seperator(&String::from("a"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_none());
    }

}
<commit_msg>Impl Token::pop_last to fix test_pop_last_token_from_single_identifier_token_is_none<commit_after>/// The tokenizer for the query interpreter

use error::*;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
    Identifier {
        ident: String,
        next: Option<Box<Token>>
    },

    Index {
        idx: usize,
        next: Option<Box<Token>>
    }
}

impl Token {

    pub fn next(&self) -> Option<&Box<Token>> {
        match self {
            &Token::Identifier { ref next, .. } => next.as_ref(),
            &Token::Index { ref next, .. }      => next.as_ref(),
        }
    }

    pub fn set_next(&mut self, token: Token) {
        match self {
            &mut Token::Identifier { ref mut next, .. } => *next = Some(Box::new(token)),
            &mut Token::Index { ref mut next, .. }      => *next = Some(Box::new(token)),
        }
    }

    /// Pop the last token from the chain of tokens
    ///
    /// Returns None if the current Token has no next token
    pub fn pop_last(&mut self) -> Option<Box<Token>> {
        if !self.has_next() {
            None
        } else {
            unimplemented!()
        }
    }

    #[cfg(test)]
    pub fn identifier(&self) -> &String {
        match self {
            &Token::Identifier { ref ident, .. } => &ident,
            _ => unreachable!(),
        }
    }

}

pub fn tokenize_with_seperator(query: &String, seperator: char) -> Result<Token> {
    use std::str::Split;

    /// Creates a Token object from a string
    ///
    /// # Panics
    ///
    /// * If the internal regex does not compile (should never happen)
    /// * If the token is non-valid (that is, a array index with a non-i64)
    /// * If the regex does not find anything
    /// * If the integer in the brackets (`[]`) cannot be parsed to a valid i64
    ///
    /// # Incorrect behaviour
    ///
    /// * If the regex finds multiple captures
    ///
    /// # Returns
    ///
    /// The `Token` object with the correct identifier/index for this token and no next token.
    ///
    fn mk_token_object(s: &str) -> Result<Token> {
        use regex::Regex;
        use std::str::FromStr;

        lazy_static! {
            static ref RE: Regex = Regex::new(r"^\[\d+\]$").unwrap();
        }

        if !has_array_brackets(s) {
            return Ok(Token::Identifier { ident: String::from(s), next: None });
        }

        match RE.captures(s) {
            None => return Err(Error::from(ErrorKind::ArrayAccessWithoutIndex)),
            Some(captures) => {
                match captures.get(0) {
                    None => Ok(Token::Identifier { ident: String::from(s), next: None }),
                    Some(mtch) => {
                        let mtch = without_array_brackets(mtch.as_str());
                        let i : usize = FromStr::from_str(&mtch).unwrap(); // save because regex
                        Ok(Token::Index {
                            idx: i,
                            next: None,
                        })
                    }
                }
            }
        }
    }

    /// Check whether a str begins with '[' and ends with ']'
    fn has_array_brackets(s: &str) -> bool {
        s.as_bytes()[0] == b'[' && s.as_bytes()[s.len() - 1] == b']'
    }

    /// Remove '[' and ']' from a str
    fn without_array_brackets(s: &str) -> String {
        s.replace("[","").replace("]","")
    }

    fn build_token_tree(split: &mut Split<char>, last: &mut Token) -> Result<()> {
        match split.next() {
            None        => { /* No more tokens */ }
            Some(token) => {
                if token.len() == 0 {
                    return Err(Error::from(ErrorKind::EmptyIdentifier));
                }
                let mut token = try!(mk_token_object(token));
                try!(build_token_tree(split, &mut token));
                last.set_next(token);
            }
        }
        Ok(())
    }

    if query.is_empty() {
        return Err(Error::from(ErrorKind::EmptyQueryError));
    }

    let mut tokens = query.split(seperator);

    match tokens.next() {
        None        => Err(Error::from(ErrorKind::EmptyQueryError)),
        Some(token) => {
            if token.len() == 0 {
                return Err(Error::from(ErrorKind::EmptyIdentifier));
            }
            let mut tok = try!(mk_token_object(token));
            let _       = try!(build_token_tree(&mut tokens, &mut tok));
            Ok(tok)
        }
    }
}

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

    use std::ops::Deref;

    #[test]
    fn test_tokenize_empty_query_to_error() {
        let tokens = tokenize_with_seperator(&String::from(""), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyQueryError { .. }));
    }

    #[test]
    fn test_tokenize_seperator_only() {
        let tokens = tokenize_with_seperator(&String::from("."), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    #[test]
    fn test_tokenize_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_with_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_in_array_brackets() {
        let tokens = tokenize_with_seperator(&String::from("[a]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_single_token_query() {
        let tokens = tokenize_with_seperator(&String::from("example"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { ref ident, next: None } => {
                assert_eq!("example", ident);
                true
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_double_token_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                assert_eq!("b", next.deref().identifier());
                match next.deref() {
                    &Token::Identifier { next: None, .. } => true,
                    _ => false
                }
            },
            _ => false,
        });
        assert_eq!("a", tokens.identifier());
    }

    #[test]
    fn test_tokenize_ident_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.[0]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());
        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                match next.deref() {
                    &Token::Index { idx: 0, next: None } => true,
                    _ => false
                }
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_many_idents_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[1000]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());

        let expected =
            Token::Identifier {
                ident: String::from("a"),
                next: Some(Box::new(Token::Identifier {
                    ident: String::from("b"),
                    next: Some(Box::new(Token::Identifier {
                        ident: String::from("c"),
                        next: Some(Box::new(Token::Index {
                            idx: 1000,
                            next: None,
                        })),
                    })),
                })),
            };

        assert_eq!(expected, tokens);
    }

    #[test]
    fn test_tokenize_empty_token_after_good_token() {
        let tokens = tokenize_with_seperator(&String::from("a..b"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    quickcheck! {
        fn test_array_index(i: usize) -> bool {
            match tokenize_with_seperator(&format!("[{}]", i), '.') {
                Ok(Token::Index { next: None, ..  }) => true,
                _                                    => false,
            }
        }
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_none() {
        let mut token = Token::Identifier {
            ident: String::from("something"),
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_none() {
        let mut token = Token::Index {
            idx: 0,
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_one() {
        let mut token = Token::Identifier {
            ident: String::from("some"),
            next: Some(Box::new(Token::Identifier {
                ident: String::from("thing"),
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Identifier { .. }));
        match *last {
            Token::Identifier { ident: ident, .. } => {
                assert_eq!("thing", ident);
            }
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_one() {
        let mut token = Token::Index {
            idx: 0,
            next: Some(Box::new(Token::Index {
                idx: 1,
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Index { idx: 1, .. }));
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_one_token() {
        let tokens = tokenize_with_seperator(&String::from("a"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_none());
    }

}
<|endoftext|>


<commit_before>//! Interfaces for adding custom transports to libgit2

use std::ffi::{self, CString};
use std::io;
use std::mem;
use std::slice;
use std::str;
use std::sync::{StaticMutex, MUTEX_INIT};
use libc::{c_int, c_void, c_uint, c_char, size_t};

use {raw, panic, Error, Remote};
use util::Binding;

/// A transport is a structure which knows how to transfer data to and from a
/// remote.
///
/// This transport is a representation of the raw transport underneath it, which
/// is similar to a trait object in Rust.
#[allow(missing_copy_implementations)]
pub struct Transport {
    raw: *mut raw::git_transport,
    owned: bool,
}

/// Interfaced used by smart transports.
///
/// The full-fledged definiton of transports has to deal with lots of
/// nitty-gritty details of the git protocol, but "smart transports" largely
/// only need to deal with read() and write() of data over a channel.
///
/// A smart subtransport is contained within an instance of a smart transport
/// and is delegated to in order to actually conduct network activity to push or
/// pull data from a remote.
pub trait SmartSubtransport: Send + Sync {
    /// Indicates that this subtransport will be performing the specified action
    /// on the specified URL.
    ///
    /// This function is responsible for making any network connections and
    /// returns a stream which can be read and written from in order to
    /// negotiate the git protocol.
    fn action(&self, url: &str, action: Service)
              -> Result<Box<SmartSubtransportStream + Send>, Error>;

    /// Terminates a connection with the remote.
    ///
    /// Each subtransport is guaranteed a call to close() between calls to
    /// action(), except for the following tow natural progressions of actions
    /// against a constant URL.
    ///
    /// 1. UploadPackLs -> UploadPack
    /// 2. ReceivePackLs -> ReceivePack
    fn close(&self) -> Result<(), Error>;
}

/// Actions that a smart transport can ask a subtransport to perform
#[derive(Copy)]
#[allow(missing_docs)]
pub enum Service {
    UploadPackLs,
    UploadPack,
    ReceivePackLs,
    ReceivePack,
}

/// An instance of a stream over which a smart transport will communicate with a
/// remote.
///
/// Currently this only requires the standard `Reader` and `Writer` traits. This
/// trait also does not need to be implemented manually as long as the `Reader`
/// and `Writer` traits are implemented.
pub trait SmartSubtransportStream: Reader + Writer {}

impl<T: Reader + Writer> SmartSubtransportStream for T {}

type TransportFactory = Fn(&Remote) -> Result<Transport, Error> + Send + Sync;

/// Boxed data payload used for registering new transports.
///
/// Currently only contains a field which knows how to create transports.
struct TransportData {
    factory: Box<TransportFactory>,
}

/// Instance of a `git_smart_subtransport`, must use `#[repr(C)]` to ensure that
/// the C fields come first.
#[repr(C)]
struct RawSmartSubtransport {
    raw: raw::git_smart_subtransport,
    obj: Box<SmartSubtransport + Send>,
}

/// Instance of a `git_smart_subtransport_stream`, must use `#[repr(C)]` to
/// ensure that the C fields come first.
#[repr(C)]
struct RawSmartSubtransportStream {
    raw: raw::git_smart_subtransport_stream,
    obj: Box<SmartSubtransportStream + Send>,
}

/// Add a custom transport definition, to be used in addition to the built-in
/// set of transports that come with libgit2.
///
/// This function is unsafe as it needs to be externally synchronized with calls
/// to creation of other transports.
pub unsafe fn register<F>(prefix: &str, factory: F) -> Result<(), Error>
    where F: Fn(&Remote) -> Result<Transport, Error> + Send + Sync
{
    let mut data = Box::new(TransportData {
        factory: Box::new(factory),
    });
    let prefix = CString::from_slice(prefix.as_bytes());
    let datap = (&mut *data) as *mut TransportData as *mut c_void;
    try_call!(raw::git_transport_register(prefix,
                                          transport_factory,
                                          datap));
    mem::forget(data);
    Ok(())
}

impl Transport {
    /// Creates a new transport which will use the "smart" transport protocol
    /// for transferring data.
    ///
    /// A smart transport requires a *subtransport* over which data is actually
    /// communicated, but this subtransport largely just needs to be able to
    /// read() and write(). The subtransport provided will be used to make
    /// connections which can then be read/written from.
    ///
    /// The `rpc` argument is `true` if the protocol is stateless, false
    /// otherwise. For example `http://` is stateless but `git://` is not.
    pub fn smart<S>(remote: &Remote,
                    rpc: bool,
                    subtransport: S) -> Result<Transport, Error>
        where S: SmartSubtransport
    {
        static LOCK: StaticMutex = MUTEX_INIT;
        static mut PTR: usize = 0;

        let mut defn = raw::git_smart_subtransport_definition {
            callback: smart_factory,
            rpc: rpc as c_uint,
        };
        let mut ret = 0 as *mut _;

        let raw = Box::new(RawSmartSubtransport {
            raw: raw::git_smart_subtransport {
                action: subtransport_action,
                close: subtransport_close,
                free: subtransport_free,
            },
            obj: Box::new(subtransport),
        });

        // Currently there's no way to pass a paload via the
        // git_smart_subtransport_definition structure, but it's only used as a
        // configuration for the initial creation of the smart transport (verified
        // by reading the current code, hopefully it doesn't change!).
        //
        // We, however, need some state (gotta pass in our
        // `RawSmartSubtransport`). This also means that this block must be
        // entirely synchronized with a lock (boo!)
        unsafe {
            let _g = LOCK.lock();
            assert!(PTR == 0);
            PTR = &*raw as *const RawSmartSubtransport as usize;
            try_call!(raw::git_transport_smart(&mut ret, remote.raw(),
                                               &mut defn as *mut _ as *mut _));
            mem::forget(raw); // ownership transport to `ret`
            PTR = 0;
        }
        return Ok(Transport { raw: ret, owned: true });

        extern fn smart_factory(out: *mut *mut raw::git_smart_subtransport,
                                _owner: *mut raw::git_transport) -> c_int {
            unsafe {
                assert!(PTR as usize != 0);
                *out = PTR as *mut raw::git_smart_subtransport;
                0
            }
        }
    }
}

impl Drop for Transport {
    fn drop(&mut self) {
        if self.owned {
            unsafe {
                ((*self.raw).free)(self.raw)
            }
        }
    }
}

// callback used by register() to create new transports
extern fn transport_factory(out: *mut *mut raw::git_transport,
                            owner: *mut raw::git_remote,
                            param: *mut c_void) -> c_int {
    unsafe {
        let remote = Binding::from_raw(owner);
        let data = &mut *(param as *mut TransportData);
        let res = panic::wrap(|| (data.factory)(&remote));
        mem::forget(remote); // TODO: maybe a method instead?
        let mut transport = match res {
            Some(Ok(transport)) => transport,
            Some(Err(e)) => return e.raw_code() as c_int,
            None => return -1,
        };
        *out = transport.raw;
        transport.owned = false;
        0
    }
}

// callback used by smart transports to delegate an action to a
// `SmartSubtransport` trait object.
extern fn subtransport_action(stream: *mut *mut raw::git_smart_subtransport_stream,
                              raw_transport: *mut raw::git_smart_subtransport,
                              url: *const c_char,
                              action: raw::git_smart_service_t) -> c_int {
    unsafe {
        let url = ffi::c_str_to_bytes(&url);
        let url = match str::from_utf8(url).ok() {
            Some(s) => s,
            None => return -1,
        };
        let action = match action {
            raw::GIT_SERVICE_UPLOADPACK_LS => Service::UploadPackLs,
            raw::GIT_SERVICE_UPLOADPACK => Service::UploadPack,
            raw::GIT_SERVICE_RECEIVEPACK_LS => Service::ReceivePackLs,
            raw::GIT_SERVICE_RECEIVEPACK => Service::ReceivePack,
        };
        let transport = &mut *(raw_transport as *mut RawSmartSubtransport);
        let obj = match panic::wrap(|| transport.obj.action(url, action)) {
            Some(Ok(s)) => s,
            Some(Err(e)) => return e.raw_code() as c_int,
            None => return -1,
        };
        *stream = mem::transmute(Box::new(RawSmartSubtransportStream {
            raw: raw::git_smart_subtransport_stream {
                subtransport: raw_transport,
                read: stream_read,
                write: stream_write,
                free: stream_free,
            },
            obj: obj,
        }));
        0
    }
}

// callback used by smart transports to close a `SmartSubtransport` trait
// object.
extern fn subtransport_close(transport: *mut raw::git_smart_subtransport)
                             -> c_int {
    unsafe {
        let transport = &mut *(transport as *mut RawSmartSubtransport);
        match panic::wrap(|| transport.obj.close()) {
            Some(Ok(())) => 0,
            Some(Err(e)) => e.raw_code() as c_int,
            None => -1,
        }
    }
}

// callback used by smart transports to free a `SmartSubtransport` trait
// object.
extern fn subtransport_free(transport: *mut raw::git_smart_subtransport) {
    unsafe {
        mem::transmute::<_, Box<RawSmartSubtransport>>(transport);
    }
}

// callback used by smart transports to read from a `SmartSubtransportStream`
// object.
extern fn stream_read(stream: *mut raw::git_smart_subtransport_stream,
                      buffer: *mut c_char,
                      buf_size: size_t,
                      bytes_read: *mut size_t) -> c_int {
    unsafe {
        let transport = &mut *(stream as *mut RawSmartSubtransportStream);
        let buffer = buffer as *mut u8;
        let buf = slice::from_raw_mut_buf(&buffer, buf_size as usize);
        match panic::wrap(|| transport.obj.read(buf)) {
            Some(Ok(n)) => { *bytes_read = n as size_t; 0 }
            Some(Err(ref e)) if e.kind == io::EndOfFile => {
                *bytes_read = 0; 0
            }
            Some(Err(..)) => -2, // TODO: can this error be preserved?
            None => -1,
        }
    }
}

// callback used by smart transports to write to a `SmartSubtransportStream`
// object.
extern fn stream_write(stream: *mut raw::git_smart_subtransport_stream,
                       buffer: *const c_char,
                       len: size_t) -> c_int {
    unsafe {
        let transport = &mut *(stream as *mut RawSmartSubtransportStream);
        let buffer = buffer as *const u8;
        let buf = slice::from_raw_buf(&buffer, len as usize);
        match panic::wrap(|| transport.obj.write(buf)) {
            Some(Ok(())) => 0,
            Some(Err(..)) => -2, // TODO: can this error be preserved?
            None => -1,
        }
    }
}

// callback used by smart transports to free a `SmartSubtransportStream`
// object.
extern fn stream_free(stream: *mut raw::git_smart_subtransport_stream) {
    unsafe {
        mem::transmute::<_, Box<RawSmartSubtransportStream>>(stream);
    }
}
<commit_msg>Tweak where send bounds are located/required<commit_after>//! Interfaces for adding custom transports to libgit2

use std::ffi::{self, CString};
use std::io;
use std::mem;
use std::slice;
use std::str;
use std::sync::{StaticMutex, MUTEX_INIT};
use libc::{c_int, c_void, c_uint, c_char, size_t};

use {raw, panic, Error, Remote};
use util::Binding;

/// A transport is a structure which knows how to transfer data to and from a
/// remote.
///
/// This transport is a representation of the raw transport underneath it, which
/// is similar to a trait object in Rust.
#[allow(missing_copy_implementations)]
pub struct Transport {
    raw: *mut raw::git_transport,
    owned: bool,
}

/// Interfaced used by smart transports.
///
/// The full-fledged definiton of transports has to deal with lots of
/// nitty-gritty details of the git protocol, but "smart transports" largely
/// only need to deal with read() and write() of data over a channel.
///
/// A smart subtransport is contained within an instance of a smart transport
/// and is delegated to in order to actually conduct network activity to push or
/// pull data from a remote.
pub trait SmartSubtransport: Send {
    /// Indicates that this subtransport will be performing the specified action
    /// on the specified URL.
    ///
    /// This function is responsible for making any network connections and
    /// returns a stream which can be read and written from in order to
    /// negotiate the git protocol.
    fn action(&self, url: &str, action: Service)
              -> Result<Box<SmartSubtransportStream>, Error>;

    /// Terminates a connection with the remote.
    ///
    /// Each subtransport is guaranteed a call to close() between calls to
    /// action(), except for the following tow natural progressions of actions
    /// against a constant URL.
    ///
    /// 1. UploadPackLs -> UploadPack
    /// 2. ReceivePackLs -> ReceivePack
    fn close(&self) -> Result<(), Error>;
}

/// Actions that a smart transport can ask a subtransport to perform
#[derive(Copy)]
#[allow(missing_docs)]
pub enum Service {
    UploadPackLs,
    UploadPack,
    ReceivePackLs,
    ReceivePack,
}

/// An instance of a stream over which a smart transport will communicate with a
/// remote.
///
/// Currently this only requires the standard `Reader` and `Writer` traits. This
/// trait also does not need to be implemented manually as long as the `Reader`
/// and `Writer` traits are implemented.
pub trait SmartSubtransportStream: Reader + Writer + Send {}

impl<T: Reader + Writer + Send> SmartSubtransportStream for T {}

type TransportFactory = Fn(&Remote) -> Result<Transport, Error> + Send + Sync;

/// Boxed data payload used for registering new transports.
///
/// Currently only contains a field which knows how to create transports.
struct TransportData {
    factory: Box<TransportFactory>,
}

/// Instance of a `git_smart_subtransport`, must use `#[repr(C)]` to ensure that
/// the C fields come first.
#[repr(C)]
struct RawSmartSubtransport {
    raw: raw::git_smart_subtransport,
    obj: Box<SmartSubtransport>,
}

/// Instance of a `git_smart_subtransport_stream`, must use `#[repr(C)]` to
/// ensure that the C fields come first.
#[repr(C)]
struct RawSmartSubtransportStream {
    raw: raw::git_smart_subtransport_stream,
    obj: Box<SmartSubtransportStream>,
}

/// Add a custom transport definition, to be used in addition to the built-in
/// set of transports that come with libgit2.
///
/// This function is unsafe as it needs to be externally synchronized with calls
/// to creation of other transports.
pub unsafe fn register<F>(prefix: &str, factory: F) -> Result<(), Error>
    where F: Fn(&Remote) -> Result<Transport, Error> + Send + Sync
{
    let mut data = Box::new(TransportData {
        factory: Box::new(factory),
    });
    let prefix = CString::from_slice(prefix.as_bytes());
    let datap = (&mut *data) as *mut TransportData as *mut c_void;
    try_call!(raw::git_transport_register(prefix,
                                          transport_factory,
                                          datap));
    mem::forget(data);
    Ok(())
}

impl Transport {
    /// Creates a new transport which will use the "smart" transport protocol
    /// for transferring data.
    ///
    /// A smart transport requires a *subtransport* over which data is actually
    /// communicated, but this subtransport largely just needs to be able to
    /// read() and write(). The subtransport provided will be used to make
    /// connections which can then be read/written from.
    ///
    /// The `rpc` argument is `true` if the protocol is stateless, false
    /// otherwise. For example `http://` is stateless but `git://` is not.
    pub fn smart<S>(remote: &Remote,
                    rpc: bool,
                    subtransport: S) -> Result<Transport, Error>
        where S: SmartSubtransport
    {
        static LOCK: StaticMutex = MUTEX_INIT;
        static mut PTR: usize = 0;

        let mut defn = raw::git_smart_subtransport_definition {
            callback: smart_factory,
            rpc: rpc as c_uint,
        };
        let mut ret = 0 as *mut _;

        let raw = Box::new(RawSmartSubtransport {
            raw: raw::git_smart_subtransport {
                action: subtransport_action,
                close: subtransport_close,
                free: subtransport_free,
            },
            obj: Box::new(subtransport),
        });

        // Currently there's no way to pass a paload via the
        // git_smart_subtransport_definition structure, but it's only used as a
        // configuration for the initial creation of the smart transport (verified
        // by reading the current code, hopefully it doesn't change!).
        //
        // We, however, need some state (gotta pass in our
        // `RawSmartSubtransport`). This also means that this block must be
        // entirely synchronized with a lock (boo!)
        unsafe {
            let _g = LOCK.lock();
            assert!(PTR == 0);
            PTR = &*raw as *const RawSmartSubtransport as usize;
            try_call!(raw::git_transport_smart(&mut ret, remote.raw(),
                                               &mut defn as *mut _ as *mut _));
            mem::forget(raw); // ownership transport to `ret`
            PTR = 0;
        }
        return Ok(Transport { raw: ret, owned: true });

        extern fn smart_factory(out: *mut *mut raw::git_smart_subtransport,
                                _owner: *mut raw::git_transport) -> c_int {
            unsafe {
                assert!(PTR as usize != 0);
                *out = PTR as *mut raw::git_smart_subtransport;
                0
            }
        }
    }
}

impl Drop for Transport {
    fn drop(&mut self) {
        if self.owned {
            unsafe {
                ((*self.raw).free)(self.raw)
            }
        }
    }
}

// callback used by register() to create new transports
extern fn transport_factory(out: *mut *mut raw::git_transport,
                            owner: *mut raw::git_remote,
                            param: *mut c_void) -> c_int {
    unsafe {
        let remote = Binding::from_raw(owner);
        let data = &mut *(param as *mut TransportData);
        let res = panic::wrap(|| (data.factory)(&remote));
        mem::forget(remote); // TODO: maybe a method instead?
        let mut transport = match res {
            Some(Ok(transport)) => transport,
            Some(Err(e)) => return e.raw_code() as c_int,
            None => return -1,
        };
        *out = transport.raw;
        transport.owned = false;
        0
    }
}

// callback used by smart transports to delegate an action to a
// `SmartSubtransport` trait object.
extern fn subtransport_action(stream: *mut *mut raw::git_smart_subtransport_stream,
                              raw_transport: *mut raw::git_smart_subtransport,
                              url: *const c_char,
                              action: raw::git_smart_service_t) -> c_int {
    unsafe {
        let url = ffi::c_str_to_bytes(&url);
        let url = match str::from_utf8(url).ok() {
            Some(s) => s,
            None => return -1,
        };
        let action = match action {
            raw::GIT_SERVICE_UPLOADPACK_LS => Service::UploadPackLs,
            raw::GIT_SERVICE_UPLOADPACK => Service::UploadPack,
            raw::GIT_SERVICE_RECEIVEPACK_LS => Service::ReceivePackLs,
            raw::GIT_SERVICE_RECEIVEPACK => Service::ReceivePack,
        };
        let transport = &mut *(raw_transport as *mut RawSmartSubtransport);
        let obj = match panic::wrap(|| transport.obj.action(url, action)) {
            Some(Ok(s)) => s,
            Some(Err(e)) => return e.raw_code() as c_int,
            None => return -1,
        };
        *stream = mem::transmute(Box::new(RawSmartSubtransportStream {
            raw: raw::git_smart_subtransport_stream {
                subtransport: raw_transport,
                read: stream_read,
                write: stream_write,
                free: stream_free,
            },
            obj: obj,
        }));
        0
    }
}

// callback used by smart transports to close a `SmartSubtransport` trait
// object.
extern fn subtransport_close(transport: *mut raw::git_smart_subtransport)
                             -> c_int {
    unsafe {
        let transport = &mut *(transport as *mut RawSmartSubtransport);
        match panic::wrap(|| transport.obj.close()) {
            Some(Ok(())) => 0,
            Some(Err(e)) => e.raw_code() as c_int,
            None => -1,
        }
    }
}

// callback used by smart transports to free a `SmartSubtransport` trait
// object.
extern fn subtransport_free(transport: *mut raw::git_smart_subtransport) {
    unsafe {
        mem::transmute::<_, Box<RawSmartSubtransport>>(transport);
    }
}

// callback used by smart transports to read from a `SmartSubtransportStream`
// object.
extern fn stream_read(stream: *mut raw::git_smart_subtransport_stream,
                      buffer: *mut c_char,
                      buf_size: size_t,
                      bytes_read: *mut size_t) -> c_int {
    unsafe {
        let transport = &mut *(stream as *mut RawSmartSubtransportStream);
        let buffer = buffer as *mut u8;
        let buf = slice::from_raw_mut_buf(&buffer, buf_size as usize);
        match panic::wrap(|| transport.obj.read(buf)) {
            Some(Ok(n)) => { *bytes_read = n as size_t; 0 }
            Some(Err(ref e)) if e.kind == io::EndOfFile => {
                *bytes_read = 0; 0
            }
            Some(Err(..)) => -2, // TODO: can this error be preserved?
            None => -1,
        }
    }
}

// callback used by smart transports to write to a `SmartSubtransportStream`
// object.
extern fn stream_write(stream: *mut raw::git_smart_subtransport_stream,
                       buffer: *const c_char,
                       len: size_t) -> c_int {
    unsafe {
        let transport = &mut *(stream as *mut RawSmartSubtransportStream);
        let buffer = buffer as *const u8;
        let buf = slice::from_raw_buf(&buffer, len as usize);
        match panic::wrap(|| transport.obj.write(buf)) {
            Some(Ok(())) => 0,
            Some(Err(..)) => -2, // TODO: can this error be preserved?
            None => -1,
        }
    }
}

// callback used by smart transports to free a `SmartSubtransportStream`
// object.
extern fn stream_free(stream: *mut raw::git_smart_subtransport_stream) {
    unsafe {
        mem::transmute::<_, Box<RawSmartSubtransportStream>>(stream);
    }
}
<|endoftext|>


<commit_before>
use vertex::{RawVertex, Vertex};
use edge::{RawEdge, Edge};
use graph::TraversableToVertex;
use path::{Path, Element};
use std::iter::Extend;
use std::iter::Filter;

// use std::iter::Iterator;

// define a traversal as a series of stages

pub struct GraphQuery {
    // many paths
    pub paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<Vertex>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
            let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

    pub fn get_paths(&self) -> &Vec<Path> {
        &self.paths
    }
    pub fn push(&mut self, path:Path) {
        self.paths.push(path)
    }

    /*
    generic mapper for our queries
    future this may use worker threads to perform
    traversals

    TODO make sure that if nothing comes back we don't keep it in the path

     */
    fn map<F: Fn(&Path) -> Vec<Element>>(&self, closure: F) -> GraphQuery  {
        let mut result = GraphQuery::empty(); // result
        for path in self.paths.iter() {
            let mut tmp = closure(&path);
            // let mut tmp2 = tmp.as_slice();
            // currently gets back a Vec<Path> but what if it gets Elements?
            let new_elements = path.permute(&tmp);
            result.paths.extend(new_elements);
        }
        result
    }

    pub fn outV(&self, labels: &[&str]) -> GraphQuery {
        // map can figure out the rest
        let f = |path: &Path| {
            //take the final element in the path
            let element = path.last().unwrap();

            let result : Vec<Element> = match element {
                &Element::Vertex(v) =>
                    v.outV(&labels).iter().map(|v| Element::Vertex(*v)).collect(),
                    // Vec::new(),
                &Element::Edge(ref e) =>
                    Vec::new()
            };
            // apply outV
            result
        };
        self.map(f)
    }

    pub fn filter<F: Fn(&Path) -> bool>(&self, closure: F) -> GraphQuery {
        let result = GraphQuery::empty();
        // apply the filter to each path
        let tmp : Vec<Path> = self.paths.iter().filter(closure).collect();
        result.paths = tmp;
        return result
    }

//    pub fn inV(&self) -> GraphQuery {
//        let g = GraphQuery::empty();
//        let f = |element: &Element| {
//            element.inV()
//        };
//        self.map(f)
//    }
}
<commit_msg>trying to get filtering working<commit_after>
use vertex::{RawVertex, Vertex};
use edge::{RawEdge, Edge};
use graph::TraversableToVertex;
use path::{Path, Element};
use std::iter::Extend;
use std::iter::Filter;

// use std::iter::Iterator;

// define a traversal as a series of stages

pub struct GraphQuery {
    // many paths
    pub paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<Vertex>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
            let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

    pub fn get_paths(&self) -> &Vec<Path> {
        &self.paths
    }
    pub fn push(&mut self, path:Path) {
        self.paths.push(path)
    }

    /*
    generic mapper for our queries
    future this may use worker threads to perform
    traversals

    TODO make sure that if nothing comes back we don't keep it in the path

     */
    fn map<F: Fn(&Path) -> Vec<Element>>(&self, closure: F) -> GraphQuery  {
        let mut result = GraphQuery::empty(); // result
        for path in self.paths.iter() {
            let mut tmp = closure(&path);
            // let mut tmp2 = tmp.as_slice();
            // currently gets back a Vec<Path> but what if it gets Elements?
            let new_elements = path.permute(&tmp);
            result.paths.extend(new_elements);
        }
        result
    }

    pub fn outV(&self, labels: &[&str]) -> GraphQuery {
        // map can figure out the rest
        let f = |path: &Path| {
            //take the final element in the path
            let element = path.last().unwrap();

            let result : Vec<Element> = match element {
                &Element::Vertex(v) =>
                    v.outV(&labels).iter().map(|v| Element::Vertex(*v)).collect(),
                    // Vec::new(),
                &Element::Edge(ref e) =>
                    Vec::new()
            };
            // apply outV
            result
        };
        self.map(f)
    }

    pub fn filter<F: Fn(&Path) -> bool>(&self, closure: F) -> GraphQuery {
        let result = GraphQuery::empty();
        // apply the filter to each path
        let tmp = self.paths.iter().filter(|&x| true);
        // result.paths = tmp;
        return result
    }

//    pub fn inV(&self) -> GraphQuery {
//        let g = GraphQuery::empty();
//        let f = |element: &Element| {
//            element.inV()
//        };
//        self.map(f)
//    }
}
<|endoftext|>


<commit_before>//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]

#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_cstr_unchecked)]
#![feature(crate_visibility_modifier)]
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
#![feature(libc)]
#![feature(nll)]
#![feature(optin_builtin_traits)]
#![feature(concat_idents)]
#![feature(link_args)]
#![feature(static_nobundle)]
#![feature(trusted_len)]

use back::write::{create_target_machine, create_informational_target_machine};
use syntax_pos::symbol::Symbol;

extern crate rustc_demangle;
extern crate flate2;
#[macro_use] extern crate bitflags;
extern crate libc;
#[macro_use] extern crate rustc;
extern crate rustc_target;
#[macro_use] extern crate rustc_data_structures;
extern crate rustc_feature;
extern crate rustc_index;
extern crate rustc_incremental;
extern crate rustc_codegen_utils;
extern crate rustc_codegen_ssa;
extern crate rustc_fs_util;

#[macro_use] extern crate log;
extern crate smallvec;
extern crate syntax;
extern crate syntax_pos;
extern crate rustc_errors as errors;

use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, FatLTOInput};
use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModule};
use rustc_codegen_ssa::CompiledModule;
use rustc_errors::{FatalError, Handler};
use rustc::dep_graph::WorkProduct;
use syntax::expand::allocator::AllocatorKind;
pub use llvm_util::target_features;
use std::any::Any;
use std::sync::Arc;
use std::ffi::CStr;

use rustc::dep_graph::DepGraph;
use rustc::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
use rustc::session::Session;
use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel};
use rustc::ty::{self, TyCtxt};
use rustc::util::common::ErrorReported;
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_utils::codegen_backend::CodegenBackend;

mod back {
    pub mod archive;
    pub mod bytecode;
    pub mod lto;
    pub mod write;
}

mod abi;
mod allocator;
mod asm;
mod attributes;
mod base;
mod builder;
mod callee;
mod common;
mod consts;
mod context;
mod debuginfo;
mod declare;
mod intrinsic;

// The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912.
#[path = "llvm/mod.rs"] mod llvm_; pub mod llvm { pub use super::llvm_::*; }

mod llvm_util;
mod metadata;
mod mono_item;
mod type_;
mod type_of;
mod value;
mod va_arg;

#[derive(Clone)]
pub struct LlvmCodegenBackend(());

impl ExtraBackendMethods for LlvmCodegenBackend {
    fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
        ModuleLlvm::new_metadata(tcx, mod_name)
    }

    fn write_compressed_metadata<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: &EncodedMetadata,
        llvm_module: &mut ModuleLlvm,
    ) {
        base::write_compressed_metadata(tcx, metadata, llvm_module)
    }
    fn codegen_allocator<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        mods: &mut ModuleLlvm,
        kind: AllocatorKind,
    ) {
        unsafe { allocator::codegen(tcx, mods, kind) }
    }
    fn compile_codegen_unit(
        &self, tcx: TyCtxt<'_>,
        cgu_name: Symbol,
        tx: &std::sync::mpsc::Sender<Box<dyn Any + Send>>,
    ) {
        base::compile_codegen_unit(tcx, cgu_name, tx);
    }
    fn target_machine_factory(
        &self,
        sess: &Session,
        optlvl: OptLevel,
        find_features: bool
    ) -> Arc<dyn Fn() ->
        Result<&'static mut llvm::TargetMachine, String> + Send + Sync> {
        back::write::target_machine_factory(sess, optlvl, find_features)
    }
    fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
        llvm_util::target_cpu(sess)
    }
}

impl WriteBackendMethods for LlvmCodegenBackend {
    type Module = ModuleLlvm;
    type ModuleBuffer = back::lto::ModuleBuffer;
    type Context = llvm::Context;
    type TargetMachine = &'static mut llvm::TargetMachine;
    type ThinData = back::lto::ThinData;
    type ThinBuffer = back::lto::ThinBuffer;
    fn print_pass_timings(&self) {
            unsafe { llvm::LLVMRustPrintPassTimings(); }
    }
    fn run_fat_lto(
        cgcx: &CodegenContext<Self>,
        modules: Vec<FatLTOInput<Self>>,
        cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
    ) -> Result<LtoModuleCodegen<Self>, FatalError> {
        back::lto::run_fat(cgcx, modules, cached_modules)
    }
    fn run_thin_lto(
        cgcx: &CodegenContext<Self>,
        modules: Vec<(String, Self::ThinBuffer)>,
        cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
    ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
        back::lto::run_thin(cgcx, modules, cached_modules)
    }
    unsafe fn optimize(
        cgcx: &CodegenContext<Self>,
        diag_handler: &Handler,
        module: &ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
    ) -> Result<(), FatalError> {
        back::write::optimize(cgcx, diag_handler, module, config)
    }
    unsafe fn optimize_thin(
        cgcx: &CodegenContext<Self>,
        thin: &mut ThinModule<Self>,
    ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
        back::lto::optimize_thin_module(thin, cgcx)
    }
    unsafe fn codegen(
        cgcx: &CodegenContext<Self>,
        diag_handler: &Handler,
        module: ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
    ) -> Result<CompiledModule, FatalError> {
        back::write::codegen(cgcx, diag_handler, module, config)
    }
    fn prepare_thin(
        module: ModuleCodegen<Self::Module>
    ) -> (String, Self::ThinBuffer) {
        back::lto::prepare_thin(module)
    }
    fn serialize_module(
        module: ModuleCodegen<Self::Module>
    ) -> (String, Self::ModuleBuffer) {
        (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
    }
    fn run_lto_pass_manager(
        cgcx: &CodegenContext<Self>,
        module: &ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
        thin: bool
    ) {
        back::lto::run_pass_manager(cgcx, module, config, thin)
    }
}

unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
unsafe impl Sync for LlvmCodegenBackend {}

impl LlvmCodegenBackend {
    pub fn new() -> Box<dyn CodegenBackend> {
        box LlvmCodegenBackend(())
    }
}

impl CodegenBackend for LlvmCodegenBackend {
    fn init(&self, sess: &Session) {
        llvm_util::init(sess); // Make sure llvm is inited
    }

    fn print(&self, req: PrintRequest, sess: &Session) {
        match req {
            PrintRequest::RelocationModels => {
                println!("Available relocation models:");
                for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() {
                    println!("    {}", name);
                }
                println!();
            }
            PrintRequest::CodeModels => {
                println!("Available code models:");
                for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){
                    println!("    {}", name);
                }
                println!();
            }
            PrintRequest::TlsModels => {
                println!("Available TLS models:");
                for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){
                    println!("    {}", name);
                }
                println!();
            }
            req => llvm_util::print(req, sess),
        }
    }

    fn print_passes(&self) {
        llvm_util::print_passes();
    }

    fn print_version(&self) {
        llvm_util::print_version();
    }

    fn target_features(&self, sess: &Session) -> Vec<Symbol> {
        target_features(sess)
    }

    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
        box metadata::LlvmMetadataLoader
    }

    fn provide(&self, providers: &mut ty::query::Providers<'_>) {
        attributes::provide(providers);
    }

    fn provide_extern(&self, providers: &mut ty::query::Providers<'_>) {
        attributes::provide_extern(providers);
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        box rustc_codegen_ssa::base::codegen_crate(
            LlvmCodegenBackend(()), tcx, metadata, need_metadata_module)
    }

    fn join_codegen_and_link(
        &self,
        ongoing_codegen: Box<dyn Any>,
        sess: &Session,
        dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc::util::common::time;
        let (codegen_results, work_products) =
            ongoing_codegen.downcast::
                <rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
                .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
                .join(sess);
        if sess.opts.debugging_opts.incremental_info {
            rustc_codegen_ssa::back::write::dump_incremental_data(&codegen_results);
        }

        time(sess,
             "serialize work products",
             move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products));

        sess.compile_status()?;

        if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
                                                   i == OutputType::Metadata) {
            return Ok(());
        }

        // Run the linker on any artifacts that resulted from the LLVM run.
        // This should produce either a finished executable or library.
        time(sess, "linking", || {
            let _prof_timer = sess.prof.generic_activity("link_crate");

            use rustc_codegen_ssa::back::link::link_binary;
            use crate::back::archive::LlvmArchiveBuilder;

            let target_cpu = crate::llvm_util::target_cpu(sess);
            link_binary::<LlvmArchiveBuilder<'_>>(
                sess,
                &codegen_results,
                outputs,
                &codegen_results.crate_name.as_str(),
                target_cpu,
            );
        });

        // Now that we won't touch anything in the incremental compilation directory
        // any more, we can finalize it (which involves renaming it)
        rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash);

        Ok(())
    }
}

pub struct ModuleLlvm {
    llcx: &'static mut llvm::Context,
    llmod_raw: *const llvm::Module,
    tm: &'static mut llvm::TargetMachine,
}

unsafe impl Send for ModuleLlvm { }
unsafe impl Sync for ModuleLlvm { }

impl ModuleLlvm {
    fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
            ModuleLlvm {
                llmod_raw,
                llcx,
                tm: create_target_machine(tcx, false),
            }
        }
    }

    fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
            ModuleLlvm {
                llmod_raw,
                llcx,
                tm: create_informational_target_machine(&tcx.sess, false),
            }
        }
    }

    fn parse(
        cgcx: &CodegenContext<LlvmCodegenBackend>,
        name: &CStr,
        buffer: &[u8],
        handler: &Handler,
    ) -> Result<Self, FatalError> {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
            let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
            let tm = match (cgcx.tm_factory.0)() {
                Ok(m) => m,
                Err(e) => {
                    handler.struct_err(&e).emit();
                    return Err(FatalError)
                }
            };

            Ok(ModuleLlvm {
                llmod_raw,
                llcx,
                tm,
            })
        }
    }

    fn llmod(&self) -> &llvm::Module {
        unsafe {
            &*self.llmod_raw
        }
    }
}

impl Drop for ModuleLlvm {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
            llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
        }
    }
}
<commit_msg>Remove `extern crate` declarations<commit_after>//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]

#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_cstr_unchecked)]
#![feature(crate_visibility_modifier)]
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
#![feature(libc)]
#![feature(nll)]
#![feature(optin_builtin_traits)]
#![feature(concat_idents)]
#![feature(link_args)]
#![feature(static_nobundle)]
#![feature(trusted_len)]

use back::write::{create_target_machine, create_informational_target_machine};
use syntax_pos::symbol::Symbol;

use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, FatLTOInput};
use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModule};
use rustc_codegen_ssa::CompiledModule;
use rustc_errors::{FatalError, Handler};
use rustc::dep_graph::WorkProduct;
use syntax::expand::allocator::AllocatorKind;
pub use llvm_util::target_features;
use std::any::Any;
use std::sync::Arc;
use std::ffi::CStr;

use rustc::dep_graph::DepGraph;
use rustc::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
use rustc::session::Session;
use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel};
use rustc::ty::{self, TyCtxt};
use rustc::util::common::ErrorReported;
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_utils::codegen_backend::CodegenBackend;

mod back {
    pub mod archive;
    pub mod bytecode;
    pub mod lto;
    pub mod write;
}

mod abi;
mod allocator;
mod asm;
mod attributes;
mod base;
mod builder;
mod callee;
mod common;
mod consts;
mod context;
mod debuginfo;
mod declare;
mod intrinsic;

// The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912.
#[path = "llvm/mod.rs"] mod llvm_; pub mod llvm { pub use super::llvm_::*; }

mod llvm_util;
mod metadata;
mod mono_item;
mod type_;
mod type_of;
mod value;
mod va_arg;

#[derive(Clone)]
pub struct LlvmCodegenBackend(());

impl ExtraBackendMethods for LlvmCodegenBackend {
    fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
        ModuleLlvm::new_metadata(tcx, mod_name)
    }

    fn write_compressed_metadata<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: &EncodedMetadata,
        llvm_module: &mut ModuleLlvm,
    ) {
        base::write_compressed_metadata(tcx, metadata, llvm_module)
    }
    fn codegen_allocator<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        mods: &mut ModuleLlvm,
        kind: AllocatorKind,
    ) {
        unsafe { allocator::codegen(tcx, mods, kind) }
    }
    fn compile_codegen_unit(
        &self, tcx: TyCtxt<'_>,
        cgu_name: Symbol,
        tx: &std::sync::mpsc::Sender<Box<dyn Any + Send>>,
    ) {
        base::compile_codegen_unit(tcx, cgu_name, tx);
    }
    fn target_machine_factory(
        &self,
        sess: &Session,
        optlvl: OptLevel,
        find_features: bool
    ) -> Arc<dyn Fn() ->
        Result<&'static mut llvm::TargetMachine, String> + Send + Sync> {
        back::write::target_machine_factory(sess, optlvl, find_features)
    }
    fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
        llvm_util::target_cpu(sess)
    }
}

impl WriteBackendMethods for LlvmCodegenBackend {
    type Module = ModuleLlvm;
    type ModuleBuffer = back::lto::ModuleBuffer;
    type Context = llvm::Context;
    type TargetMachine = &'static mut llvm::TargetMachine;
    type ThinData = back::lto::ThinData;
    type ThinBuffer = back::lto::ThinBuffer;
    fn print_pass_timings(&self) {
            unsafe { llvm::LLVMRustPrintPassTimings(); }
    }
    fn run_fat_lto(
        cgcx: &CodegenContext<Self>,
        modules: Vec<FatLTOInput<Self>>,
        cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
    ) -> Result<LtoModuleCodegen<Self>, FatalError> {
        back::lto::run_fat(cgcx, modules, cached_modules)
    }
    fn run_thin_lto(
        cgcx: &CodegenContext<Self>,
        modules: Vec<(String, Self::ThinBuffer)>,
        cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
    ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
        back::lto::run_thin(cgcx, modules, cached_modules)
    }
    unsafe fn optimize(
        cgcx: &CodegenContext<Self>,
        diag_handler: &Handler,
        module: &ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
    ) -> Result<(), FatalError> {
        back::write::optimize(cgcx, diag_handler, module, config)
    }
    unsafe fn optimize_thin(
        cgcx: &CodegenContext<Self>,
        thin: &mut ThinModule<Self>,
    ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
        back::lto::optimize_thin_module(thin, cgcx)
    }
    unsafe fn codegen(
        cgcx: &CodegenContext<Self>,
        diag_handler: &Handler,
        module: ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
    ) -> Result<CompiledModule, FatalError> {
        back::write::codegen(cgcx, diag_handler, module, config)
    }
    fn prepare_thin(
        module: ModuleCodegen<Self::Module>
    ) -> (String, Self::ThinBuffer) {
        back::lto::prepare_thin(module)
    }
    fn serialize_module(
        module: ModuleCodegen<Self::Module>
    ) -> (String, Self::ModuleBuffer) {
        (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
    }
    fn run_lto_pass_manager(
        cgcx: &CodegenContext<Self>,
        module: &ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
        thin: bool
    ) {
        back::lto::run_pass_manager(cgcx, module, config, thin)
    }
}

unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
unsafe impl Sync for LlvmCodegenBackend {}

impl LlvmCodegenBackend {
    pub fn new() -> Box<dyn CodegenBackend> {
        box LlvmCodegenBackend(())
    }
}

impl CodegenBackend for LlvmCodegenBackend {
    fn init(&self, sess: &Session) {
        llvm_util::init(sess); // Make sure llvm is inited
    }

    fn print(&self, req: PrintRequest, sess: &Session) {
        match req {
            PrintRequest::RelocationModels => {
                println!("Available relocation models:");
                for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() {
                    println!("    {}", name);
                }
                println!();
            }
            PrintRequest::CodeModels => {
                println!("Available code models:");
                for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){
                    println!("    {}", name);
                }
                println!();
            }
            PrintRequest::TlsModels => {
                println!("Available TLS models:");
                for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){
                    println!("    {}", name);
                }
                println!();
            }
            req => llvm_util::print(req, sess),
        }
    }

    fn print_passes(&self) {
        llvm_util::print_passes();
    }

    fn print_version(&self) {
        llvm_util::print_version();
    }

    fn target_features(&self, sess: &Session) -> Vec<Symbol> {
        target_features(sess)
    }

    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
        box metadata::LlvmMetadataLoader
    }

    fn provide(&self, providers: &mut ty::query::Providers<'_>) {
        attributes::provide(providers);
    }

    fn provide_extern(&self, providers: &mut ty::query::Providers<'_>) {
        attributes::provide_extern(providers);
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        box rustc_codegen_ssa::base::codegen_crate(
            LlvmCodegenBackend(()), tcx, metadata, need_metadata_module)
    }

    fn join_codegen_and_link(
        &self,
        ongoing_codegen: Box<dyn Any>,
        sess: &Session,
        dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc::util::common::time;
        let (codegen_results, work_products) =
            ongoing_codegen.downcast::
                <rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
                .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
                .join(sess);
        if sess.opts.debugging_opts.incremental_info {
            rustc_codegen_ssa::back::write::dump_incremental_data(&codegen_results);
        }

        time(sess,
             "serialize work products",
             move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products));

        sess.compile_status()?;

        if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
                                                   i == OutputType::Metadata) {
            return Ok(());
        }

        // Run the linker on any artifacts that resulted from the LLVM run.
        // This should produce either a finished executable or library.
        time(sess, "linking", || {
            let _prof_timer = sess.prof.generic_activity("link_crate");

            use rustc_codegen_ssa::back::link::link_binary;
            use crate::back::archive::LlvmArchiveBuilder;

            let target_cpu = crate::llvm_util::target_cpu(sess);
            link_binary::<LlvmArchiveBuilder<'_>>(
                sess,
                &codegen_results,
                outputs,
                &codegen_results.crate_name.as_str(),
                target_cpu,
            );
        });

        // Now that we won't touch anything in the incremental compilation directory
        // any more, we can finalize it (which involves renaming it)
        rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash);

        Ok(())
    }
}

pub struct ModuleLlvm {
    llcx: &'static mut llvm::Context,
    llmod_raw: *const llvm::Module,
    tm: &'static mut llvm::TargetMachine,
}

unsafe impl Send for ModuleLlvm { }
unsafe impl Sync for ModuleLlvm { }

impl ModuleLlvm {
    fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
            ModuleLlvm {
                llmod_raw,
                llcx,
                tm: create_target_machine(tcx, false),
            }
        }
    }

    fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
            ModuleLlvm {
                llmod_raw,
                llcx,
                tm: create_informational_target_machine(&tcx.sess, false),
            }
        }
    }

    fn parse(
        cgcx: &CodegenContext<LlvmCodegenBackend>,
        name: &CStr,
        buffer: &[u8],
        handler: &Handler,
    ) -> Result<Self, FatalError> {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
            let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
            let tm = match (cgcx.tm_factory.0)() {
                Ok(m) => m,
                Err(e) => {
                    handler.struct_err(&e).emit();
                    return Err(FatalError)
                }
            };

            Ok(ModuleLlvm {
                llmod_raw,
                llcx,
                tm,
            })
        }
    }

    fn llmod(&self) -> &llvm::Module {
        unsafe {
            &*self.llmod_raw
        }
    }
}

impl Drop for ModuleLlvm {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
            llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
        }
    }
}
<|endoftext|>