<commit_before>use std::io;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use BindServer;
use futures::stream::Stream;
use futures::future::{Then, Future};
use net2;
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::reactor::{Core, Handle};
use tokio_service::{NewService, Service};

// TODO: Add more options, e.g.:
// - max concurrent requests
// - request timeout
// - read timeout
// - write timeout
// - max idle time
// - max lifetime

/// A builder for TCP servers.
///
/// Setting up a server needs, at minimum:
///
/// - A server protocol implementation
/// - An address
/// - A service to provide
///
/// In addition to those basics, the builder provides some additional
/// configuration, which is expected to grow over time.
///
/// See the crate docs for an example.
pub struct TcpServer<Kind, P> {
    _kind: PhantomData<Kind>,
    proto: Arc<P>,
    threads: usize,
    addr: SocketAddr,
}

impl<Kind, P> TcpServer<Kind, P> where
    P: BindServer<Kind, TcpStream> + Send + Sync + 'static
{
    /// Starts building a server for the given protocol and address, with
    /// default configuration.
    ///
    /// Generally, a protocol is implemented *not* by implementing the
    /// `BindServer` trait directly, but instead by implementing one of the
    /// protocol traits:
    ///
    /// - `pipeline::ServerProto`
    /// - `multiplex::ServerProto`
    /// - `streaming::pipeline::ServerProto`
    /// - `streaming::multiplex::ServerProto`
    ///
    /// See the crate documentation for more details on those traits.
    pub fn new(protocol: P, addr: SocketAddr) -> TcpServer<Kind, P> {
        TcpServer {
            _kind: PhantomData,
            proto: Arc::new(protocol),
            threads: 1,
            addr: addr,
        }
    }

    /// Set the address for the server.
    pub fn addr(&mut self, addr: SocketAddr) {
        self.addr = addr;
    }

    /// Set the number of threads running simultaneous event loops (Unix only).
    pub fn threads(&mut self, threads: usize) {
        assert!(threads > 0);
        if cfg!(unix) {
            self.threads = threads;
        }
    }

    /// Start up the server, providing the given service on it.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn serve<S>(&self, new_service: S) where
        S: NewService + Send + Sync + 'static,
        S::Instance: 'static,
        P::ServiceError: 'static,
        P::ServiceResponse: 'static,
        P::ServiceRequest: 'static,
        S::Request: From<P::ServiceRequest>,
        S::Response: Into<P::ServiceResponse>,
        S::Error: Into<P::ServiceError>,
    {
        let new_service = Arc::new(new_service);
        self.with_handle(move |_| new_service.clone())
    }

    /// Start up the server, providing the given service on it, and providing
    /// access to the event loop handle.
    ///
    /// The `new_service` argument is a closure that is given an event loop
    /// handle, and produces a value implementing `NewService`. That value is in
    /// turned used to make a new service instance for each incoming connection.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn with_handle<F, S>(&self, new_service: F) where
        F: Fn(&Handle) -> S + Send + Sync + 'static,
        S: NewService + Send + Sync + 'static,
        S::Instance: 'static,
        P::ServiceError: 'static,
        P::ServiceResponse: 'static,
        P::ServiceRequest: 'static,
        S::Request: From<P::ServiceRequest>,
        S::Response: Into<P::ServiceResponse>,
        S::Error: Into<P::ServiceError>,
    {
        let proto = self.proto.clone();
        let new_service = Arc::new(new_service);
        let addr = self.addr;
        let workers = self.threads;

        let threads = (0..self.threads - 1).map(|i| {
            let proto = proto.clone();
            let new_service = new_service.clone();

            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                serve(proto, addr, workers, &*new_service)
            }).unwrap()
        }).collect::<Vec<_>>();

        serve(proto, addr, workers, &*new_service);

        for thread in threads {
            thread.join().unwrap();
        }
    }
}

fn serve<P, Kind, F, S>(binder: Arc<P>, addr: SocketAddr, workers: usize, new_service: &F)
    where P: BindServer<Kind, TcpStream>,
          F: Fn(&Handle) -> S,
          S: NewService + Send + Sync,
          S::Instance: 'static,
          P::ServiceError: 'static,
          P::ServiceResponse: 'static,
          P::ServiceRequest: 'static,
          S::Request: From<P::ServiceRequest>,
          S::Response: Into<P::ServiceResponse>,
          S::Error: Into<P::ServiceError>,
{
    struct WrapService<S, Request, Response, Error> {
        inner: S,
        _marker: PhantomData<fn() -> (Request, Response, Error)>,
    }

    impl<S, Request, Response, Error> Service for WrapService<S, Request, Response, Error>
        where S: Service,
              S::Request: From<Request>,
              S::Response: Into<Response>,
              S::Error: Into<Error>,
    {
        type Request = Request;
        type Response = Response;
        type Error = Error;
        type Future = Then<S::Future,
                           Result<Response, Error>,
                           fn(Result<S::Response, S::Error>) -> Result<Response, Error>>;

        fn call(&self, req: Request) -> Self::Future {
            fn change_types<A, B, C, D>(r: Result<A, B>) -> Result<C, D>
                where A: Into<C>,
                      B: Into<D>,
            {
                match r {
                    Ok(e) => Ok(e.into()),
                    Err(e) => Err(e.into()),
                }
            }

            self.inner.call(S::Request::from(req)).then(change_types)
        }
    }

    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let new_service = new_service(&handle);
    let listener = listener(&addr, workers, &handle).unwrap();

    let server = listener.incoming().for_each(move |(socket, _)| {
        // Create the service
        let service = try!(new_service.new_service());

        // Bind it!
        binder.bind_server(&handle, socket, WrapService {
            inner: service,
            _marker: PhantomData,
        });

        Ok(())
    });

    core.run(server).unwrap();
}

fn listener(addr: &SocketAddr,
            workers: usize,
            handle: &Handle) -> io::Result<TcpListener> {
    let listener = match *addr {
        SocketAddr::V4(_) => try!(net2::TcpBuilder::new_v4()),
        SocketAddr::V6(_) => try!(net2::TcpBuilder::new_v6()),
    };
    try!(configure_tcp(workers, &listener));
    try!(listener.reuse_address(true));
    try!(listener.bind(addr));
    listener.listen(1024).and_then(|l| {
        TcpListener::from_listener(l, addr, handle)
    })
}

#[cfg(unix)]
fn configure_tcp(workers: usize, tcp: &net2::TcpBuilder) -> io::Result<()> {
    use net2::unix::*;

    if workers > 1 {
        try!(tcp.reuse_port(true));
    }

    Ok(())
}

#[cfg(windows)]
fn configure_tcp(workers: usize, _tcp: &net2::TcpBuilder) -> io::Result<()> {
    Ok(())
}
<commit_msg>Fix unused variable warning on Windows<commit_after>use std::io;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use BindServer;
use futures::stream::Stream;
use futures::future::{Then, Future};
use net2;
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::reactor::{Core, Handle};
use tokio_service::{NewService, Service};

// TODO: Add more options, e.g.:
// - max concurrent requests
// - request timeout
// - read timeout
// - write timeout
// - max idle time
// - max lifetime

/// A builder for TCP servers.
///
/// Setting up a server needs, at minimum:
///
/// - A server protocol implementation
/// - An address
/// - A service to provide
///
/// In addition to those basics, the builder provides some additional
/// configuration, which is expected to grow over time.
///
/// See the crate docs for an example.
pub struct TcpServer<Kind, P> {
    _kind: PhantomData<Kind>,
    proto: Arc<P>,
    threads: usize,
    addr: SocketAddr,
}

impl<Kind, P> TcpServer<Kind, P> where
    P: BindServer<Kind, TcpStream> + Send + Sync + 'static
{
    /// Starts building a server for the given protocol and address, with
    /// default configuration.
    ///
    /// Generally, a protocol is implemented *not* by implementing the
    /// `BindServer` trait directly, but instead by implementing one of the
    /// protocol traits:
    ///
    /// - `pipeline::ServerProto`
    /// - `multiplex::ServerProto`
    /// - `streaming::pipeline::ServerProto`
    /// - `streaming::multiplex::ServerProto`
    ///
    /// See the crate documentation for more details on those traits.
    pub fn new(protocol: P, addr: SocketAddr) -> TcpServer<Kind, P> {
        TcpServer {
            _kind: PhantomData,
            proto: Arc::new(protocol),
            threads: 1,
            addr: addr,
        }
    }

    /// Set the address for the server.
    pub fn addr(&mut self, addr: SocketAddr) {
        self.addr = addr;
    }

    /// Set the number of threads running simultaneous event loops (Unix only).
    pub fn threads(&mut self, threads: usize) {
        assert!(threads > 0);
        if cfg!(unix) {
            self.threads = threads;
        }
    }

    /// Start up the server, providing the given service on it.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn serve<S>(&self, new_service: S) where
        S: NewService + Send + Sync + 'static,
        S::Instance: 'static,
        P::ServiceError: 'static,
        P::ServiceResponse: 'static,
        P::ServiceRequest: 'static,
        S::Request: From<P::ServiceRequest>,
        S::Response: Into<P::ServiceResponse>,
        S::Error: Into<P::ServiceError>,
    {
        let new_service = Arc::new(new_service);
        self.with_handle(move |_| new_service.clone())
    }

    /// Start up the server, providing the given service on it, and providing
    /// access to the event loop handle.
    ///
    /// The `new_service` argument is a closure that is given an event loop
    /// handle, and produces a value implementing `NewService`. That value is in
    /// turned used to make a new service instance for each incoming connection.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn with_handle<F, S>(&self, new_service: F) where
        F: Fn(&Handle) -> S + Send + Sync + 'static,
        S: NewService + Send + Sync + 'static,
        S::Instance: 'static,
        P::ServiceError: 'static,
        P::ServiceResponse: 'static,
        P::ServiceRequest: 'static,
        S::Request: From<P::ServiceRequest>,
        S::Response: Into<P::ServiceResponse>,
        S::Error: Into<P::ServiceError>,
    {
        let proto = self.proto.clone();
        let new_service = Arc::new(new_service);
        let addr = self.addr;
        let workers = self.threads;

        let threads = (0..self.threads - 1).map(|i| {
            let proto = proto.clone();
            let new_service = new_service.clone();

            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                serve(proto, addr, workers, &*new_service)
            }).unwrap()
        }).collect::<Vec<_>>();

        serve(proto, addr, workers, &*new_service);

        for thread in threads {
            thread.join().unwrap();
        }
    }
}

fn serve<P, Kind, F, S>(binder: Arc<P>, addr: SocketAddr, workers: usize, new_service: &F)
    where P: BindServer<Kind, TcpStream>,
          F: Fn(&Handle) -> S,
          S: NewService + Send + Sync,
          S::Instance: 'static,
          P::ServiceError: 'static,
          P::ServiceResponse: 'static,
          P::ServiceRequest: 'static,
          S::Request: From<P::ServiceRequest>,
          S::Response: Into<P::ServiceResponse>,
          S::Error: Into<P::ServiceError>,
{
    struct WrapService<S, Request, Response, Error> {
        inner: S,
        _marker: PhantomData<fn() -> (Request, Response, Error)>,
    }

    impl<S, Request, Response, Error> Service for WrapService<S, Request, Response, Error>
        where S: Service,
              S::Request: From<Request>,
              S::Response: Into<Response>,
              S::Error: Into<Error>,
    {
        type Request = Request;
        type Response = Response;
        type Error = Error;
        type Future = Then<S::Future,
                           Result<Response, Error>,
                           fn(Result<S::Response, S::Error>) -> Result<Response, Error>>;

        fn call(&self, req: Request) -> Self::Future {
            fn change_types<A, B, C, D>(r: Result<A, B>) -> Result<C, D>
                where A: Into<C>,
                      B: Into<D>,
            {
                match r {
                    Ok(e) => Ok(e.into()),
                    Err(e) => Err(e.into()),
                }
            }

            self.inner.call(S::Request::from(req)).then(change_types)
        }
    }

    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let new_service = new_service(&handle);
    let listener = listener(&addr, workers, &handle).unwrap();

    let server = listener.incoming().for_each(move |(socket, _)| {
        // Create the service
        let service = try!(new_service.new_service());

        // Bind it!
        binder.bind_server(&handle, socket, WrapService {
            inner: service,
            _marker: PhantomData,
        });

        Ok(())
    });

    core.run(server).unwrap();
}

fn listener(addr: &SocketAddr,
            workers: usize,
            handle: &Handle) -> io::Result<TcpListener> {
    let listener = match *addr {
        SocketAddr::V4(_) => try!(net2::TcpBuilder::new_v4()),
        SocketAddr::V6(_) => try!(net2::TcpBuilder::new_v6()),
    };
    try!(configure_tcp(workers, &listener));
    try!(listener.reuse_address(true));
    try!(listener.bind(addr));
    listener.listen(1024).and_then(|l| {
        TcpListener::from_listener(l, addr, handle)
    })
}

#[cfg(unix)]
fn configure_tcp(workers: usize, tcp: &net2::TcpBuilder) -> io::Result<()> {
    use net2::unix::*;

    if workers > 1 {
        try!(tcp.reuse_port(true));
    }

    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_workers: usize, _tcp: &net2::TcpBuilder) -> io::Result<()> {
    Ok(())
}
<|endoftext|>


<commit_before>use std::{env,
          io::Error,
          ptr::{null,
                null_mut}};

use widestring::WideCString;
use winapi::{shared::{minwindef::{BOOL,
                                  LPDWORD},
                      ntdef::LPCWSTR,
                      winerror::*},
             um::{winbase::LookupAccountSidW,
                  winnt::{PSID,
                          PSID_NAME_USE,
                          SID_NAME_USE}}};

use super::sid::Sid;

extern "system" {
    fn LookupAccountNameW(lpSystemName: LPCWSTR,
                          lpAccountName: LPCWSTR,
                          Sid: PSID,
                          cbSid: LPDWORD,
                          ReferencedDomainName: LPCWSTR,
                          cchReferencedDomainName: LPDWORD,
                          peUse: PSID_NAME_USE)
                          -> BOOL;
}

pub struct Account {
    pub name:         String,
    pub system_name:  Option<String>,
    pub domain:       String,
    pub account_type: SID_NAME_USE,
    pub sid:          Sid,
}

impl Account {
    pub fn from_name(name: &str) -> Option<Account> { lookup_account(name, None) }

    pub fn from_name_and_system(name: &str, system_name: &str) -> Option<Account> {
        lookup_account(name, Some(system_name.to_string()))
    }

    pub fn from_sid(sid: &str) -> Option<Account> {
        let sid = if let Ok(sid) = Sid::from_str(sid) {
            sid
        } else {
            return None;
        };
        let mut name_size: u32 = 0;
        let mut domain_size: u32 = 0;
        let ret = unsafe {
            LookupAccountSidW(null(),
                              sid.raw.as_ptr() as *mut _,
                              null_mut(),
                              &mut name_size as LPDWORD,
                              null_mut(),
                              &mut domain_size as LPDWORD,
                              null_mut())
        };
        if ret == 0 {
            match Error::last_os_error().raw_os_error().unwrap() as u32 {
                ERROR_INSUFFICIENT_BUFFER => {}
                ERROR_NONE_MAPPED => return None,
                _ => {
                    debug!("Error while looking up account for {}: {}",
                           sid.to_string().expect("to convert sid to string"),
                           Error::last_os_error());
                    return None;
                }
            }
        }

        let mut name: Vec<u16> = Vec::with_capacity(name_size as usize);
        let mut domain: Vec<u16> = Vec::with_capacity(domain_size as usize);
        let mut sid_type = 0;

        let ret = unsafe {
            LookupAccountSidW(null(),
                              sid.raw.as_ptr() as *mut _,
                              name.as_mut_ptr(),
                              &mut name_size as LPDWORD,
                              domain.as_mut_ptr(),
                              &mut domain_size as LPDWORD,
                              &mut sid_type as PSID_NAME_USE)
        };
        if ret == 0 {
            error!("Failed to retrieve name for {}: {}",
                   sid.to_string().expect("to convert sid to string"),
                   Error::last_os_error());
            return None;
        }
        unsafe {
            name.set_len(name_size as usize);
            domain.set_len(domain_size as usize);
        }
        let name = WideCString::new(name).expect("valid name widestring")
                                         .to_string_lossy();
        let domain = WideCString::new(domain).expect("valid domain widestring")
                                             .to_string_lossy();
        Some(Account { name,
                       system_name: None,
                       domain,
                       account_type: sid_type,
                       sid })
    }
}

fn lookup_account(name: &str, system_name: Option<String>) -> Option<Account> {
    // if this is a machine account, strip the terminating '$'
    // LookupAccountName will return the sid of the computer account
    // given the computer name. Windows forbids usernames to match the
    // computer name
    let stripped_name =
        if name.to_lowercase() == (env::var("COMPUTERNAME").unwrap().to_lowercase() + "$") {
            &name[..name.len() - 1]
        } else {
            name
        };
    let mut sid_size: u32 = 0;
    let mut domain_size: u32 = 0;
    let wide = WideCString::from_str(stripped_name).unwrap();
    let ret = unsafe {
        LookupAccountNameW(null_mut(),
                           wide.as_ptr(),
                           null_mut(),
                           &mut sid_size as LPDWORD,
                           null_mut(),
                           &mut domain_size as LPDWORD,
                           null_mut())
    };
    if ret == 0 {
        match Error::last_os_error().raw_os_error().unwrap() as u32 {
            ERROR_INSUFFICIENT_BUFFER => {}
            ERROR_NONE_MAPPED => return None,
            _ => {
                debug!("Error while looking up account for {}: {}",
                       name,
                       Error::last_os_error());
                return None;
            }
        }
    }

    let mut sid: Vec<u8> = Vec::with_capacity(sid_size as usize);
    let mut domain: Vec<u16> = Vec::with_capacity(domain_size as usize);
    let mut sid_type: SID_NAME_USE = 0;

    let ret = unsafe {
        LookupAccountNameW(null_mut(),
                           wide.as_ptr(),
                           sid.as_mut_ptr() as PSID,
                           &mut sid_size as LPDWORD,
                           domain.as_mut_ptr(),
                           &mut domain_size as LPDWORD,
                           &mut sid_type as PSID_NAME_USE)
    };
    if ret == 0 {
        error!("Failed to retrieve SID for {}: {}",
               name,
               Error::last_os_error());
        return None;
    }
    unsafe {
        domain.set_len(domain_size as usize);
        sid.set_len(sid_size as usize);
    }
    let domain_str = WideCString::new(domain).unwrap().to_string_lossy();
    Some(Account { name: name.to_string(),
                   system_name,
                   domain: domain_str,
                   account_type: sid_type,
                   sid: Sid { raw: sid } })
}

#[cfg(test)]
mod tests {
    use std::env;

    use winapi::um::winnt::{SidTypeUser,
                            SidTypeWellKnownGroup};

    use super::*;

    #[test]
    fn real_account_returns_some() { assert!(Account::from_name("Administrator").is_some()) }

    #[test]
    fn bogus_account_returns_none() { assert!(Account::from_name("bogus").is_none()) }

    #[test]
    fn user_account_returns_user_type() {
        let acct_type = Account::from_name("Administrator").unwrap().account_type;
        assert_eq!(acct_type, SidTypeUser)
    }

    #[test]
    fn local_user_account_returns_local_machine_as_domain() {
        let acct_domain = Account::from_name("Administrator").unwrap().domain;
        assert_eq!(acct_domain, env::var("COMPUTERNAME").unwrap())
    }

    #[test]
    fn well_known_group_account_returns_correct_type() {
        let acct_type = Account::from_name("Everyone").unwrap().account_type;
        assert_eq!(acct_type, SidTypeWellKnownGroup)
    }

    #[test]
    fn well_known_group_account_has_well_known_sid() {
        let sid = Account::from_name("Everyone").unwrap().sid;
        assert_eq!(sid.to_string().unwrap(), "S-1-1-0")
    }

    #[test]
    fn mixing_case_returns_same_account() {
        let current_user = env::var("USERNAME").unwrap();
        let lower_sid = Account::from_name(current_user.to_lowercase().as_str()).unwrap()
                                                                                .sid;
        let upper_sid = Account::from_name(current_user.to_uppercase().as_str()).unwrap()
                                                                                .sid;
        assert_eq!(lower_sid.to_string().unwrap(),
                   upper_sid.to_string().unwrap())
    }

    #[test]
    fn test_built_in_accounts() {
        // Check the local administrator account
        let administrator = Account::from_sid("LA").expect("Administrator account");
        assert_eq!(administrator.name, "Administrator");
        assert_eq!(administrator.domain,
                   env::var("COMPUTERNAME").expect("COMPUTERNAME env var"));
    }
}
<commit_msg>fix clippy<commit_after>use std::{env,
          io::Error,
          ptr::{null,
                null_mut}};

use widestring::WideCString;
use winapi::{shared::{minwindef::{BOOL,
                                  LPDWORD},
                      ntdef::LPCWSTR,
                      winerror::*},
             um::{winbase::LookupAccountSidW,
                  winnt::{PSID,
                          PSID_NAME_USE,
                          SID_NAME_USE}}};

use super::sid::Sid;

extern "system" {
    fn LookupAccountNameW(lpSystemName: LPCWSTR,
                          lpAccountName: LPCWSTR,
                          Sid: PSID,
                          cbSid: LPDWORD,
                          ReferencedDomainName: LPCWSTR,
                          cchReferencedDomainName: LPDWORD,
                          peUse: PSID_NAME_USE)
                          -> BOOL;
}

pub struct Account {
    pub name:         String,
    pub system_name:  Option<String>,
    pub domain:       String,
    pub account_type: SID_NAME_USE,
    pub sid:          Sid,
}

impl Account {
    pub fn from_name(name: &str) -> Option<Account> { lookup_account(name, None) }

    pub fn from_name_and_system(name: &str, system_name: &str) -> Option<Account> {
        lookup_account(name, Some(system_name.to_string()))
    }

    pub fn from_sid(sid: &str) -> Option<Account> {
        let sid = if let Ok(sid) = Sid::from_str(sid) {
            sid
        } else {
            return None;
        };
        let mut name_size: u32 = 0;
        let mut domain_size: u32 = 0;
        let ret = unsafe {
            LookupAccountSidW(null(),
                              sid.raw.as_ptr() as *mut _,
                              null_mut(),
                              &mut name_size as LPDWORD,
                              null_mut(),
                              &mut domain_size as LPDWORD,
                              null_mut())
        };
        if ret == 0 {
            match Error::last_os_error().raw_os_error().unwrap() as u32 {
                ERROR_INSUFFICIENT_BUFFER => {}
                ERROR_NONE_MAPPED => return None,
                _ => {
                    debug!("Error while looking up account for {}: {}",
                           sid.to_string().expect("to convert sid to string"),
                           Error::last_os_error());
                    return None;
                }
            }
        }

        let mut name: Vec<u16> = Vec::with_capacity(name_size as usize);
        let mut domain: Vec<u16> = Vec::with_capacity(domain_size as usize);
        let mut sid_type = 0;

        let ret = unsafe {
            LookupAccountSidW(null(),
                              sid.raw.as_ptr() as *mut _,
                              name.as_mut_ptr(),
                              &mut name_size as LPDWORD,
                              domain.as_mut_ptr(),
                              &mut domain_size as LPDWORD,
                              &mut sid_type as PSID_NAME_USE)
        };
        if ret == 0 {
            error!("Failed to retrieve name for {}: {}",
                   sid.to_string().expect("to convert sid to string"),
                   Error::last_os_error());
            return None;
        }
        unsafe {
            name.set_len(name_size as usize);
            domain.set_len(domain_size as usize);
        }
        let name = WideCString::from_vec(name).expect("valid name widestring")
                                              .to_string_lossy();
        let domain = WideCString::from_vec(domain).expect("valid domain widestring")
                                                  .to_string_lossy();
        Some(Account { name,
                       system_name: None,
                       domain,
                       account_type: sid_type,
                       sid })
    }
}

fn lookup_account(name: &str, system_name: Option<String>) -> Option<Account> {
    // if this is a machine account, strip the terminating '$'
    // LookupAccountName will return the sid of the computer account
    // given the computer name. Windows forbids usernames to match the
    // computer name
    let stripped_name =
        if name.to_lowercase() == (env::var("COMPUTERNAME").unwrap().to_lowercase() + "$") {
            &name[..name.len() - 1]
        } else {
            name
        };
    let mut sid_size: u32 = 0;
    let mut domain_size: u32 = 0;
    let wide = WideCString::from_str(stripped_name).unwrap();
    let ret = unsafe {
        LookupAccountNameW(null_mut(),
                           wide.as_ptr(),
                           null_mut(),
                           &mut sid_size as LPDWORD,
                           null_mut(),
                           &mut domain_size as LPDWORD,
                           null_mut())
    };
    if ret == 0 {
        match Error::last_os_error().raw_os_error().unwrap() as u32 {
            ERROR_INSUFFICIENT_BUFFER => {}
            ERROR_NONE_MAPPED => return None,
            _ => {
                debug!("Error while looking up account for {}: {}",
                       name,
                       Error::last_os_error());
                return None;
            }
        }
    }

    let mut sid: Vec<u8> = Vec::with_capacity(sid_size as usize);
    let mut domain: Vec<u16> = Vec::with_capacity(domain_size as usize);
    let mut sid_type: SID_NAME_USE = 0;

    let ret = unsafe {
        LookupAccountNameW(null_mut(),
                           wide.as_ptr(),
                           sid.as_mut_ptr() as PSID,
                           &mut sid_size as LPDWORD,
                           domain.as_mut_ptr(),
                           &mut domain_size as LPDWORD,
                           &mut sid_type as PSID_NAME_USE)
    };
    if ret == 0 {
        error!("Failed to retrieve SID for {}: {}",
               name,
               Error::last_os_error());
        return None;
    }
    unsafe {
        domain.set_len(domain_size as usize);
        sid.set_len(sid_size as usize);
    }
    let domain_str = WideCString::from_vec(domain).unwrap().to_string_lossy();
    Some(Account { name: name.to_string(),
                   system_name,
                   domain: domain_str,
                   account_type: sid_type,
                   sid: Sid { raw: sid } })
}

#[cfg(test)]
mod tests {
    use std::env;

    use winapi::um::winnt::{SidTypeUser,
                            SidTypeWellKnownGroup};

    use super::*;

    #[test]
    fn real_account_returns_some() { assert!(Account::from_name("Administrator").is_some()) }

    #[test]
    fn bogus_account_returns_none() { assert!(Account::from_name("bogus").is_none()) }

    #[test]
    fn user_account_returns_user_type() {
        let acct_type = Account::from_name("Administrator").unwrap().account_type;
        assert_eq!(acct_type, SidTypeUser)
    }

    #[test]
    fn local_user_account_returns_local_machine_as_domain() {
        let acct_domain = Account::from_name("Administrator").unwrap().domain;
        assert_eq!(acct_domain, env::var("COMPUTERNAME").unwrap())
    }

    #[test]
    fn well_known_group_account_returns_correct_type() {
        let acct_type = Account::from_name("Everyone").unwrap().account_type;
        assert_eq!(acct_type, SidTypeWellKnownGroup)
    }

    #[test]
    fn well_known_group_account_has_well_known_sid() {
        let sid = Account::from_name("Everyone").unwrap().sid;
        assert_eq!(sid.to_string().unwrap(), "S-1-1-0")
    }

    #[test]
    fn mixing_case_returns_same_account() {
        let current_user = env::var("USERNAME").unwrap();
        let lower_sid = Account::from_name(current_user.to_lowercase().as_str()).unwrap()
                                                                                .sid;
        let upper_sid = Account::from_name(current_user.to_uppercase().as_str()).unwrap()
                                                                                .sid;
        assert_eq!(lower_sid.to_string().unwrap(),
                   upper_sid.to_string().unwrap())
    }

    #[test]
    fn test_built_in_accounts() {
        // Check the local administrator account
        let administrator = Account::from_sid("LA").expect("Administrator account");
        assert_eq!(administrator.name, "Administrator");
        assert_eq!(administrator.domain,
                   env::var("COMPUTERNAME").expect("COMPUTERNAME env var"));
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//

//! Kernel memory management.
//!
//! This module contains all of the non-arch-specific paging code, and
//! re-exports memory-related definitions.
#![crate_name = "memory"]
#![feature(const_fn)]
#![feature(asm)]
#![feature(step_trait)]
#![feature(linkage)]
#![no_std]

#[macro_use] extern crate bitflags;
#[macro_use] extern crate macro_attr;

#[macro_use] extern crate util;
// #[cfg(not(test))] #[macro_use] extern crate vga;
// extern crate alloc as liballoc; // TODO: workaround

#[macro_use] pub mod macros;
pub mod arch;

// use alloc::buddy;
// use ::params::InitParams;
use core::{ops, cmp, convert};
use util::Align;

pub use arch::{PAddr, PAGE_SHIFT, PAGE_SIZE};

pub mod alloc;

/// Trait representing an address, whether physical or virtual.
pub trait Addr: ops::Add<Self> + ops::Sub<Self>
              + ops::Mul<Self> + ops::Div<Self>
              + ops::Shl<Self> + ops::Shr<Self>
              + ops::BitOr<Self> + ops::BitAnd<Self>
              + convert::From<*mut u8> + convert::From<*const u8>
              + Sized {
    type Repr: Align;

    fn align_down(&self, align: Self::Repr) -> Self;
    fn align_up(&self, align: Self::Repr) -> Self;

    /// Returns true if this address is aligned on a page boundary.
    fn is_page_aligned(&self) -> bool;
}

//impl Addr<usize> for VAddr { }

//impl_addr! { VAddr, usize }

macro_attr! {
    /// A virtual address is a machine-sized unsigned integer
    #[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd, Addr!(usize))]
    pub struct VAddr(usize);
}

impl VAddr {
    /// Convert this virtual address to a pointer
    #[inline] pub fn from_ptr<T>(ptr: *mut T) -> Self { VAddr(ptr as usize) }

    /// Convert a `usize` to a virtual address
    #[inline] pub const fn from_usize(u: usize) -> Self { VAddr(u) }

    /// Convert this virtual address to a `usize`.
    #[inline] pub const fn as_usize(&self) -> usize { self.0 }

    /// Calculate the index in the PML4 table corresponding to this address.
    #[inline] pub fn pml4_index(&self) -> usize {
        *((self >> 39) & 0b111111111 as usize)
    }

    /// Calculate the index in the PDPT table corresponding to this address.
    #[inline] pub fn pdpt_index(&self) -> usize {
        *((self >> 30) & 0b111111111)
    }

    /// Calculate the index in the PD table corresponding to this address.
    #[inline] pub fn pd_index(&self) -> usize {
        *((self >> 21) & 0b111111111)
    }

    /// Calculate the index in the PT table corresponding to this address.
    #[inline] pub fn pt_index(&self) -> usize {
        *((self >> 12) & 0b111111111)
    }
}

use core::ops::Range;

pub use arch::PhysicalPage;

pub type PageRange = Range<VirtualPage>;
pub type FrameRange = Range<PhysicalPage>;

/// Trait for a page. These can be virtual pages or physical frames.
pub trait Page
where Self: Sized
    , Self: ops::AddAssign<usize> + ops::SubAssign<usize>
    , Self: ops::Add<usize, Output=Self> + ops::Sub<usize, Output=Self>
    , Self: cmp::PartialEq<Self> + cmp::PartialOrd<Self>
    , Self: Copy + Clone {

    /// The type of address used to address this `Page`.
    ///
    /// Typically, this is a `PAddr` or `VAddr` (but it could be a "MAddr")
    /// in schemes where we differentiate between physical and machine
    /// addresses. If we ever have those.
    type Address: Addr;

    /// Returns a new `Page` containing the given `Address`.
    ///
    /// N.B. that since trait functions cannot be `const`, implementors of
    /// this trait may wish to provide implementations of this function
    /// outside of the `impl` block and then wrap them here.
    fn containing(addr: Self::Address) -> Self;

    /// Returns the base `Address` where this page starts.
    fn base(&self) -> Self::Address;

    ///// Convert the frame into a raw pointer to the frame's base address
    //#[inline]
    //unsafe fn as_ptr<T>(&self) -> *const T {
    //    mem::transmute(self.base())
    //}
    //
    ///// Convert the frame into a raw mutable pointer to the frame's base address
    //#[inline]
    //unsafe fn as_mut_ptr<T>(&self) -> *mut T {
    //    mem::transmute(self.base())
    //}

    /// Returns a `PageRange` of this `Page` and the next `n` pages.
    #[inline]
    fn range_of(&self, n: usize) -> Range<Self> {
        self.range_until(*self + n)
    }

    /// Returns a `PageRange` on the frames from this frame until the end frame
    #[inline]
    fn range_until(&self, end: Self) -> Range<Self> {
        Range { start: *self, end: end }
    }

    fn number(&self) -> usize;

}

macro_attr!{
    /// A virtual page
    #[derive( Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Page!(VAddr) )]
    pub struct VirtualPage { pub number: usize }
}

impl convert::From<PAddr> for PhysicalPage {
    #[inline] fn from(addr: PAddr) -> Self {
        PhysicalPage::containing(addr)
    }
}

impl convert::From<VAddr> for VirtualPage {
    #[inline] fn from(addr: VAddr) -> Self {
        VirtualPage::containing(addr)
    }
}

//
///// A range of `Page`s.
//#[derive(Copy, Clone, Debug, Eq, PartialEq)]
//pub struct Range

//where P: Page { start: P, end: P }
//
pub trait MemRange {
    /// Returns the number of `Page`s in this ranage
    #[inline]
    fn length(&self) -> usize;

    /// Remove `n` pages from the beginning of this `PageRange`
    fn drop_front(&mut self, n: usize) -> &mut Self;

    /// Remove `n` pages from the end of this `PageRange`
    fn drop_back(&mut self, n: usize) -> &mut Self;

    /// Add `n` pages at the front of this `PageRange`
    fn add_front(&mut self, n: usize) -> &mut Self;

    /// Add `n` pages at the back of this `PageRange`
    fn add_back(&mut self, n: usize) -> &mut Self;
}
    //pub const fn start(&self) -> P { self.start }
   //
   ///// Returns a `PageRange` between two pages
   //pub const fn between(start: P, end: P) -> Range
 {
   //    Range { start: start, end: end }
   //}
   //
   // /// Returns an iterator over this `PageRange`
   // pub fn iter<'a>(&'a self) -> RangeIter<'a, P> {
   //     RangeIter { range: self, current: self.start.clone() }
   // }

impl
 MemRange for Range

where P: Page {

    /// Returns the number of `Page`s in this ranage
    #[inline]
    fn length(&self) -> usize {
        self.end.number() - self.start.number()
    }

    /// Remove `n` pages from the beginning of this `PageRange`
    fn drop_front(&mut self, n: usize) -> &mut Self {
        assert!(n < self.length());
        self.start += n;
        self
    }

    /// Remove `n` pages from the end of this `PageRange`
    fn drop_back(&mut self, n: usize) -> &mut Self {
        assert!(n < self.length());
        self.end -= n;
        self
    }

    /// Add `n` pages at the front of this `PageRange`
    fn add_front(&mut self, n: usize) -> &mut Self {
        self.start -= n;
        self
    }

    /// Add `n` pages at the back of this `PageRange`
    fn add_back(&mut self, n: usize) -> &mut Self {
        self.end += n;
        self
    }
}

/// An iterator over a range of pages
pub struct RangeIter<'a, P>
where P: Page
    , P: 'a { range: &'a Range
, current: P }

impl<'a, P> Iterator for RangeIter<'a, P>
where P: Page
    , P: Clone {
    type Item = P;

    fn next(&mut self) -> Option
 {
        let end = self.range.end;
      assert!(self.range.start <= end);
      if self.current < end {
          let page = self.current.clone();
          self.current += 1;
          Some(page)
      } else {
          None
      }
  }

}
<commit_msg>fix(memory): delete reference to module removed in merge<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//

//! Kernel memory management.
//!
//! This module contains all of the non-arch-specific paging code, and
//! re-exports memory-related definitions.
#![crate_name = "memory"]
#![feature(const_fn)]
#![feature(asm)]
#![feature(step_trait)]
#![feature(linkage)]
#![no_std]

#[macro_use] extern crate bitflags;
#[macro_use] extern crate macro_attr;

#[macro_use] extern crate util;
// #[cfg(not(test))] #[macro_use] extern crate vga;
// extern crate alloc as liballoc; // TODO: workaround

#[macro_use] pub mod macros;
pub mod arch;

// use alloc::buddy;
// use ::params::InitParams;
use core::{ops, cmp, convert};
use util::Align;

pub use arch::{PAddr, PAGE_SHIFT, PAGE_SIZE};

/// Trait representing an address, whether physical or virtual.
pub trait Addr: ops::Add<Self> + ops::Sub<Self>
              + ops::Mul<Self> + ops::Div<Self>
              + ops::Shl<Self> + ops::Shr<Self>
              + ops::BitOr<Self> + ops::BitAnd<Self>
              + convert::From<*mut u8> + convert::From<*const u8>
              + Sized {
    type Repr: Align;

    fn align_down(&self, align: Self::Repr) -> Self;
    fn align_up(&self, align: Self::Repr) -> Self;

    /// Returns true if this address is aligned on a page boundary.
    fn is_page_aligned(&self) -> bool;
}

//impl Addr<usize> for VAddr { }

//impl_addr! { VAddr, usize }

macro_attr! {
    /// A virtual address is a machine-sized unsigned integer
    #[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd, Addr!(usize))]
    pub struct VAddr(usize);
}

impl VAddr {
    /// Convert this virtual address to a pointer
    #[inline] pub fn from_ptr<T>(ptr: *mut T) -> Self { VAddr(ptr as usize) }

    /// Convert a `usize` to a virtual address
    #[inline] pub const fn from_usize(u: usize) -> Self { VAddr(u) }

    /// Convert this virtual address to a `usize`.
    #[inline] pub const fn as_usize(&self) -> usize { self.0 }

    /// Calculate the index in the PML4 table corresponding to this address.
    #[inline] pub fn pml4_index(&self) -> usize {
        *((self >> 39) & 0b111111111 as usize)
    }

    /// Calculate the index in the PDPT table corresponding to this address.
    #[inline] pub fn pdpt_index(&self) -> usize {
        *((self >> 30) & 0b111111111)
    }

    /// Calculate the index in the PD table corresponding to this address.
    #[inline] pub fn pd_index(&self) -> usize {
        *((self >> 21) & 0b111111111)
    }

    /// Calculate the index in the PT table corresponding to this address.
    #[inline] pub fn pt_index(&self) -> usize {
        *((self >> 12) & 0b111111111)
    }
}

use core::ops::Range;

pub use arch::PhysicalPage;

pub type PageRange = Range<VirtualPage>;
pub type FrameRange = Range<PhysicalPage>;

/// Trait for a page. These can be virtual pages or physical frames.
pub trait Page
where Self: Sized
    , Self: ops::AddAssign<usize> + ops::SubAssign<usize>
    , Self: ops::Add<usize, Output=Self> + ops::Sub<usize, Output=Self>
    , Self: cmp::PartialEq<Self> + cmp::PartialOrd<Self>
    , Self: Copy + Clone {

    /// The type of address used to address this `Page`.
    ///
    /// Typically, this is a `PAddr` or `VAddr` (but it could be a "MAddr")
    /// in schemes where we differentiate between physical and machine
    /// addresses. If we ever have those.
    type Address: Addr;

    /// Returns a new `Page` containing the given `Address`.
    ///
    /// N.B. that since trait functions cannot be `const`, implementors of
    /// this trait may wish to provide implementations of this function
    /// outside of the `impl` block and then wrap them here.
    fn containing(addr: Self::Address) -> Self;

    /// Returns the base `Address` where this page starts.
    fn base(&self) -> Self::Address;

    ///// Convert the frame into a raw pointer to the frame's base address
    //#[inline]
    //unsafe fn as_ptr<T>(&self) -> *const T {
    //    mem::transmute(self.base())
    //}
    //
    ///// Convert the frame into a raw mutable pointer to the frame's base address
    //#[inline]
    //unsafe fn as_mut_ptr<T>(&self) -> *mut T {
    //    mem::transmute(self.base())
    //}

    /// Returns a `PageRange` of this `Page` and the next `n` pages.
    #[inline]
    fn range_of(&self, n: usize) -> Range<Self> {
        self.range_until(*self + n)
    }

    /// Returns a `PageRange` on the frames from this frame until the end frame
    #[inline]
    fn range_until(&self, end: Self) -> Range<Self> {
        Range { start: *self, end: end }
    }

    fn number(&self) -> usize;

}

macro_attr!{
    /// A virtual page
    #[derive( Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Page!(VAddr) )]
    pub struct VirtualPage { pub number: usize }
}

impl convert::From<PAddr> for PhysicalPage {
    #[inline] fn from(addr: PAddr) -> Self {
        PhysicalPage::containing(addr)
    }
}

impl convert::From<VAddr> for VirtualPage {
    #[inline] fn from(addr: VAddr) -> Self {
        VirtualPage::containing(addr)
    }
}

//
///// A range of `Page`s.
//#[derive(Copy, Clone, Debug, Eq, PartialEq)]
//pub struct Range

//where P: Page { start: P, end: P }
//
pub trait MemRange {
    /// Returns the number of `Page`s in this ranage
    #[inline]
    fn length(&self) -> usize;

    /// Remove `n` pages from the beginning of this `PageRange`
    fn drop_front(&mut self, n: usize) -> &mut Self;

    /// Remove `n` pages from the end of this `PageRange`
    fn drop_back(&mut self, n: usize) -> &mut Self;

    /// Add `n` pages at the front of this `PageRange`
    fn add_front(&mut self, n: usize) -> &mut Self;

    /// Add `n` pages at the back of this `PageRange`
    fn add_back(&mut self, n: usize) -> &mut Self;
}
    //pub const fn start(&self) -> P { self.start }
   //
   ///// Returns a `PageRange` between two pages
   //pub const fn between(start: P, end: P) -> Range
 {
   //    Range { start: start, end: end }
   //}
   //
   // /// Returns an iterator over this `PageRange`
   // pub fn iter<'a>(&'a self) -> RangeIter<'a, P> {
   //     RangeIter { range: self, current: self.start.clone() }
   // }

impl
 MemRange for Range

where P: Page {

    /// Returns the number of `Page`s in this ranage
    #[inline]
    fn length(&self) -> usize {
        self.end.number() - self.start.number()
    }

    /// Remove `n` pages from the beginning of this `PageRange`
    fn drop_front(&mut self, n: usize) -> &mut Self {
        assert!(n < self.length());
        self.start += n;
        self
    }

    /// Remove `n` pages from the end of this `PageRange`
    fn drop_back(&mut self, n: usize) -> &mut Self {
        assert!(n < self.length());
        self.end -= n;
        self
    }

    /// Add `n` pages at the front of this `PageRange`
    fn add_front(&mut self, n: usize) -> &mut Self {
        self.start -= n;
        self
    }

    /// Add `n` pages at the back of this `PageRange`
    fn add_back(&mut self, n: usize) -> &mut Self {
        self.end += n;
        self
    }
}

/// An iterator over a range of pages
pub struct RangeIter<'a, P>
where P: Page
    , P: 'a { range: &'a Range
, current: P }

impl<'a, P> Iterator for RangeIter<'a, P>
where P: Page
    , P: Clone {
    type Item = P;

    fn next(&mut self) -> Option
 {
        let end = self.range.end;
      assert!(self.range.start <= end);
      if self.current < end {
          let page = self.current.clone();
          self.current += 1;
          Some(page)
      } else {
          None
      }
  }

}
<|endoftext|>


<commit_before>extern crate clap;
use clap::{App, Arg, SubCommand};
use std::io::{self, BufReader, Read};

extern crate encoding;
extern crate xor;

fn main() {
    let matches = App::new("cryt")
                          .version("v0.1")
                          .author("Nicolas Schmidt <nfschmidt@gmail.com>")
                          .about("Cryptographic tools")
                          .subcommand(SubCommand::with_name("encode")
                                      .about("Encode input with the specified encoding")
                                      .subcommand(SubCommand::with_name("hex")
                                                  .about("Encode input in hex"))
                                      .subcommand(SubCommand::with_name("base64")
                                                  .about("Encode input in base64")))
                          .subcommand(SubCommand::with_name("decode")
                                      .about("Decode input with the specified encoding")
                                      .subcommand(SubCommand::with_name("hex")
                                                  .about("Decode input in hex"))
                                      .subcommand(SubCommand::with_name("base64")
                                                  .about("Decode input in base64")))
                          .subcommand(SubCommand::with_name("encrypt")
                                      .about("Encrypt input with the specified algorithm")
                                      .subcommand(SubCommand::with_name("xor")
                                                  .about("Encrypt using xor")
                                                  .arg(Arg::with_name("key")
                                                       .short("k")
                                                       .long("key")
                                                       .takes_value(true)
                                                       .required(true)
                                                       .help("xor key to be used"))))
                          .get_matches();

    if let Some(matches) = matches.subcommand_matches("encode") {
        if let Some(_) = matches.subcommand_matches("base64") {
            run_encode_base64();
        } else if let Some(_) = matches.subcommand_matches("hex") {
            run_encode_hex();
        }
    } else if let Some(matches) = matches.subcommand_matches("decode") {
        if let Some(_) = matches.subcommand_matches("base64") {
            run_decode_base64();
        } else if let Some(_) = matches.subcommand_matches("hex") {
            run_decode_hex();
        }
    } else if let Some(matches) = matches.subcommand_matches("encrypt") {
        if let Some(matches) = matches.subcommand_matches("xor") {
            match matches.value_of("key") {
                Some(k) => {
                    run_encrypt_xor(k);
                }
                None => {
                    println!("Error: No key received!");
                }
            }
        }
    } else {
        run_interpreter();
    }
}

fn run_encode_base64() {
    let result = encoding::base64_encode(io::stdin());
    print!("{}", result);
}

fn run_encode_hex() {
    let result = encoding::hex_encode(io::stdin());
    print!("{}", result);
}

fn run_decode_base64() {
    let mut input = String::new();
    match io::stdin().read_to_string(&mut input) {
        Ok(_) => {
            let result: String = encoding::base64_decode(&input)
                .into_iter()
                .map(|b| b as char)
                .collect();
            println!("{}", result);
        }
        Err(error) => { print!("Error: {}", error); }
    }
}

fn run_decode_hex() {
    let mut input = String::new();
    match io::stdin().read_to_string(&mut input) {
        Ok(_) => {
            let result: String = encoding::hex_decode(&input)
                .into_iter()
                .map(|b| b as char)
                .collect();
            print!("{}", result);
        }
        Err(error) => { println!("Error: {}", error); }
    }
}

fn run_encrypt_xor(key: &str) {
    let result: String = xor::repeated_xor(io::stdin(), BufReader::new(key.as_bytes()))
        .into_iter()
        .map(|b| b as char)
        .collect();
    print!("{}", result);
}

fn run_interpreter() {
    println!("Interpreter");
}
<commit_msg>Added decrypt subcommand<commit_after>extern crate clap;
use clap::{App, Arg, SubCommand};
use std::io::{self, BufReader, Read};

extern crate encoding;
extern crate xor;

fn main() {
    let matches = App::new("cryt")
                          .version("v0.1")
                          .author("Nicolas Schmidt <nfschmidt@gmail.com>")
                          .about("Cryptographic tools")
                          .subcommand(SubCommand::with_name("encode")
                                      .about("Encode input with the specified encoding")
                                      .subcommand(SubCommand::with_name("hex")
                                                  .about("Encode input in hex"))
                                      .subcommand(SubCommand::with_name("base64")
                                                  .about("Encode input in base64")))
                          .subcommand(SubCommand::with_name("decode")
                                      .about("Decode input with the specified encoding")
                                      .subcommand(SubCommand::with_name("hex")
                                                  .about("Decode input in hex"))
                                      .subcommand(SubCommand::with_name("base64")
                                                  .about("Decode input in base64")))
                          .subcommand(SubCommand::with_name("encrypt")
                                      .about("Encrypt input with the specified algorithm")
                                      .subcommand(SubCommand::with_name("xor")
                                                  .about("Encrypt using xor")
                                                  .arg(Arg::with_name("key")
                                                       .short("k")
                                                       .long("key")
                                                       .takes_value(true)
                                                       .required(true)
                                                       .help("xor key to be used"))))
                          .subcommand(SubCommand::with_name("encrypt")
                                      .about("Decrypt input with the specified algorithm")
                                      .subcommand(SubCommand::with_name("xor")
                                                  .about("Decrypt using xor")
                                                  .arg(Arg::with_name("key")
                                                       .short("k")
                                                       .long("key")
                                                       .takes_value(true)
                                                       .required(true)
                                                       .help("xor key to be used"))))
                          .get_matches();

    if let Some(matches) = matches.subcommand_matches("encode") {
        if let Some(_) = matches.subcommand_matches("base64") {
            run_encode_base64();
        } else if let Some(_) = matches.subcommand_matches("hex") {
            run_encode_hex();
        }
    } else if let Some(matches) = matches.subcommand_matches("decode") {
        if let Some(_) = matches.subcommand_matches("base64") {
            run_decode_base64();
        } else if let Some(_) = matches.subcommand_matches("hex") {
            run_decode_hex();
        }
    } else if let Some(matches) = matches.subcommand_matches("encrypt") {
        if let Some(matches) = matches.subcommand_matches("xor") {
            match matches.value_of("key") {
                Some(k) => {
                    run_encrypt_xor(k);
                }
                None => {
                    println!("Error: No key received!");
                }
            }
        }
    } else {
        run_interpreter();
    }
}

fn run_encode_base64() {
    let result = encoding::base64_encode(io::stdin());
    print!("{}", result);
}

fn run_encode_hex() {
    let result = encoding::hex_encode(io::stdin());
    print!("{}", result);
}

fn run_decode_base64() {
    let mut input = String::new();
    match io::stdin().read_to_string(&mut input) {
        Ok(_) => {
            let result: String = encoding::base64_decode(&input)
                .into_iter()
                .map(|b| b as char)
                .collect();
            println!("{}", result);
        }
        Err(error) => { print!("Error: {}", error); }
    }
}

fn run_decode_hex() {
    let mut input = String::new();
    match io::stdin().read_to_string(&mut input) {
        Ok(_) => {
            let result: String = encoding::hex_decode(&input)
                .into_iter()
                .map(|b| b as char)
                .collect();
            print!("{}", result);
        }
        Err(error) => { println!("Error: {}", error); }
    }
}

fn run_encrypt_xor(key: &str) {
    let result: String = xor::repeated_xor(io::stdin(), BufReader::new(key.as_bytes()))
        .into_iter()
        .map(|b| b as char)
        .collect();
    print!("{}", result);
}

fn run_interpreter() {
    println!("Interpreter");
}
<|endoftext|>


<commit_before>use super::*;

use std::marker::PhantomData;
use winit::event_loop::EventLoop;
use winit::window::{Window, WindowBuilder};

/// Represents an OpenGL [`Context`] and the [`Window`] with which it is
/// associated.
///
/// Please see [`ContextWrapper<T, Window>`].
///
/// # Example
///
/// ```no_run
/// # fn main() {
/// let mut el = glutin::event_loop::EventLoop::new();
/// let wb = glutin::window::WindowBuilder::new();
/// let windowed_context = glutin::ContextBuilder::new()
///     .build_windowed(wb, &el)
///     .unwrap();
///
/// let windowed_context = unsafe { windowed_context.make_current().unwrap() };
/// # }
/// ```
///
/// [`ContextWrapper<T, Window>`]: struct.ContextWrapper.html
/// [`Window`]: struct.Window.html
/// [`Context`]: struct.Context.html
pub type WindowedContext<T> = ContextWrapper<T, Window>;

/// Represents an OpenGL [`Context`] which has an underlying window that is
/// stored separately.
///
/// This type can only be created via one of three ways:
///
///  * [`platform::unix::RawContextExt`]
///  * [`platform::windows::RawContextExt`]
///  * [`WindowedContext<T>::split`]
///
/// Please see [`ContextWrapper<T, ()>`].
///
/// [`ContextWrapper<T, ()>`]: struct.ContextWrapper.html
/// [`WindowedContext<T>::split`]: type.WindowedContext.html#method.split
/// [`Context`]: struct.Context.html
#[cfg_attr(
    target_os = "windows",
    doc = "\
[`platform::windows::RawContextExt`]: os/windows/enum.RawHandle.html
"
)]
#[cfg_attr(
    not(target_os = "windows",),
    doc = "\
[`platform::windows::RawContextExt`]: os/index.html
"
)]
#[cfg_attr(
    not(any(
        target_os = "linux",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
    )),
    doc = "\
[`platform::unix::RawContextExt`]: os/index.html
"
)]
#[cfg_attr(
    any(
        target_os = "linux",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
    ),
    doc = "\
[`platform::unix::RawContextExt`]: os/unix/enum.RawHandle.html
"
)]
pub type RawContext<T> = ContextWrapper<T, ()>;

/// A context which has an underlying window, which may or may not be stored
/// separately.
///
/// If the window is stored separately, it is a [`RawContext<T>`]. Otherwise,
/// it is a [`WindowedContext<T>`].
///
/// [`WindowedContext<T>`]: type.WindowedContext.html
/// [`RawContext<T>`]: type.RawContext.html
/// [`Context`]: struct.Context.html
#[derive(Debug)]
pub struct ContextWrapper<T: ContextCurrentState, W> {
    pub(crate) context: Context<T>,
    pub(crate) window: W,
}

impl<T: ContextCurrentState> WindowedContext<T> {
    /// Borrow the inner `W`.
    pub fn window(&self) -> &Window {
        &self.window
    }

    /// Split the [`Window`] apart from the OpenGL [`Context`]. Should only be
    /// used when intending to transfer the [`RawContext<T>`] to an other
    /// thread.
    ///
    /// Unsaftey:
    ///   - The OpenGL [`Context`] must be dropped before the [`Window`].
    ///
    /// [`RawContext<T>`]: type.RawContext.html
    /// [`Window`]: struct.Window.html
    /// [`Context`]: struct.Context.html
    pub unsafe fn split(self) -> (RawContext<T>, Window) {
        (
            RawContext {
                context: self.context,
                window: (),
            },
            self.window,
        )
    }
}

impl<W> ContextWrapper<PossiblyCurrent, W> {
    /// Swaps the buffers in case of double or triple buffering.
    ///
    /// You should call this function every time you have finished rendering, or
    /// the image may not be displayed on the screen.
    ///
    /// **Warning**: if you enabled vsync, this function will block until the
    /// next time the screen is refreshed. However drivers can choose to
    /// override your vsync settings, which means that you can't know in
    /// advance whether `swap_buffers` will block or not.
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        self.context.context.swap_buffers()
    }

    /// Returns the pixel format of the main framebuffer of the context.
    pub fn get_pixel_format(&self) -> PixelFormat {
        self.context.context.get_pixel_format()
    }

    /// Resize the context.
    ///
    /// Some platforms (macOS, Wayland) require being manually updated when
    /// their window or surface is resized.
    ///
    /// The easiest way of doing this is to take every [`Resized`] window event
    /// that is received with a [`LogicalSize`] and convert it to a
    /// [`PhysicalSize`] and pass it into this function.
    ///
    /// [`LogicalSize`]: dpi/struct.LogicalSize.html
    /// [`PhysicalSize`]: dpi/struct.PhysicalSize.html
    /// [`Resized`]: event/enum.WindowEvent.html#variant.Resized
    pub fn resize(&self, size: dpi::PhysicalSize) {
        let (width, height) = size.into();
        self.context.context.resize(width, height);
    }
}

impl<T: ContextCurrentState, W> ContextWrapper<T, W> {
    /// Borrow the inner GL [`Context`].
    ///
    /// [`Context`]: struct.Context.html
    pub fn context(&self) -> &Context<T> {
        &self.context
    }

    /// Sets this context as the current context. The previously current context
    /// (if any) is no longer current.
    ///
    /// A failed call to `make_current` might make this, or no context
    /// current. It could also keep the previous context current. What happens
    /// varies by platform and error.
    ///
    /// To attempt to recover and get back into a know state, either:
    ///
    ///  * attempt to use [`is_current`] to find the new current context; or
    ///  * call [`make_not_current`] on both the previously
    ///  current context and this context.
    ///
    /// # An higher level overview.
    ///
    /// In OpenGl, only a single context can be current in a thread at a time.
    /// Making a new context current will make the old one not current.
    /// Contexts can only be sent to different threads if they are not current.
    ///
    /// If you call `make_current` on some context, you should call
    /// [`treat_as_not_current`] as soon as possible on the previously current
    /// context.
    ///
    /// If you wish to move a currently current context to a different thread,
    /// you should do one of two options:
    ///
    ///  * Call `make_current` on an other context, then call
    ///  [`treat_as_not_current`] on this context.
    ///  * Call [`make_not_current`] on this context.
    ///
    /// If you are aware of what context you intend to make current next, it is
    /// preferable for performance reasons to call `make_current` on that
    /// context, then [`treat_as_not_current`] on this context.
    ///
    /// If you are not aware of what context you intend to make current next,
    /// consider waiting until you do. If you need this context not current
    /// immediately (e.g. to transfer it to an other thread), then call
    /// [`make_not_current`] on this context.
    ///
    /// Please avoid calling [`make_not_current`] on one context only to call
    /// `make_current` on an other context before and/or after. This hurts
    /// performance by requiring glutin to:
    ///
    ///  * Check if this context is current; then
    ///  * If it is, change the current context from this context to none; then
    ///  * Change the current context from none to the new context.
    ///
    /// Instead prefer the method we mentioned above with `make_current` and
    /// [`treat_as_not_current`].
    ///
    /// [`make_not_current`]: struct.ContextWrapper.html#method.make_not_current
    /// [`treat_as_not_current`]:
    /// struct.ContextWrapper.html#method.treat_as_not_current
    /// [`is_current`]: struct.ContextWrapper.html#method.is_current
    pub unsafe fn make_current(
        self,
    ) -> Result<ContextWrapper<PossiblyCurrent, W>, (Self, ContextError)> {
        let window = self.window;
        match self.context.make_current() {
            Ok(context) => Ok(ContextWrapper { window, context }),
            Err((context, err)) => {
                Err((ContextWrapper { window, context }, err))
            }
        }
    }

    /// If this context is current, makes this context not current. If this
    /// context is not current however, this function does nothing.
    ///
    /// Please see [`make_current`].
    ///
    /// [`make_current`]: struct.ContextWrapper.html#method.make_current
    pub unsafe fn make_not_current(
        self,
    ) -> Result<ContextWrapper<NotCurrent, W>, (Self, ContextError)> {
        let window = self.window;
        match self.context.make_not_current() {
            Ok(context) => Ok(ContextWrapper { window, context }),
            Err((context, err)) => {
                Err((ContextWrapper { window, context }, err))
            }
        }
    }

    /// Treats this context as not current, even if it is current. We do no
    /// checks to confirm that this is actually case.
    ///
    /// If unsure whether or not this context is current, please use
    /// [`make_not_current`] which will do nothing if this context is not
    /// current.
    ///
    /// Please see [`make_current`].
    ///
    /// [`make_not_current`]: struct.ContextWrapper.html#method.make_not_current
    /// [`make_current`]: struct.ContextWrapper.html#method.make_current
    pub unsafe fn treat_as_not_current(self) -> ContextWrapper<NotCurrent, W> {
        ContextWrapper {
            context: self.context.treat_as_not_current(),
            window: self.window,
        }
    }

    /// Treats this context as current, even if it is not current. We do no
    /// checks to confirm that this is actually case.
    ///
    /// This function should only be used if you intend to track context
    /// currency without the limited aid of glutin, and you wish to store
    /// all the [`Context`]s as [`NotCurrent`].
    ///
    /// Please see [`make_current`] for the prefered method of handling context
    /// currency.
    ///
    /// [`make_current`]: struct.ContextWrapper.html#method.make_current
    /// [`NotCurrent`]: enum.NotCurrent.html
    /// [`Context`]: struct.Context.html
    pub unsafe fn treat_as_current(self) -> ContextWrapper<PossiblyCurrent, W> {
        ContextWrapper {
            context: self.context.treat_as_current(),
            window: self.window,
        }
    }

    /// Returns true if this context is the current one in this thread.
    pub fn is_current(&self) -> bool {
        self.context.is_current()
    }

    /// Returns the OpenGL API being used.
    pub fn get_api(&self) -> Api {
        self.context.get_api()
    }
}

impl<W> ContextWrapper<PossiblyCurrent, W> {
    /// Returns the address of an OpenGL function.
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        self.context.get_proc_address(addr)
    }
}

impl<T: ContextCurrentState, W> std::ops::Deref for ContextWrapper<T, W> {
    type Target = Context<T>;
    fn deref(&self) -> &Self::Target {
        &self.context
    }
}

impl<'a, T: ContextCurrentState> ContextBuilder<'a, T> {
    /// Builds the given window along with the associated GL context, returning
    /// the pair as a [`WindowedContext<T>`].
    ///
    /// Errors can occur in two scenarios:
    ///  - If the window could not be created (via permission denied,
    ///  incompatible system, out of memory, etc.). This should be very rare.
    ///  - If the OpenGL [`Context`] could not be created. This generally
    ///    happens
    ///  because the underlying platform doesn't support a requested feature.
    ///
    /// [`WindowedContext<T>`]: type.WindowedContext.html
    /// [`Context`]: struct.Context.html
    pub fn build_windowed<TE>(
        self,
        wb: WindowBuilder,
        el: &EventLoop<TE>,
    ) -> Result<WindowedContext<NotCurrent>, CreationError> {
        let ContextBuilder { pf_reqs, gl_attr } = self;
        let gl_attr = gl_attr.map_sharing(|ctx| &ctx.context);
        platform_impl::Context::new_windowed(wb, el, &pf_reqs, &gl_attr).map(
            |(window, context)| WindowedContext {
                window,
                context: Context {
                    context,
                    phantom: PhantomData,
                },
            },
        )
    }
}
<commit_msg>typo fix (#1196)<commit_after>use super::*;

use std::marker::PhantomData;
use winit::event_loop::EventLoop;
use winit::window::{Window, WindowBuilder};

/// Represents an OpenGL [`Context`] and the [`Window`] with which it is
/// associated.
///
/// Please see [`ContextWrapper<T, Window>`].
///
/// # Example
///
/// ```no_run
/// # fn main() {
/// let mut el = glutin::event_loop::EventLoop::new();
/// let wb = glutin::window::WindowBuilder::new();
/// let windowed_context = glutin::ContextBuilder::new()
///     .build_windowed(wb, &el)
///     .unwrap();
///
/// let windowed_context = unsafe { windowed_context.make_current().unwrap() };
/// # }
/// ```
///
/// [`ContextWrapper<T, Window>`]: struct.ContextWrapper.html
/// [`Window`]: struct.Window.html
/// [`Context`]: struct.Context.html
pub type WindowedContext<T> = ContextWrapper<T, Window>;

/// Represents an OpenGL [`Context`] which has an underlying window that is
/// stored separately.
///
/// This type can only be created via one of three ways:
///
///  * [`platform::unix::RawContextExt`]
///  * [`platform::windows::RawContextExt`]
///  * [`WindowedContext<T>::split`]
///
/// Please see [`ContextWrapper<T, ()>`].
///
/// [`ContextWrapper<T, ()>`]: struct.ContextWrapper.html
/// [`WindowedContext<T>::split`]: type.WindowedContext.html#method.split
/// [`Context`]: struct.Context.html
#[cfg_attr(
    target_os = "windows",
    doc = "\
[`platform::windows::RawContextExt`]: os/windows/enum.RawHandle.html
"
)]
#[cfg_attr(
    not(target_os = "windows",),
    doc = "\
[`platform::windows::RawContextExt`]: os/index.html
"
)]
#[cfg_attr(
    not(any(
        target_os = "linux",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
    )),
    doc = "\
[`platform::unix::RawContextExt`]: os/index.html
"
)]
#[cfg_attr(
    any(
        target_os = "linux",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
    ),
    doc = "\
[`platform::unix::RawContextExt`]: os/unix/enum.RawHandle.html
"
)]
pub type RawContext<T> = ContextWrapper<T, ()>;

/// A context which has an underlying window, which may or may not be stored
/// separately.
///
/// If the window is stored separately, it is a [`RawContext<T>`]. Otherwise,
/// it is a [`WindowedContext<T>`].
///
/// [`WindowedContext<T>`]: type.WindowedContext.html
/// [`RawContext<T>`]: type.RawContext.html
/// [`Context`]: struct.Context.html
#[derive(Debug)]
pub struct ContextWrapper<T: ContextCurrentState, W> {
    pub(crate) context: Context<T>,
    pub(crate) window: W,
}

impl<T: ContextCurrentState> WindowedContext<T> {
    /// Borrow the inner `W`.
    pub fn window(&self) -> &Window {
        &self.window
    }

    /// Split the [`Window`] apart from the OpenGL [`Context`]. Should only be
    /// used when intending to transfer the [`RawContext<T>`] to another
    /// thread.
    ///
    /// Unsaftey:
    ///   - The OpenGL [`Context`] must be dropped before the [`Window`].
    ///
    /// [`RawContext<T>`]: type.RawContext.html
    /// [`Window`]: struct.Window.html
    /// [`Context`]: struct.Context.html
    pub unsafe fn split(self) -> (RawContext<T>, Window) {
        (
            RawContext {
                context: self.context,
                window: (),
            },
            self.window,
        )
    }
}

impl<W> ContextWrapper<PossiblyCurrent, W> {
    /// Swaps the buffers in case of double or triple buffering.
    ///
    /// You should call this function every time you have finished rendering, or
    /// the image may not be displayed on the screen.
    ///
    /// **Warning**: if you enabled vsync, this function will block until the
    /// next time the screen is refreshed. However drivers can choose to
    /// override your vsync settings, which means that you can't know in
    /// advance whether `swap_buffers` will block or not.
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        self.context.context.swap_buffers()
    }

    /// Returns the pixel format of the main framebuffer of the context.
    pub fn get_pixel_format(&self) -> PixelFormat {
        self.context.context.get_pixel_format()
    }

    /// Resize the context.
    ///
    /// Some platforms (macOS, Wayland) require being manually updated when
    /// their window or surface is resized.
    ///
    /// The easiest way of doing this is to take every [`Resized`] window event
    /// that is received with a [`LogicalSize`] and convert it to a
    /// [`PhysicalSize`] and pass it into this function.
    ///
    /// [`LogicalSize`]: dpi/struct.LogicalSize.html
    /// [`PhysicalSize`]: dpi/struct.PhysicalSize.html
    /// [`Resized`]: event/enum.WindowEvent.html#variant.Resized
    pub fn resize(&self, size: dpi::PhysicalSize) {
        let (width, height) = size.into();
        self.context.context.resize(width, height);
    }
}

impl<T: ContextCurrentState, W> ContextWrapper<T, W> {
    /// Borrow the inner GL [`Context`].
    ///
    /// [`Context`]: struct.Context.html
    pub fn context(&self) -> &Context<T> {
        &self.context
    }

    /// Sets this context as the current context. The previously current context
    /// (if any) is no longer current.
    ///
    /// A failed call to `make_current` might make this, or no context
    /// current. It could also keep the previous context current. What happens
    /// varies by platform and error.
    ///
    /// To attempt to recover and get back into a know state, either:
    ///
    ///  * attempt to use [`is_current`] to find the new current context; or
    ///  * call [`make_not_current`] on both the previously
    ///  current context and this context.
    ///
    /// # An higher level overview.
    ///
    /// In OpenGl, only a single context can be current in a thread at a time.
    /// Making a new context current will make the old one not current.
    /// Contexts can only be sent to different threads if they are not current.
    ///
    /// If you call `make_current` on some context, you should call
    /// [`treat_as_not_current`] as soon as possible on the previously current
    /// context.
    ///
    /// If you wish to move a currently current context to a different thread,
    /// you should do one of two options:
    ///
    ///  * Call `make_current` on another context, then call
    ///  [`treat_as_not_current`] on this context.
    ///  * Call [`make_not_current`] on this context.
    ///
    /// If you are aware of what context you intend to make current next, it is
    /// preferable for performance reasons to call `make_current` on that
    /// context, then [`treat_as_not_current`] on this context.
    ///
    /// If you are not aware of what context you intend to make current next,
    /// consider waiting until you do. If you need this context not current
    /// immediately (e.g. to transfer it to another thread), then call
    /// [`make_not_current`] on this context.
    ///
    /// Please avoid calling [`make_not_current`] on one context only to call
    /// `make_current` on another context before and/or after. This hurts
    /// performance by requiring glutin to:
    ///
    ///  * Check if this context is current; then
    ///  * If it is, change the current context from this context to none; then
    ///  * Change the current context from none to the new context.
    ///
    /// Instead prefer the method we mentioned above with `make_current` and
    /// [`treat_as_not_current`].
    ///
    /// [`make_not_current`]: struct.ContextWrapper.html#method.make_not_current
    /// [`treat_as_not_current`]:
    /// struct.ContextWrapper.html#method.treat_as_not_current
    /// [`is_current`]: struct.ContextWrapper.html#method.is_current
    pub unsafe fn make_current(
        self,
    ) -> Result<ContextWrapper<PossiblyCurrent, W>, (Self, ContextError)> {
        let window = self.window;
        match self.context.make_current() {
            Ok(context) => Ok(ContextWrapper { window, context }),
            Err((context, err)) => {
                Err((ContextWrapper { window, context }, err))
            }
        }
    }

    /// If this context is current, makes this context not current. If this
    /// context is not current however, this function does nothing.
    ///
    /// Please see [`make_current`].
    ///
    /// [`make_current`]: struct.ContextWrapper.html#method.make_current
    pub unsafe fn make_not_current(
        self,
    ) -> Result<ContextWrapper<NotCurrent, W>, (Self, ContextError)> {
        let window = self.window;
        match self.context.make_not_current() {
            Ok(context) => Ok(ContextWrapper { window, context }),
            Err((context, err)) => {
                Err((ContextWrapper { window, context }, err))
            }
        }
    }

    /// Treats this context as not current, even if it is current. We do no
    /// checks to confirm that this is actually case.
    ///
    /// If unsure whether or not this context is current, please use
    /// [`make_not_current`] which will do nothing if this context is not
    /// current.
    ///
    /// Please see [`make_current`].
    ///
    /// [`make_not_current`]: struct.ContextWrapper.html#method.make_not_current
    /// [`make_current`]: struct.ContextWrapper.html#method.make_current
    pub unsafe fn treat_as_not_current(self) -> ContextWrapper<NotCurrent, W> {
        ContextWrapper {
            context: self.context.treat_as_not_current(),
            window: self.window,
        }
    }

    /// Treats this context as current, even if it is not current. We do no
    /// checks to confirm that this is actually case.
    ///
    /// This function should only be used if you intend to track context
    /// currency without the limited aid of glutin, and you wish to store
    /// all the [`Context`]s as [`NotCurrent`].
    ///
    /// Please see [`make_current`] for the prefered method of handling context
    /// currency.
    ///
    /// [`make_current`]: struct.ContextWrapper.html#method.make_current
    /// [`NotCurrent`]: enum.NotCurrent.html
    /// [`Context`]: struct.Context.html
    pub unsafe fn treat_as_current(self) -> ContextWrapper<PossiblyCurrent, W> {
        ContextWrapper {
            context: self.context.treat_as_current(),
            window: self.window,
        }
    }

    /// Returns true if this context is the current one in this thread.
    pub fn is_current(&self) -> bool {
        self.context.is_current()
    }

    /// Returns the OpenGL API being used.
    pub fn get_api(&self) -> Api {
        self.context.get_api()
    }
}

impl<W> ContextWrapper<PossiblyCurrent, W> {
    /// Returns the address of an OpenGL function.
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        self.context.get_proc_address(addr)
    }
}

impl<T: ContextCurrentState, W> std::ops::Deref for ContextWrapper<T, W> {
    type Target = Context<T>;
    fn deref(&self) -> &Self::Target {
        &self.context
    }
}

impl<'a, T: ContextCurrentState> ContextBuilder<'a, T> {
    /// Builds the given window along with the associated GL context, returning
    /// the pair as a [`WindowedContext<T>`].
    ///
    /// Errors can occur in two scenarios:
    ///  - If the window could not be created (via permission denied,
    ///  incompatible system, out of memory, etc.). This should be very rare.
    ///  - If the OpenGL [`Context`] could not be created. This generally
    ///    happens
    ///  because the underlying platform doesn't support a requested feature.
    ///
    /// [`WindowedContext<T>`]: type.WindowedContext.html
    /// [`Context`]: struct.Context.html
    pub fn build_windowed<TE>(
        self,
        wb: WindowBuilder,
        el: &EventLoop<TE>,
    ) -> Result<WindowedContext<NotCurrent>, CreationError> {
        let ContextBuilder { pf_reqs, gl_attr } = self;
        let gl_attr = gl_attr.map_sharing(|ctx| &ctx.context);
        platform_impl::Context::new_windowed(wb, el, &pf_reqs, &gl_attr).map(
            |(window, context)| WindowedContext {
                window,
                context: Context {
                    context,
                    phantom: PhantomData,
                },
            },
        )
    }
}
<|endoftext|>


<commit_before>//! Computing stack layout.

use ir::StackSlots;
use ir::stackslot::{StackSize, StackOffset, StackSlotKind};
use result::CtonError;
use std::cmp::{min, max};

/// Compute the stack frame layout.
///
/// Determine the total size of this stack frame and assign offsets to all `Spill` and `Local`
/// stack slots.
///
/// The total frame size will be a multiple of `alignment` which must be a power of two.
///
/// Returns the total stack frame size which is also saved in `frame.frame_size`.
///
/// If the stack frame is too big, returns an `ImplLimitExceeded` error.
pub fn layout_stack(frame: &mut StackSlots, alignment: StackSize) -> Result<StackSize, CtonError> {
    // Each object and the whole stack frame must fit in 2 GB such that any relative offset within
    // the frame fits in a `StackOffset`.
    let max_size = StackOffset::max_value() as StackSize;
    assert!(alignment.is_power_of_two() && alignment <= max_size);

    // We assume a stack that grows toward lower addresses as implemented by modern ISAs. The
    // stack layout from high to low addresses will be:
    //
    // 1. incoming arguments.
    // 2. spills + locals.
    // 3. outgoing arguments.
    //
    // The incoming arguments can have both positive and negative offsets. A negative offset
    // incoming arguments is usually the x86 return address pushed by the call instruction, but
    // it can also be fixed stack slots pushed by an externally generated prologue.
    //
    // Both incoming and outgoing argument slots have fixed offsets that are treated as
    // reserved zones by the layout algorithm.

    let mut incoming_min = 0;
    let mut outgoing_max = 0;
    let mut min_align = alignment;

    for ss in frame.keys() {
        let slot = &frame[ss];

        if slot.size > max_size {
            return Err(CtonError::ImplLimitExceeded);
        }

        match slot.kind {
            StackSlotKind::IncomingArg => {
                incoming_min = min(incoming_min, slot.offset);
            }
            StackSlotKind::OutgoingArg => {
                let offset = slot.offset
                    .checked_add(slot.size as StackOffset)
                    .ok_or(CtonError::ImplLimitExceeded)?;
                outgoing_max = max(outgoing_max, offset);
            }
            StackSlotKind::SpillSlot | StackSlotKind::Local => {
                // Determine the smallest alignment of any local or spill slot.
                min_align = slot.alignment(min_align);
            }
        }
    }

    // Lay out spill slots and locals below the incoming arguments.
    // The offset is negative, growing downwards.
    // Start with the smallest alignments for better packing.
    let mut offset = incoming_min;
    assert!(min_align.is_power_of_two());
    while min_align <= alignment {
        for ss in frame.keys() {
            let slot = frame[ss].clone();

            // Pick out locals and spill slots with exact alignment `min_align`.
            match slot.kind {
                StackSlotKind::SpillSlot | StackSlotKind::Local => {
                    if slot.alignment(alignment) != min_align {
                        continue;
                    }
                }
                _ => continue,
            }

            offset = offset
                .checked_sub(slot.size as StackOffset)
                .ok_or(CtonError::ImplLimitExceeded)?;

            // Aligning the negative offset can never cause overflow. We're only clearing bits.
            offset &= -(min_align as StackOffset);
            frame.set_offset(ss, offset);
        }

        // Move on to the next higher alignment.
        min_align *= 2;
    }

    // Finally, make room for the outgoing arguments.
    offset = offset
        .checked_sub(outgoing_max)
        .ok_or(CtonError::ImplLimitExceeded)?;
    offset &= -(alignment as StackOffset);

    let frame_size = (offset as StackSize).wrapping_neg();
    frame.frame_size = Some(frame_size);
    Ok(frame_size)
}

#[cfg(test)]
mod tests {
    use ir::StackSlots;
    use ir::types;
    use super::layout_stack;

    #[test]
    fn layout() {
        let sss = &mut StackSlots::new();

        // An empty layout should have 0-sized stack frame.
        assert_eq!(layout_stack(sss, 1), Ok(0));
        assert_eq!(layout_stack(sss, 16), Ok(0));

        // Same for incoming arguments with non-negative offsets.
        let in0 = sss.make_incoming_arg(types::I64, 0);
        let in1 = sss.make_incoming_arg(types::I64, 8);

        assert_eq!(layout_stack(sss, 1), Ok(0));
        assert_eq!(layout_stack(sss, 16), Ok(0));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);

        // Add some spill slots.
        let ss0 = sss.make_spill_slot(types::I64);
        let ss1 = sss.make_spill_slot(types::I32);

        assert_eq!(layout_stack(sss, 1), Ok(12));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[ss0].offset, -8);
        assert_eq!(sss[ss1].offset, -12);

        assert_eq!(layout_stack(sss, 16), Ok(16));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[ss0].offset, -16);
        assert_eq!(sss[ss1].offset, -4);

        // An incoming argument with negative offset counts towards the total frame size, but it
        // should still pack nicely with the spill slots.
        let in2 = sss.make_incoming_arg(types::I32, -4);

        assert_eq!(layout_stack(sss, 1), Ok(16));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[in2].offset, -4);
        assert_eq!(sss[ss0].offset, -12);
        assert_eq!(sss[ss1].offset, -16);

        assert_eq!(layout_stack(sss, 16), Ok(16));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[in2].offset, -4);
        assert_eq!(sss[ss0].offset, -16);
        assert_eq!(sss[ss1].offset, -8);

        // Finally, make sure there is room for the outgoing args.
        let out0 = sss.get_outgoing_arg(types::I32, 0);

        assert_eq!(layout_stack(sss, 1), Ok(20));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[in2].offset, -4);
        assert_eq!(sss[ss0].offset, -12);
        assert_eq!(sss[ss1].offset, -16);
        assert_eq!(sss[out0].offset, 0);

        assert_eq!(layout_stack(sss, 16), Ok(32));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[in2].offset, -4);
        assert_eq!(sss[ss0].offset, -16);
        assert_eq!(sss[ss1].offset, -8);
        assert_eq!(sss[out0].offset, 0);
    }
}
<commit_msg>Test that stack layout with an unsupported offset is rejected cleanly.<commit_after>//! Computing stack layout.

use ir::StackSlots;
use ir::stackslot::{StackSize, StackOffset, StackSlotKind};
use result::CtonError;
use std::cmp::{min, max};

/// Compute the stack frame layout.
///
/// Determine the total size of this stack frame and assign offsets to all `Spill` and `Local`
/// stack slots.
///
/// The total frame size will be a multiple of `alignment` which must be a power of two.
///
/// Returns the total stack frame size which is also saved in `frame.frame_size`.
///
/// If the stack frame is too big, returns an `ImplLimitExceeded` error.
pub fn layout_stack(frame: &mut StackSlots, alignment: StackSize) -> Result<StackSize, CtonError> {
    // Each object and the whole stack frame must fit in 2 GB such that any relative offset within
    // the frame fits in a `StackOffset`.
    let max_size = StackOffset::max_value() as StackSize;
    assert!(alignment.is_power_of_two() && alignment <= max_size);

    // We assume a stack that grows toward lower addresses as implemented by modern ISAs. The
    // stack layout from high to low addresses will be:
    //
    // 1. incoming arguments.
    // 2. spills + locals.
    // 3. outgoing arguments.
    //
    // The incoming arguments can have both positive and negative offsets. A negative offset
    // incoming arguments is usually the x86 return address pushed by the call instruction, but
    // it can also be fixed stack slots pushed by an externally generated prologue.
    //
    // Both incoming and outgoing argument slots have fixed offsets that are treated as
    // reserved zones by the layout algorithm.

    let mut incoming_min = 0;
    let mut outgoing_max = 0;
    let mut min_align = alignment;

    for ss in frame.keys() {
        let slot = &frame[ss];

        if slot.size > max_size {
            return Err(CtonError::ImplLimitExceeded);
        }

        match slot.kind {
            StackSlotKind::IncomingArg => {
                incoming_min = min(incoming_min, slot.offset);
            }
            StackSlotKind::OutgoingArg => {
                let offset = slot.offset
                    .checked_add(slot.size as StackOffset)
                    .ok_or(CtonError::ImplLimitExceeded)?;
                outgoing_max = max(outgoing_max, offset);
            }
            StackSlotKind::SpillSlot | StackSlotKind::Local => {
                // Determine the smallest alignment of any local or spill slot.
                min_align = slot.alignment(min_align);
            }
        }
    }

    // Lay out spill slots and locals below the incoming arguments.
    // The offset is negative, growing downwards.
    // Start with the smallest alignments for better packing.
    let mut offset = incoming_min;
    assert!(min_align.is_power_of_two());
    while min_align <= alignment {
        for ss in frame.keys() {
            let slot = frame[ss].clone();

            // Pick out locals and spill slots with exact alignment `min_align`.
            match slot.kind {
                StackSlotKind::SpillSlot | StackSlotKind::Local => {
                    if slot.alignment(alignment) != min_align {
                        continue;
                    }
                }
                _ => continue,
            }

            offset = offset
                .checked_sub(slot.size as StackOffset)
                .ok_or(CtonError::ImplLimitExceeded)?;

            // Aligning the negative offset can never cause overflow. We're only clearing bits.
            offset &= -(min_align as StackOffset);
            frame.set_offset(ss, offset);
        }

        // Move on to the next higher alignment.
        min_align *= 2;
    }

    // Finally, make room for the outgoing arguments.
    offset = offset
        .checked_sub(outgoing_max)
        .ok_or(CtonError::ImplLimitExceeded)?;
    offset &= -(alignment as StackOffset);

    let frame_size = (offset as StackSize).wrapping_neg();
    frame.frame_size = Some(frame_size);
    Ok(frame_size)
}

#[cfg(test)]
mod tests {
    use ir::StackSlots;
    use ir::types;
    use super::layout_stack;
    use ir::stackslot::StackOffset;
    use result::CtonError;

    #[test]
    fn layout() {
        let sss = &mut StackSlots::new();

        // An empty layout should have 0-sized stack frame.
        assert_eq!(layout_stack(sss, 1), Ok(0));
        assert_eq!(layout_stack(sss, 16), Ok(0));

        // Same for incoming arguments with non-negative offsets.
        let in0 = sss.make_incoming_arg(types::I64, 0);
        let in1 = sss.make_incoming_arg(types::I64, 8);

        assert_eq!(layout_stack(sss, 1), Ok(0));
        assert_eq!(layout_stack(sss, 16), Ok(0));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);

        // Add some spill slots.
        let ss0 = sss.make_spill_slot(types::I64);
        let ss1 = sss.make_spill_slot(types::I32);

        assert_eq!(layout_stack(sss, 1), Ok(12));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[ss0].offset, -8);
        assert_eq!(sss[ss1].offset, -12);

        assert_eq!(layout_stack(sss, 16), Ok(16));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[ss0].offset, -16);
        assert_eq!(sss[ss1].offset, -4);

        // An incoming argument with negative offset counts towards the total frame size, but it
        // should still pack nicely with the spill slots.
        let in2 = sss.make_incoming_arg(types::I32, -4);

        assert_eq!(layout_stack(sss, 1), Ok(16));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[in2].offset, -4);
        assert_eq!(sss[ss0].offset, -12);
        assert_eq!(sss[ss1].offset, -16);

        assert_eq!(layout_stack(sss, 16), Ok(16));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[in2].offset, -4);
        assert_eq!(sss[ss0].offset, -16);
        assert_eq!(sss[ss1].offset, -8);

        // Finally, make sure there is room for the outgoing args.
        let out0 = sss.get_outgoing_arg(types::I32, 0);

        assert_eq!(layout_stack(sss, 1), Ok(20));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[in2].offset, -4);
        assert_eq!(sss[ss0].offset, -12);
        assert_eq!(sss[ss1].offset, -16);
        assert_eq!(sss[out0].offset, 0);

        assert_eq!(layout_stack(sss, 16), Ok(32));
        assert_eq!(sss[in0].offset, 0);
        assert_eq!(sss[in1].offset, 8);
        assert_eq!(sss[in2].offset, -4);
        assert_eq!(sss[ss0].offset, -16);
        assert_eq!(sss[ss1].offset, -8);
        assert_eq!(sss[out0].offset, 0);

        // Also test that an unsupported offset is rejected.
        sss.get_outgoing_arg(types::I8, StackOffset::max_value() - 1);
        assert_eq!(layout_stack(sss, 1), Err(CtonError::ImplLimitExceeded));
    }
}
<|endoftext|>