<commit_before>//! This is a binary running in the server environment
//!
//! You have to provide all needed configuration attributes via command line parameters,
//! or you could specify a configuration file. The format of configuration file is defined
//! in mod `config`.
//!
//! *It should be notice that the extended configuration file is not suitable for the server
//! side.*

use std::{net::IpAddr, path::PathBuf, process, time::Duration};

use clap::{clap_app, Arg};
use futures::future::{self, Either};
use log::info;
use tokio::{self, runtime::Builder};

use shadowsocks_service::{
    acl::AccessControl,
    config::{Config, ConfigType, ManagerConfig, ManagerServerHost},
    run_manager,
    shadowsocks::{
        config::{ManagerAddr, Mode},
        crypto::v1::{available_ciphers, CipherKind},
        plugin::PluginConfig,
    },
};

#[cfg(feature = "logging")]
use self::common::logging;
use self::common::{monitor, validator};

mod common;

/// shadowsocks version
const VERSION: &str = env!("CARGO_PKG_VERSION");

fn main() {
    let (config, runtime) = {
        #[allow(unused_mut)]
        let mut app = clap_app!(shadowsocks =>
            (version: VERSION)
            (about: "A fast tunnel proxy that helps you bypass firewalls.")

            (@arg UDP_ONLY: -u conflicts_with[TCP_AND_UDP] "Server mode UDP_ONLY")
            (@arg TCP_AND_UDP: -U conflicts_with[UDP_ONLY] "Server mode TCP_AND_UDP")

            (@arg CONFIG: -c --config +takes_value
                "Shadowsocks configuration file (https://shadowsocks.org/en/config/quick-guide.html), \
                    the only required fields are \"manager_address\" and \"manager_port\". \
                    Servers defined will be created when process is started.")

            (@arg OUTBOUND_BIND_ADDR: -b --("outbound-bind-addr") +takes_value alias("bind-addr") {validator::validate_ip_addr} "Bind address, outbound socket will bind this address")
            (@arg OUTBOUND_BIND_INTERFACE: --("outbound-bind-interface") +takes_value "Set SO_BINDTODEVICE / IP_BOUND_IF / IP_UNICAST_IF option for outbound socket")
            (@arg SERVER_HOST: -s --("server-host") +takes_value "Host name or IP address of your remote server")

            (@arg MANAGER_ADDR: --("manager-addr") +takes_value alias("manager-address") {validator::validate_manager_addr} "ShadowSocks Manager (ssmgr) address, could be ip:port, domain:port or /path/to/unix.sock")
            (@arg ENCRYPT_METHOD: -m --("encrypt-method") +takes_value possible_values(available_ciphers()) "Default encryption method")
            (@arg TIMEOUT: --timeout +takes_value {validator::validate_u64} "Default timeout seconds for TCP relay")

            (@arg PLUGIN: --plugin +takes_value requires[SERVER_ADDR] "Default SIP003 (https://shadowsocks.org/en/spec/Plugin.html) plugin")
            (@arg PLUGIN_OPT: --("plugin-opts") +takes_value requires[PLUGIN] "Default SIP003 plugin options")

            (@arg ACL: --acl +takes_value "Path to ACL (Access Control List)")
            (@arg DNS: --dns +takes_value "DNS nameservers, formatted like [(tcp|udp)://]host[:port][,host[:port]]..., or unix:///path/to/dns, or predefined keys like \"google\", \"cloudflare\"")

            (@arg TCP_NO_DELAY: --("tcp-no-delay") !takes_value alias("no-delay") "Set TCP_NODELAY option for socket")
            (@arg TCP_FAST_OPEN: --("tcp-fast-open") !takes_value alias("fast-open") "Enable TCP Fast Open (TFO)")
            (@arg TCP_KEEP_ALIVE: --("tcp-keep-alive") +takes_value {validator::validate_u64} "Set TCP keep alive timeout seconds")

            (@arg UDP_TIMEOUT: --("udp-timeout") +takes_value {validator::validate_u64} "Timeout seconds for UDP relay")
            (@arg UDP_MAX_ASSOCIATIONS: --("udp-max-associations") +takes_value {validator::validate_u64} "Maximum associations to be kept simultaneously for UDP relay")

            (@arg INBOUND_SEND_BUFFER_SIZE: --("inbound-send-buffer-size") +takes_value {validator::validate_u32} "Set inbound sockets' SO_SNDBUF option")
            (@arg INBOUND_RECV_BUFFER_SIZE: --("inbound-recv-buffer-size") +takes_value {validator::validate_u32} "Set inbound sockets' SO_RCVBUF option")
            (@arg OUTBOUND_SEND_BUFFER_SIZE: --("outbound-send-buffer-size") +takes_value {validator::validate_u32} "Set outbound sockets' SO_SNDBUF option")
            (@arg OUTBOUND_RECV_BUFFER_SIZE: --("outbound-recv-buffer-size") +takes_value {validator::validate_u32} "Set outbound sockets' SO_RCVBUF option")
        );

        #[cfg(feature = "logging")]
        {
            app = clap_app!(@app (app)
                (@arg VERBOSE: -v ... "Set log level")
                (@arg LOG_WITHOUT_TIME: --("log-without-time") "Log without datetime prefix")
                (@arg LOG_CONFIG: --("log-config") +takes_value "log4rs configuration file")
            );
        }

        #[cfg(unix)]
        {
            app = clap_app!(@app (app)
                (@arg DAEMONIZE: -d --("daemonize") "Daemonize")
                (@arg DAEMONIZE_PID_PATH: --("daemonize-pid") +takes_value "File path to store daemonized process's PID")

                (@arg MANAGER_SERVER_MODE: --("manager-server-mode") +takes_value possible_values(&["builtin", "standalone"]) "Servers that running in builtin or standalone mode")
                (@arg MANAGER_SERVER_WORKING_DIRECTORY: --("manager-server-working-directory") +takes_value "Folder for putting servers' configuration and pid files, default is current directory")
            );
        }

        #[cfg(all(unix, not(target_os = "android")))]
        {
            app = clap_app!(@app (app)
                (@arg NOFILE: -n --nofile +takes_value "Set RLIMIT_NOFILE with both soft and hard limit")
            );
        }

        #[cfg(any(target_os = "linux", target_os = "android"))]
        {
            app = clap_app!(@app (app)
                (@arg OUTBOUND_FWMARK: --("outbound-fwmark") +takes_value {validator::validate_u32} "Set SO_MARK option for outbound socket")
            );
        }

        #[cfg(feature = "multi-threaded")]
        {
            app = clap_app!(@app (app)
                (@arg SINGLE_THREADED: --("single-threaded") "Run the program all in one thread")
                (@arg WORKER_THREADS: --("worker-threads") +takes_value {validator::validate_usize} "Sets the number of worker threads the `Runtime` will use")
            );
        }

        let matches = app
            .arg(
                Arg::with_name("IPV6_FIRST")
                    .short("6")
                    .help("Resolve hostname to IPv6 address first"),
            )
            .get_matches();

        #[cfg(feature = "logging")]
        match matches.value_of("LOG_CONFIG") {
            Some(path) => {
                logging::init_with_file(path);
            }
            None => {
                logging::init_with_config("ssmanager", &matches);
            }
        }

        let config_path_opt = matches.value_of("CONFIG").map(|c| PathBuf::from(c)).or_else(|| {
            if !matches.is_present("MANAGER_ADDR") {
                common::config::get_default_config_path()
            } else {
                None
            }
        });

        let mut config = match config_path_opt {
            Some(cpath) => match Config::load_from_file(&cpath, ConfigType::Manager) {
                Ok(cfg) => cfg,
                Err(err) => {
                    eprintln!("loading config \"{}\", {}", cpath.display(), err);
                    process::exit(common::EXIT_CODE_LOAD_CONFIG_FAILURE);
                }
            },
            None => Config::new(ConfigType::Manager),
        };

        if let Some(bind_addr) = matches.value_of("OUTBOUND_BIND_ADDR") {
            let bind_addr = bind_addr.parse::<IpAddr>().expect("outbound-bind-addr");
            config.outbound_bind_addr = Some(bind_addr);
        }

        if matches.is_present("TCP_NO_DELAY") {
            config.no_delay = true;
        }

        if matches.is_present("TCP_FAST_OPEN") {
            config.fast_open = true;
        }

        if let Some(keep_alive) = matches.value_of("TCP_KEEP_ALIVE") {
            config.keep_alive = Some(Duration::from_secs(
                keep_alive
                    .parse::<u64>()
                    .expect("`tcp-keep-alive` is expecting an integer"),
            ));
        }

        #[cfg(any(target_os = "linux", target_os = "android"))]
        if let Some(mark) = matches.value_of("OUTBOUND_FWMARK") {
            config.outbound_fwmark = Some(mark.parse::<u32>().expect("an unsigned integer for `outbound-fwmark`"));
        }

        if let Some(iface) = matches.value_of("OUTBOUND_BIND_INTERFACE") {
            config.outbound_bind_interface = Some(iface.to_owned());
        }

        if let Some(m) = matches.value_of("MANAGER_ADDR") {
            if let Some(ref mut manager_config) = config.manager {
                manager_config.addr = m.parse::<ManagerAddr>().expect("manager-address");
            } else {
                config.manager = Some(ManagerConfig::new(m.parse::<ManagerAddr>().expect("manager-address")));
            }
        }

        if let Some(ref mut manager_config) = config.manager {
            if let Some(m) = matches.value_of("ENCRYPT_METHOD") {
                manager_config.method = Some(m.parse::<CipherKind>().expect("encrypt-method"));
            }

            if let Some(t) = matches.value_of("TIMEOUT") {
                manager_config.timeout = Some(Duration::from_secs(t.parse::<u64>().expect("timeout")));
            }

            if let Some(sh) = matches.value_of("SERVER_HOST") {
                manager_config.server_host = sh.parse::<ManagerServerHost>().unwrap();
            }

            if let Some(p) = matches.value_of("PLUGIN") {
                manager_config.plugin = Some(PluginConfig {
                    plugin: p.to_owned(),
                    plugin_opts: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned),
                    plugin_args: Vec::new(),
                });
            }

            #[cfg(unix)]
            if let Some(server_mode) = matches.value_of("MANAGER_SERVER_MODE") {
                manager_config.server_mode = server_mode.parse().expect("manager-server-mode");
            }

            #[cfg(unix)]
            if let Some(server_working_directory) = matches.value_of("MANAGER_SERVER_WORKING_DIRECTORY") {
                manager_config.server_working_directory = server_working_directory
                    .parse()
                    .expect("manager-server-working-directory");
            }
        }

        // Overrides
        if matches.is_present("UDP_ONLY") {
            if let Some(ref mut m) = config.manager {
                m.mode = Mode::UdpOnly;
            }
        }

        if matches.is_present("TCP_AND_UDP") {
            if let Some(ref mut m) = config.manager {
                m.mode = Mode::TcpAndUdp;
            }
        }

        #[cfg(all(unix, not(target_os = "android")))]
        if let Some(nofile) = matches.value_of("NOFILE") {
            config.nofile = Some(nofile.parse::<u64>().expect("an unsigned integer for `nofile`"));
        }

        if let Some(acl_file) = matches.value_of("ACL") {
            let acl = match AccessControl::load_from_file(acl_file) {
                Ok(acl) => acl,
                Err(err) => {
                    eprintln!("loading ACL \"{}\", {}", acl_file, err);
                    process::exit(common::EXIT_CODE_LOAD_ACL_FAILURE);
                }
            };
            config.acl = Some(acl);
        }

        if let Some(dns) = matches.value_of("DNS") {
            config.set_dns_formatted(dns).expect("dns");
        }

        if matches.is_present("IPV6_FIRST") {
            config.ipv6_first = true;
        }

        if let Some(udp_timeout) = matches.value_of("UDP_TIMEOUT") {
            config.udp_timeout = Some(Duration::from_secs(udp_timeout.parse::<u64>().expect("udp-timeout")));
        }

        if let Some(udp_max_assoc) = matches.value_of("UDP_MAX_ASSOCIATIONS") {
            config.udp_max_associations = Some(udp_max_assoc.parse::<usize>().expect("udp-max-associations"));
        }

        if let Some(bs) = matches.value_of("INBOUND_SEND_BUFFER_SIZE") {
            config.inbound_send_buffer_size = Some(bs.parse::<u32>().expect("inbound-send-buffer-size"));
        }
        if let Some(bs) = matches.value_of("INBOUND_RECV_BUFFER_SIZE") {
            config.inbound_recv_buffer_size = Some(bs.parse::<u32>().expect("inbound-recv-buffer-size"));
        }
        if let Some(bs) = matches.value_of("OUTBOUND_SEND_BUFFER_SIZE") {
            config.outbound_send_buffer_size = Some(bs.parse::<u32>().expect("outbound-send-buffer-size"));
        }
        if let Some(bs) = matches.value_of("OUTBOUND_RECV_BUFFER_SIZE") {
            config.outbound_recv_buffer_size = Some(bs.parse::<u32>().expect("outbound-recv-buffer-size"));
        }

        // DONE reading options

        if config.manager.is_none() {
            eprintln!(
                "missing `manager_address`, consider specifying it by --manager-address command line option, \
             or \"manager_address\" and \"manager_port\" keys in configuration file"
            );
            println!("{}", matches.usage());
            return;
        }

        if let Err(err) = config.check_integrity() {
            eprintln!("config integrity check failed, {}", err);
            println!("{}", matches.usage());
            return;
        }

        #[cfg(unix)]
        if matches.is_present("DAEMONIZE") || matches.is_present("DAEMONIZE_PID_PATH") {
            use self::common::daemonize;
            daemonize::daemonize(matches.value_of("DAEMONIZE_PID_PATH"));
        }

        info!("shadowsocks manager {} build {}", VERSION, common::BUILD_TIME);

        #[cfg(feature = "multi-threaded")]
        let mut builder = if matches.is_present("SINGLE_THREADED") {
            Builder::new_current_thread()
        } else {
            let mut builder = Builder::new_multi_thread();
            if let Some(worker_threads) = matches.value_of("WORKER_THREADS") {
                builder.worker_threads(worker_threads.parse::<usize>().expect("worker-threads"));
            }
            builder
        };
        #[cfg(not(feature = "multi-threaded"))]
        let mut builder = Builder::new_current_thread();

        let runtime = builder.enable_all().build().expect("create tokio Runtime");

        (config, runtime)
    };

    runtime.block_on(async move {
        let abort_signal = monitor::create_signal_monitor();
        let server = run_manager(config);

        tokio::pin!(abort_signal);
        tokio::pin!(server);

        match future::select(server, abort_signal).await {
            // Server future resolved without an error. This should never happen.
            Either::Left((Ok(..), ..)) => {
                eprintln!("server exited unexpectedly");
                process::exit(common::EXIT_CODE_SERVER_EXIT_UNEXPECTEDLY);
            }
            // Server future resolved with error, which are listener errors in most cases
            Either::Left((Err(err), ..)) => {
                eprintln!("server aborted with {}", err);
                process::exit(common::EXIT_CODE_SERVER_ABORTED);
            }
            // The abort signal future resolved. Means we should just exit.
            Either::Right(_) => (),
        }
    });
}
<commit_msg>ssmanager won't use read_server_password<commit_after>//! This is a binary running in the server environment
//!
//! You have to provide all needed configuration attributes via command line parameters,
//! or you could specify a configuration file. The format of configuration file is defined
//! in mod `config`.
//!
//! *It should be notice that the extended configuration file is not suitable for the server
//! side.*

use std::{net::IpAddr, path::PathBuf, process, time::Duration};

use clap::{clap_app, Arg};
use futures::future::{self, Either};
use log::info;
use tokio::{self, runtime::Builder};

use shadowsocks_service::{
    acl::AccessControl,
    config::{Config, ConfigType, ManagerConfig, ManagerServerHost},
    run_manager,
    shadowsocks::{
        config::{ManagerAddr, Mode},
        crypto::v1::{available_ciphers, CipherKind},
        plugin::PluginConfig,
    },
};

#[cfg(feature = "logging")]
use self::common::logging;
use self::common::{monitor, validator};

#[allow(dead_code)]
mod common;

/// shadowsocks version
const VERSION: &str = env!("CARGO_PKG_VERSION");

fn main() {
    let (config, runtime) = {
        #[allow(unused_mut)]
        let mut app = clap_app!(shadowsocks =>
            (version: VERSION)
            (about: "A fast tunnel proxy that helps you bypass firewalls.")

            (@arg UDP_ONLY: -u conflicts_with[TCP_AND_UDP] "Server mode UDP_ONLY")
            (@arg TCP_AND_UDP: -U conflicts_with[UDP_ONLY] "Server mode TCP_AND_UDP")

            (@arg CONFIG: -c --config +takes_value
                "Shadowsocks configuration file (https://shadowsocks.org/en/config/quick-guide.html), \
                    the only required fields are \"manager_address\" and \"manager_port\". \
                    Servers defined will be created when process is started.")

            (@arg OUTBOUND_BIND_ADDR: -b --("outbound-bind-addr") +takes_value alias("bind-addr") {validator::validate_ip_addr} "Bind address, outbound socket will bind this address")
            (@arg OUTBOUND_BIND_INTERFACE: --("outbound-bind-interface") +takes_value "Set SO_BINDTODEVICE / IP_BOUND_IF / IP_UNICAST_IF option for outbound socket")
            (@arg SERVER_HOST: -s --("server-host") +takes_value "Host name or IP address of your remote server")

            (@arg MANAGER_ADDR: --("manager-addr") +takes_value alias("manager-address") {validator::validate_manager_addr} "ShadowSocks Manager (ssmgr) address, could be ip:port, domain:port or /path/to/unix.sock")
            (@arg ENCRYPT_METHOD: -m --("encrypt-method") +takes_value possible_values(available_ciphers()) "Default encryption method")
            (@arg TIMEOUT: --timeout +takes_value {validator::validate_u64} "Default timeout seconds for TCP relay")

            (@arg PLUGIN: --plugin +takes_value requires[SERVER_ADDR] "Default SIP003 (https://shadowsocks.org/en/spec/Plugin.html) plugin")
            (@arg PLUGIN_OPT: --("plugin-opts") +takes_value requires[PLUGIN] "Default SIP003 plugin options")

            (@arg ACL: --acl +takes_value "Path to ACL (Access Control List)")
            (@arg DNS: --dns +takes_value "DNS nameservers, formatted like [(tcp|udp)://]host[:port][,host[:port]]..., or unix:///path/to/dns, or predefined keys like \"google\", \"cloudflare\"")

            (@arg TCP_NO_DELAY: --("tcp-no-delay") !takes_value alias("no-delay") "Set TCP_NODELAY option for socket")
            (@arg TCP_FAST_OPEN: --("tcp-fast-open") !takes_value alias("fast-open") "Enable TCP Fast Open (TFO)")
            (@arg TCP_KEEP_ALIVE: --("tcp-keep-alive") +takes_value {validator::validate_u64} "Set TCP keep alive timeout seconds")

            (@arg UDP_TIMEOUT: --("udp-timeout") +takes_value {validator::validate_u64} "Timeout seconds for UDP relay")
            (@arg UDP_MAX_ASSOCIATIONS: --("udp-max-associations") +takes_value {validator::validate_u64} "Maximum associations to be kept simultaneously for UDP relay")

            (@arg INBOUND_SEND_BUFFER_SIZE: --("inbound-send-buffer-size") +takes_value {validator::validate_u32} "Set inbound sockets' SO_SNDBUF option")
            (@arg INBOUND_RECV_BUFFER_SIZE: --("inbound-recv-buffer-size") +takes_value {validator::validate_u32} "Set inbound sockets' SO_RCVBUF option")
            (@arg OUTBOUND_SEND_BUFFER_SIZE: --("outbound-send-buffer-size") +takes_value {validator::validate_u32} "Set outbound sockets' SO_SNDBUF option")
            (@arg OUTBOUND_RECV_BUFFER_SIZE: --("outbound-recv-buffer-size") +takes_value {validator::validate_u32} "Set outbound sockets' SO_RCVBUF option")
        );

        #[cfg(feature = "logging")]
        {
            app = clap_app!(@app (app)
                (@arg VERBOSE: -v ... "Set log level")
                (@arg LOG_WITHOUT_TIME: --("log-without-time") "Log without datetime prefix")
                (@arg LOG_CONFIG: --("log-config") +takes_value "log4rs configuration file")
            );
        }

        #[cfg(unix)]
        {
            app = clap_app!(@app (app)
                (@arg DAEMONIZE: -d --("daemonize") "Daemonize")
                (@arg DAEMONIZE_PID_PATH: --("daemonize-pid") +takes_value "File path to store daemonized process's PID")

                (@arg MANAGER_SERVER_MODE: --("manager-server-mode") +takes_value possible_values(&["builtin", "standalone"]) "Servers that running in builtin or standalone mode")
                (@arg MANAGER_SERVER_WORKING_DIRECTORY: --("manager-server-working-directory") +takes_value "Folder for putting servers' configuration and pid files, default is current directory")
            );
        }

        #[cfg(all(unix, not(target_os = "android")))]
        {
            app = clap_app!(@app (app)
                (@arg NOFILE: -n --nofile +takes_value "Set RLIMIT_NOFILE with both soft and hard limit")
            );
        }

        #[cfg(any(target_os = "linux", target_os = "android"))]
        {
            app = clap_app!(@app (app)
                (@arg OUTBOUND_FWMARK: --("outbound-fwmark") +takes_value {validator::validate_u32} "Set SO_MARK option for outbound socket")
            );
        }

        #[cfg(feature = "multi-threaded")]
        {
            app = clap_app!(@app (app)
                (@arg SINGLE_THREADED: --("single-threaded") "Run the program all in one thread")
                (@arg WORKER_THREADS: --("worker-threads") +takes_value {validator::validate_usize} "Sets the number of worker threads the `Runtime` will use")
            );
        }

        let matches = app
            .arg(
                Arg::with_name("IPV6_FIRST")
                    .short("6")
                    .help("Resolve hostname to IPv6 address first"),
            )
            .get_matches();

        #[cfg(feature = "logging")]
        match matches.value_of("LOG_CONFIG") {
            Some(path) => {
                logging::init_with_file(path);
            }
            None => {
                logging::init_with_config("ssmanager", &matches);
            }
        }

        let config_path_opt = matches.value_of("CONFIG").map(|c| PathBuf::from(c)).or_else(|| {
            if !matches.is_present("MANAGER_ADDR") {
                common::config::get_default_config_path()
            } else {
                None
            }
        });

        let mut config = match config_path_opt {
            Some(cpath) => match Config::load_from_file(&cpath, ConfigType::Manager) {
                Ok(cfg) => cfg,
                Err(err) => {
                    eprintln!("loading config \"{}\", {}", cpath.display(), err);
                    process::exit(common::EXIT_CODE_LOAD_CONFIG_FAILURE);
                }
            },
            None => Config::new(ConfigType::Manager),
        };

        if let Some(bind_addr) = matches.value_of("OUTBOUND_BIND_ADDR") {
            let bind_addr = bind_addr.parse::<IpAddr>().expect("outbound-bind-addr");
            config.outbound_bind_addr = Some(bind_addr);
        }

        if matches.is_present("TCP_NO_DELAY") {
            config.no_delay = true;
        }

        if matches.is_present("TCP_FAST_OPEN") {
            config.fast_open = true;
        }

        if let Some(keep_alive) = matches.value_of("TCP_KEEP_ALIVE") {
            config.keep_alive = Some(Duration::from_secs(
                keep_alive
                    .parse::<u64>()
                    .expect("`tcp-keep-alive` is expecting an integer"),
            ));
        }

        #[cfg(any(target_os = "linux", target_os = "android"))]
        if let Some(mark) = matches.value_of("OUTBOUND_FWMARK") {
            config.outbound_fwmark = Some(mark.parse::<u32>().expect("an unsigned integer for `outbound-fwmark`"));
        }

        if let Some(iface) = matches.value_of("OUTBOUND_BIND_INTERFACE") {
            config.outbound_bind_interface = Some(iface.to_owned());
        }

        if let Some(m) = matches.value_of("MANAGER_ADDR") {
            if let Some(ref mut manager_config) = config.manager {
                manager_config.addr = m.parse::<ManagerAddr>().expect("manager-address");
            } else {
                config.manager = Some(ManagerConfig::new(m.parse::<ManagerAddr>().expect("manager-address")));
            }
        }

        if let Some(ref mut manager_config) = config.manager {
            if let Some(m) = matches.value_of("ENCRYPT_METHOD") {
                manager_config.method = Some(m.parse::<CipherKind>().expect("encrypt-method"));
            }

            if let Some(t) = matches.value_of("TIMEOUT") {
                manager_config.timeout = Some(Duration::from_secs(t.parse::<u64>().expect("timeout")));
            }

            if let Some(sh) = matches.value_of("SERVER_HOST") {
                manager_config.server_host = sh.parse::<ManagerServerHost>().unwrap();
            }

            if let Some(p) = matches.value_of("PLUGIN") {
                manager_config.plugin = Some(PluginConfig {
                    plugin: p.to_owned(),
                    plugin_opts: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned),
                    plugin_args: Vec::new(),
                });
            }

            #[cfg(unix)]
            if let Some(server_mode) = matches.value_of("MANAGER_SERVER_MODE") {
                manager_config.server_mode = server_mode.parse().expect("manager-server-mode");
            }

            #[cfg(unix)]
            if let Some(server_working_directory) = matches.value_of("MANAGER_SERVER_WORKING_DIRECTORY") {
                manager_config.server_working_directory = server_working_directory
                    .parse()
                    .expect("manager-server-working-directory");
            }
        }

        // Overrides
        if matches.is_present("UDP_ONLY") {
            if let Some(ref mut m) = config.manager {
                m.mode = Mode::UdpOnly;
            }
        }

        if matches.is_present("TCP_AND_UDP") {
            if let Some(ref mut m) = config.manager {
                m.mode = Mode::TcpAndUdp;
            }
        }

        #[cfg(all(unix, not(target_os = "android")))]
        if let Some(nofile) = matches.value_of("NOFILE") {
            config.nofile = Some(nofile.parse::<u64>().expect("an unsigned integer for `nofile`"));
        }

        if let Some(acl_file) = matches.value_of("ACL") {
            let acl = match AccessControl::load_from_file(acl_file) {
                Ok(acl) => acl,
                Err(err) => {
                    eprintln!("loading ACL \"{}\", {}", acl_file, err);
                    process::exit(common::EXIT_CODE_LOAD_ACL_FAILURE);
                }
            };
            config.acl = Some(acl);
        }

        if let Some(dns) = matches.value_of("DNS") {
            config.set_dns_formatted(dns).expect("dns");
        }

        if matches.is_present("IPV6_FIRST") {
            config.ipv6_first = true;
        }

        if let Some(udp_timeout) = matches.value_of("UDP_TIMEOUT") {
            config.udp_timeout = Some(Duration::from_secs(udp_timeout.parse::<u64>().expect("udp-timeout")));
        }

        if let Some(udp_max_assoc) = matches.value_of("UDP_MAX_ASSOCIATIONS") {
            config.udp_max_associations = Some(udp_max_assoc.parse::<usize>().expect("udp-max-associations"));
        }

        if let Some(bs) = matches.value_of("INBOUND_SEND_BUFFER_SIZE") {
            config.inbound_send_buffer_size = Some(bs.parse::<u32>().expect("inbound-send-buffer-size"));
        }
        if let Some(bs) = matches.value_of("INBOUND_RECV_BUFFER_SIZE") {
            config.inbound_recv_buffer_size = Some(bs.parse::<u32>().expect("inbound-recv-buffer-size"));
        }
        if let Some(bs) = matches.value_of("OUTBOUND_SEND_BUFFER_SIZE") {
            config.outbound_send_buffer_size = Some(bs.parse::<u32>().expect("outbound-send-buffer-size"));
        }
        if let Some(bs) = matches.value_of("OUTBOUND_RECV_BUFFER_SIZE") {
            config.outbound_recv_buffer_size = Some(bs.parse::<u32>().expect("outbound-recv-buffer-size"));
        }

        // DONE reading options

        if config.manager.is_none() {
            eprintln!(
                "missing `manager_address`, consider specifying it by --manager-address command line option, \
             or \"manager_address\" and \"manager_port\" keys in configuration file"
            );
            println!("{}", matches.usage());
            return;
        }

        if let Err(err) = config.check_integrity() {
            eprintln!("config integrity check failed, {}", err);
            println!("{}", matches.usage());
            return;
        }

        #[cfg(unix)]
        if matches.is_present("DAEMONIZE") || matches.is_present("DAEMONIZE_PID_PATH") {
            use self::common::daemonize;
            daemonize::daemonize(matches.value_of("DAEMONIZE_PID_PATH"));
        }

        info!("shadowsocks manager {} build {}", VERSION, common::BUILD_TIME);

        #[cfg(feature = "multi-threaded")]
        let mut builder = if matches.is_present("SINGLE_THREADED") {
            Builder::new_current_thread()
        } else {
            let mut builder = Builder::new_multi_thread();
            if let Some(worker_threads) = matches.value_of("WORKER_THREADS") {
                builder.worker_threads(worker_threads.parse::<usize>().expect("worker-threads"));
            }
            builder
        };
        #[cfg(not(feature = "multi-threaded"))]
        let mut builder = Builder::new_current_thread();

        let runtime = builder.enable_all().build().expect("create tokio Runtime");

        (config, runtime)
    };

    runtime.block_on(async move {
        let abort_signal = monitor::create_signal_monitor();
        let server = run_manager(config);

        tokio::pin!(abort_signal);
        tokio::pin!(server);

        match future::select(server, abort_signal).await {
            // Server future resolved without an error. This should never happen.
            Either::Left((Ok(..), ..)) => {
                eprintln!("server exited unexpectedly");
                process::exit(common::EXIT_CODE_SERVER_EXIT_UNEXPECTEDLY);
            }
            // Server future resolved with error, which are listener errors in most cases
            Either::Left((Err(err), ..)) => {
                eprintln!("server aborted with {}", err);
                process::exit(common::EXIT_CODE_SERVER_ABORTED);
            }
            // The abort signal future resolved. Means we should just exit.
            Either::Right(_) => (),
        }
    });
}
<|endoftext|>


<commit_before>//! Memory allocation APIs

#![stable(feature = "alloc_module", since = "1.28.0")]

mod global;
mod layout;

#[stable(feature = "global_alloc", since = "1.28.0")]
pub use self::global::GlobalAlloc;
#[stable(feature = "alloc_layout", since = "1.28.0")]
pub use self::layout::{Layout, LayoutErr};

use crate::fmt;
use crate::ptr::{self, NonNull};

/// The `AllocErr` error indicates an allocation failure
/// that may be due to resource exhaustion or to
/// something wrong when combining the given input arguments with this
/// allocator.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AllocErr;

// (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for AllocErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("memory allocation failed")
    }
}

/// A desired initial state for allocated memory.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum AllocInit {
    /// The contents of the new memory are uninitialized.
    Uninitialized,
    /// The new memory is guaranteed to be zeroed.
    Zeroed,
}

impl AllocInit {
    /// Initialize the specified memory block.
    ///
    /// This behaves like calling [`AllocInit::init_offset(memory, 0)`][off].
    ///
    /// [off]: AllocInit::init_offset
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    ///
    /// [valid]: ../../core/ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init(self, memory: MemoryBlock) {
        self.init_offset(memory, 0)
    }

    /// Initialize the memory block like specified by `init` at the specified `offset`.
    ///
    /// This is a no-op for [`AllocInit::Uninitialized`][] and writes zeroes for
    /// [`AllocInit::Zeroed`][] at `ptr + offset` until `ptr + layout.size()`.
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    /// * `offset` must be smaller than or equal to `memory.size`
    ///
    /// [valid]: ../../core/ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init_offset(self, memory: MemoryBlock, offset: usize) {
        debug_assert!(
            offset <= memory.size,
            "`offset` must be smaller than or equal to `memory.size`"
        );
        match self {
            AllocInit::Uninitialized => (),
            AllocInit::Zeroed => {
                memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset)
            }
        }
    }
}

/// Represents a block of allocated memory returned by an allocator.
#[derive(Debug, Copy, Clone)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub struct MemoryBlock {
    pub ptr: NonNull<u8>,
    pub size: usize,
}

/// A placement constraint when growing or shrinking an existing allocation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum ReallocPlacement {
    /// The allocator is allowed to move the allocation to a different memory address.
    // FIXME(wg-allocators#46): Add a section to the module documentation "What is a legal
    //                          allocator" and link it at "valid location".
    ///
    /// If the allocation _does_ move, it's the responsibility of the allocator
    /// to also move the data from the previous location to the new location.
    MayMove,
    /// The address of the new memory must not change.
    ///
    /// If the allocation would have to be moved to a new location to fit, the
    /// reallocation request will fail.
    InPlace,
}

/// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of
/// data described via [`Layout`][].
///
/// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having
/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
/// allocated memory.
///
/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying
/// allocator does not support this (like jemalloc) or return a null pointer (such as
/// `libc::malloc`), this case must be caught.
///
/// ### Currently allocated memory
///
/// Some of the methods require that a memory block be *currently allocated* via an allocator. This
/// means that:
///
/// * the starting address for that memory block was previously returned by [`alloc`], [`grow`], or
///   [`shrink`], and
///
/// * the memory block has not been subsequently deallocated, where blocks are either deallocated
///   directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or
///   [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
///   remains valid.
///
/// [`alloc`]: AllocRef::alloc
/// [`grow`]: AllocRef::grow
/// [`shrink`]: AllocRef::shrink
/// [`dealloc`]: AllocRef::dealloc
///
/// ### Memory fitting
///
/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
/// following conditions must hold:
///
/// * The block must be allocated with the same alignment as [`layout.align()`], and
///
/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
///   - `min` is the size of the layout most recently used to allocate the block, and
///   - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`].
///
/// [`layout.align()`]: Layout::align
/// [`layout.size()`]: Layout::size
///
/// # Safety
///
/// * Memory blocks returned from an allocator must point to valid memory and retain their validity
///   until the instance and all of its clones are dropped, and
///
/// * cloning or moving the allocator must not invalidate memory blocks returned from this
///   allocator. A cloned allocator must behave like the same allocator.
///
/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
///   method of the allocator.
///
/// [*currently allocated*]: #currently-allocated-memory
#[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe trait AllocRef {
    /// On success, returns a memory block meeting the size and alignment guarantees of `layout`.
    ///
    /// The returned block may have a larger size than specified by `layout.size()` and is
    /// initialized as specified by [`init`], all the way up to the returned size of the block.
    ///
    /// [`init`]: AllocInit
    ///
    /// # Errors
    ///
    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
    /// allocator's size or alignment constraints.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr>;

    /// Deallocates the memory denoted by `memory`.
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator, and
    /// * `layout` must [*fit*] the `ptr`.
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);

    /// Attempts to extend the memory block.
    ///
    /// Returns a new memory block containing a pointer and the actual size of the allocated
    /// block. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If `ReallocPlacement::MayMove` is used then ownership of the memory block referenced by `ptr`
    /// is transferred to this allocator. The memory may or may not be freed, and should be
    /// considered unusable (unless of course it is transferred back to the caller again via the
    /// return value of this method).
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The memory block will contain the following contents after a successful call to `grow`:
    ///   * Bytes `0..layout.size()` are preserved from the original allocation.
    ///   * Bytes `layout.size()..old_size` will either be preserved or initialized according to
    ///     [`init`], depending on the allocator implementation. `old_size` refers to the size of
    ///     the `MemoryBlock` prior to the `grow` call, which may be larger than the size
    ///     that was originally requested when it was allocated.
    ///   * Bytes `old_size..new_size` are initialized according to [`init`]. `new_size` refers to
    ///     the size of the `MemoryBlock` returned by the `grow` call.
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    /// [`init`]: AllocInit
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] the `ptr`. (The `new_size` argument need not fit it.)
    // We can't require that `new_size` is strictly greater than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly greater than `memory.size` or both are zero
    /// * `new_size` must be greater than or equal to `layout.size()`
    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow
    ///   (i.e., the rounded value must be less than or equal to `usize::MAX`).
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
        init: AllocInit,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size >= size,
                    "`new_size` must be greater than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, init)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }

    /// Attempts to shrink the memory block.
    ///
    /// Returns a new memory block containing a pointer and the actual size of the allocated
    /// block. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
    /// transferred to this allocator. The memory may or may not have been freed, and should be
    /// considered unusable unless it was transferred back to the caller again via the
    /// return value of this method.
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The behavior of how the allocator tries to shrink the memory is specified by [`placement`].
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] the `ptr`. (The `new_size` argument need not fit it.)
    // We can't require that `new_size` is strictly smaller than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly smaller than `memory.size` or both are zero
    /// * `new_size` must be smaller than or equal to `layout.size()`
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size <= size,
                    "`new_size` must be smaller than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }
}
<commit_msg>Rollup merge of #70728 - TimDiekmann:allocref-doc, r=Amanieu<commit_after>//! Memory allocation APIs

#![stable(feature = "alloc_module", since = "1.28.0")]

mod global;
mod layout;

#[stable(feature = "global_alloc", since = "1.28.0")]
pub use self::global::GlobalAlloc;
#[stable(feature = "alloc_layout", since = "1.28.0")]
pub use self::layout::{Layout, LayoutErr};

use crate::fmt;
use crate::ptr::{self, NonNull};

/// The `AllocErr` error indicates an allocation failure
/// that may be due to resource exhaustion or to
/// something wrong when combining the given input arguments with this
/// allocator.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AllocErr;

// (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for AllocErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("memory allocation failed")
    }
}

/// A desired initial state for allocated memory.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum AllocInit {
    /// The contents of the new memory are uninitialized.
    Uninitialized,
    /// The new memory is guaranteed to be zeroed.
    Zeroed,
}

impl AllocInit {
    /// Initialize the specified memory block.
    ///
    /// This behaves like calling [`AllocInit::init_offset(memory, 0)`][off].
    ///
    /// [off]: AllocInit::init_offset
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    ///
    /// [valid]: ../../core/ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init(self, memory: MemoryBlock) {
        self.init_offset(memory, 0)
    }

    /// Initialize the memory block like specified by `init` at the specified `offset`.
    ///
    /// This is a no-op for [`AllocInit::Uninitialized`][] and writes zeroes for
    /// [`AllocInit::Zeroed`][] at `ptr + offset` until `ptr + layout.size()`.
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    /// * `offset` must be smaller than or equal to `memory.size`
    ///
    /// [valid]: ../../core/ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init_offset(self, memory: MemoryBlock, offset: usize) {
        debug_assert!(
            offset <= memory.size,
            "`offset` must be smaller than or equal to `memory.size`"
        );
        match self {
            AllocInit::Uninitialized => (),
            AllocInit::Zeroed => {
                memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset)
            }
        }
    }
}

/// Represents a block of allocated memory returned by an allocator.
#[derive(Debug, Copy, Clone)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub struct MemoryBlock {
    pub ptr: NonNull<u8>,
    pub size: usize,
}

/// A placement constraint when growing or shrinking an existing allocation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum ReallocPlacement {
    /// The allocator is allowed to move the allocation to a different memory address.
    // FIXME(wg-allocators#46): Add a section to the module documentation "What is a legal
    //                          allocator" and link it at "valid location".
    ///
    /// If the allocation _does_ move, it's the responsibility of the allocator
    /// to also move the data from the previous location to the new location.
    MayMove,
    /// The address of the new memory must not change.
    ///
    /// If the allocation would have to be moved to a new location to fit, the
    /// reallocation request will fail.
    InPlace,
}

/// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of
/// data described via [`Layout`][].
///
/// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having
/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
/// allocated memory.
///
/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying
/// allocator does not support this (like jemalloc) or return a null pointer (such as
/// `libc::malloc`), this must be caught by the implementation.
///
/// ### Currently allocated memory
///
/// Some of the methods require that a memory block be *currently allocated* via an allocator. This
/// means that:
///
/// * the starting address for that memory block was previously returned by [`alloc`], [`grow`], or
///   [`shrink`], and
///
/// * the memory block has not been subsequently deallocated, where blocks are either deallocated
///   directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or
///   [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
///   remains valid.
///
/// [`alloc`]: AllocRef::alloc
/// [`grow`]: AllocRef::grow
/// [`shrink`]: AllocRef::shrink
/// [`dealloc`]: AllocRef::dealloc
///
/// ### Memory fitting
///
/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
/// following conditions must hold:
///
/// * The block must be allocated with the same alignment as [`layout.align()`], and
///
/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
///   - `min` is the size of the layout most recently used to allocate the block, and
///   - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`].
///
/// [`layout.align()`]: Layout::align
/// [`layout.size()`]: Layout::size
///
/// # Safety
///
/// * Memory blocks returned from an allocator must point to valid memory and retain their validity
///   until the instance and all of its clones are dropped,
///
/// * cloning or moving the allocator must not invalidate memory blocks returned from this
///   allocator. A cloned allocator must behave like the same allocator, and
///
/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
///   method of the allocator.
///
/// [*currently allocated*]: #currently-allocated-memory
#[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe trait AllocRef {
    /// Attempts to allocate a block of memory.
    ///
    /// On success, returns a [`MemoryBlock`][] meeting the size and alignment guarantees of `layout`.
    ///
    /// The returned block may have a larger size than specified by `layout.size()` and is
    /// initialized as specified by [`init`], all the way up to the returned size of the block.
    ///
    /// [`init`]: AllocInit
    ///
    /// # Errors
    ///
    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
    /// allocator's size or alignment constraints.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr>;

    /// Deallocates the memory referenced by `ptr`.
    ///
    /// # Safety
    ///
    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and
    /// * `layout` must [*fit*] that block of memory.
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);

    /// Attempts to extend the memory block.
    ///
    /// Returns a new [`MemoryBlock`][] containing a pointer and the actual size of the allocated
    /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If [`MayMove`] is used then ownership of the memory block referenced by `ptr`
    /// is transferred to this allocator. The memory may or may not be freed, and should be
    /// considered unusable (unless of course it is transferred back to the caller again via the
    /// return value of this method).
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The memory block will contain the following contents after a successful call to `grow`:
    ///   * Bytes `0..layout.size()` are preserved from the original allocation.
    ///   * Bytes `layout.size()..old_size` will either be preserved or initialized according to
    ///     [`init`], depending on the allocator implementation. `old_size` refers to the size of
    ///     the `MemoryBlock` prior to the `grow` call, which may be larger than the size
    ///     that was originally requested when it was allocated.
    ///   * Bytes `old_size..new_size` are initialized according to [`init`]. `new_size` refers to
    ///     the size of the `MemoryBlock` returned by the `grow` call.
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`MayMove`]: ReallocPlacement::MayMove
    /// [`placement`]: ReallocPlacement
    /// [`init`]: AllocInit
    ///
    /// # Safety
    ///
    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.),
    // We can't require that `new_size` is strictly greater than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly greater than `memory.size` or both are zero
    /// * `new_size` must be greater than or equal to `layout.size()`, and
    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow
    ///   (i.e., the rounded value must be less than or equal to `usize::MAX`).
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
        init: AllocInit,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size >= size,
                    "`new_size` must be greater than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, init)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }

    /// Attempts to shrink the memory block.
    ///
    /// Returns a new [`MemoryBlock`][] containing a pointer and the actual size of the allocated
    /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
    /// transferred to this allocator. The memory may or may not have been freed, and should be
    /// considered unusable unless it was transferred back to the caller again via the
    /// return value of this method.
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The behavior of how the allocator tries to shrink the memory is specified by [`placement`].
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    ///
    /// # Safety
    ///
    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), and
    // We can't require that `new_size` is strictly smaller than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly smaller than `memory.size` or both are zero
    /// * `new_size` must be smaller than or equal to `layout.size()`.
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if shrinking otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size <= size,
                    "`new_size` must be smaller than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use to_str::{ToStr,ToStrConsume};
use str;
use cast;

/// Datatype to hold one ascii character. It is 8 bit long.
#[deriving(Clone, Eq)]
pub struct Ascii { priv chr: u8 }

pub impl Ascii {
    /// Converts a ascii character into a `u8`.
    #[inline(always)]
    fn to_byte(self) -> u8 {
        self.chr
    }

    /// Converts a ascii character into a `char`.
    #[inline(always)]
    fn to_char(self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline(always)]
    fn to_lower(self) -> Ascii {
        if self.chr >= 65 && self.chr <= 90 {
            Ascii{chr: self.chr | 0x20 }
        } else {
            self
        }
    }

    /// Convert to uppercase.
    #[inline(always)]
    fn to_upper(self) -> Ascii {
        if self.chr >= 97 && self.chr <= 122 {
            Ascii{chr: self.chr & !0x20 }
        } else {
            self
        }
    }

    // Compares two ascii characters of equality, ignoring case.
    #[inline(always)]
    fn eq_ignore_case(self, other: Ascii) -> bool {
        self.to_lower().chr == other.to_lower().chr
    }
}

impl ToStr for Ascii {
    #[inline(always)]
    fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) }
}

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
    /// Convert to an ascii type
    fn to_ascii(&self) -> T;

    /// Check if convertible to ascii
    fn is_ascii(&self) -> bool;
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        unsafe{ cast::transmute(*self) }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
        unsafe{ cast::transmute((p, len - 1))}
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl AsciiCast<Ascii> for u8 {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self & 128 == 0u8
    }
}

impl AsciiCast<Ascii> for char {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self as u8 }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self - ('\x7F' & *self) == '\x00'
    }
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
    /// Take ownership and cast to an ascii vector without trailing zero element.
    fn to_ascii_consume(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        unsafe {cast::transmute(self)}
    }
}

impl OwnedAsciiCast for ~str {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        let mut s = self;
        unsafe {
            str::raw::pop_byte(&mut s);
            cast::transmute(s)
        }
    }
}

/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
pub trait AsciiStr {
    /// Convert to a string.
    fn to_str_ascii(&self) -> ~str;

    /// Convert to vector representing a lower cased ascii string.
    fn to_lower(&self) -> ~[Ascii];

    /// Convert to vector representing a upper cased ascii string.
    fn to_upper(&self) -> ~[Ascii];

}

impl<'self> AsciiStr for &'self [Ascii] {
    #[inline(always)]
    fn to_str_ascii(&self) -> ~str {
        let mut cpy = self.to_owned();
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }

    #[inline(always)]
    fn to_lower(&self) -> ~[Ascii] {
        self.map(|a| a.to_lower())
    }

    #[inline(always)]
    fn to_upper(&self) -> ~[Ascii] {
        self.map(|a| a.to_upper())
    }
}

impl ToStrConsume for ~[Ascii] {
    #[inline(always)]
    fn to_str_consume(self) -> ~str {
        let mut cpy = self;
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

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

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
        (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().to_byte(), 65u8);
        assert_eq!(65u8.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_byte(), 65u8);

        assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
        assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
        assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
        assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');

        assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
        assert_eq!('['.to_ascii().to_lower().to_char(), '[');
        assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
        assert_eq!('{'.to_ascii().to_upper().to_char(), '{');

        assert!(str::all(~"banana", |c| c.is_ascii()));
        assert!(! str::all(~"ประเทศไทย中华Việt Nam", |c| c.is_ascii()));
    }

    #[test]
    fn test_ascii_vec() {
        assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
        assert_eq!("( ;".to_ascii(),                 v2ascii!([40, 32, 59]));
        // FIXME: #5475 borrowchk error, owned vectors do not live long enough
        // if chained-from directly
        let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
        let v = ~"( ;";              assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));

        assert_eq!("abCDef&?#".to_ascii().to_lower().to_str_ascii(), ~"abcdef&?#");
        assert_eq!("abCDef&?#".to_ascii().to_upper().to_str_ascii(), ~"ABCDEF&?#");

        assert_eq!("".to_ascii().to_lower().to_str_ascii(), ~"");
        assert_eq!("YMCA".to_ascii().to_lower().to_str_ascii(), ~"ymca");
        assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().to_str_ascii(), ~"ABCDEFXYZ:.;");

        assert!("".is_ascii());
        assert!("a".is_ascii());
        assert!(!"\u2009".is_ascii());

    }

    #[test]
    fn test_owned_ascii_vec() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
        //           v2ascii!(~[40, 32, 59, 0]));
    }

    #[test]
    fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

    #[test]
    fn test_ascii_to_str_consume() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
    }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
}
<commit_msg>Add a brief description to show up in http://static.rust-lang.org/doc/core/index.html<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Operations on ASCII strings and characters.

use to_str::{ToStr,ToStrConsume};
use str;
use cast;

/// Datatype to hold one ascii character. It is 8 bit long.
#[deriving(Clone, Eq)]
pub struct Ascii { priv chr: u8 }

pub impl Ascii {
    /// Converts a ascii character into a `u8`.
    #[inline(always)]
    fn to_byte(self) -> u8 {
        self.chr
    }

    /// Converts a ascii character into a `char`.
    #[inline(always)]
    fn to_char(self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline(always)]
    fn to_lower(self) -> Ascii {
        if self.chr >= 65 && self.chr <= 90 {
            Ascii{chr: self.chr | 0x20 }
        } else {
            self
        }
    }

    /// Convert to uppercase.
    #[inline(always)]
    fn to_upper(self) -> Ascii {
        if self.chr >= 97 && self.chr <= 122 {
            Ascii{chr: self.chr & !0x20 }
        } else {
            self
        }
    }

    // Compares two ascii characters of equality, ignoring case.
    #[inline(always)]
    fn eq_ignore_case(self, other: Ascii) -> bool {
        self.to_lower().chr == other.to_lower().chr
    }
}

impl ToStr for Ascii {
    #[inline(always)]
    fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) }
}

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
    /// Convert to an ascii type
    fn to_ascii(&self) -> T;

    /// Check if convertible to ascii
    fn is_ascii(&self) -> bool;
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        unsafe{ cast::transmute(*self) }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
        unsafe{ cast::transmute((p, len - 1))}
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl AsciiCast<Ascii> for u8 {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self & 128 == 0u8
    }
}

impl AsciiCast<Ascii> for char {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self as u8 }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self - ('\x7F' & *self) == '\x00'
    }
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
    /// Take ownership and cast to an ascii vector without trailing zero element.
    fn to_ascii_consume(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        unsafe {cast::transmute(self)}
    }
}

impl OwnedAsciiCast for ~str {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        let mut s = self;
        unsafe {
            str::raw::pop_byte(&mut s);
            cast::transmute(s)
        }
    }
}

/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
pub trait AsciiStr {
    /// Convert to a string.
    fn to_str_ascii(&self) -> ~str;

    /// Convert to vector representing a lower cased ascii string.
    fn to_lower(&self) -> ~[Ascii];

    /// Convert to vector representing a upper cased ascii string.
    fn to_upper(&self) -> ~[Ascii];

}

impl<'self> AsciiStr for &'self [Ascii] {
    #[inline(always)]
    fn to_str_ascii(&self) -> ~str {
        let mut cpy = self.to_owned();
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }

    #[inline(always)]
    fn to_lower(&self) -> ~[Ascii] {
        self.map(|a| a.to_lower())
    }

    #[inline(always)]
    fn to_upper(&self) -> ~[Ascii] {
        self.map(|a| a.to_upper())
    }
}

impl ToStrConsume for ~[Ascii] {
    #[inline(always)]
    fn to_str_consume(self) -> ~str {
        let mut cpy = self;
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

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

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
        (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().to_byte(), 65u8);
        assert_eq!(65u8.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_byte(), 65u8);

        assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
        assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
        assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
        assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');

        assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
        assert_eq!('['.to_ascii().to_lower().to_char(), '[');
        assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
        assert_eq!('{'.to_ascii().to_upper().to_char(), '{');

        assert!(str::all(~"banana", |c| c.is_ascii()));
        assert!(! str::all(~"ประเทศไทย中华Việt Nam", |c| c.is_ascii()));
    }

    #[test]
    fn test_ascii_vec() {
        assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
        assert_eq!("( ;".to_ascii(),                 v2ascii!([40, 32, 59]));
        // FIXME: #5475 borrowchk error, owned vectors do not live long enough
        // if chained-from directly
        let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
        let v = ~"( ;";              assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));

        assert_eq!("abCDef&?#".to_ascii().to_lower().to_str_ascii(), ~"abcdef&?#");
        assert_eq!("abCDef&?#".to_ascii().to_upper().to_str_ascii(), ~"ABCDEF&?#");

        assert_eq!("".to_ascii().to_lower().to_str_ascii(), ~"");
        assert_eq!("YMCA".to_ascii().to_lower().to_str_ascii(), ~"ymca");
        assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().to_str_ascii(), ~"ABCDEFXYZ:.;");

        assert!("".is_ascii());
        assert!("a".is_ascii());
        assert!(!"\u2009".is_ascii());

    }

    #[test]
    fn test_owned_ascii_vec() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
        //           v2ascii!(~[40, 32, 59, 0]));
    }

    #[test]
    fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

    #[test]
    fn test_ascii_to_str_consume() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
    }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(warnings)]

#![feature(box_syntax)]
#![feature(core_float)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(dec2flt)]
#![feature(decode_utf8)]
#![feature(exact_size_is_empty)]
#![feature(fixed_size_array)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(iterator_step_by)]
#![feature(i128_type)]
#![feature(inclusive_range)]
#![feature(inclusive_range_syntax)]
#![feature(iterator_try_fold)]
#![feature(iterator_flatten)]
#![feature(conservative_impl_trait)]
#![feature(iter_rfind)]
#![feature(iter_rfold)]
#![feature(iterator_repeat_with)]
#![feature(nonzero)]
#![feature(pattern)]
#![feature(range_is_empty)]
#![feature(raw)]
#![feature(refcell_replace_swap)]
#![feature(sip_hash_13)]
#![feature(slice_patterns)]
#![feature(sort_internals)]
#![feature(specialization)]
#![feature(step_trait)]
#![feature(test)]
#![feature(trusted_len)]
#![feature(try_from)]
#![feature(try_trait)]
#![feature(exact_chunks)]
#![feature(atomic_nand)]
#![feature(reverse_bits)]

extern crate core;
extern crate test;

mod any;
mod array;
mod ascii;
mod atomic;
mod cell;
mod char;
mod clone;
mod cmp;
mod fmt;
mod hash;
mod intrinsics;
mod iter;
mod mem;
mod nonzero;
mod num;
mod ops;
mod option;
mod pattern;
mod ptr;
mod result;
mod slice;
mod str;
mod tuple;
<commit_msg>added ascii_ctypes feature to libcore tests module<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(warnings)]

#![feature(ascii_ctype)]
#![feature(box_syntax)]
#![feature(core_float)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(dec2flt)]
#![feature(decode_utf8)]
#![feature(exact_size_is_empty)]
#![feature(fixed_size_array)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(iterator_step_by)]
#![feature(i128_type)]
#![feature(inclusive_range)]
#![feature(inclusive_range_syntax)]
#![feature(iterator_try_fold)]
#![feature(iterator_flatten)]
#![feature(conservative_impl_trait)]
#![feature(iter_rfind)]
#![feature(iter_rfold)]
#![feature(iterator_repeat_with)]
#![feature(nonzero)]
#![feature(pattern)]
#![feature(range_is_empty)]
#![feature(raw)]
#![feature(refcell_replace_swap)]
#![feature(sip_hash_13)]
#![feature(slice_patterns)]
#![feature(sort_internals)]
#![feature(specialization)]
#![feature(step_trait)]
#![feature(test)]
#![feature(trusted_len)]
#![feature(try_from)]
#![feature(try_trait)]
#![feature(exact_chunks)]
#![feature(atomic_nand)]
#![feature(reverse_bits)]

extern crate core;
extern crate test;

mod any;
mod array;
mod ascii;
mod atomic;
mod cell;
mod char;
mod clone;
mod cmp;
mod fmt;
mod hash;
mod intrinsics;
mod iter;
mod mem;
mod nonzero;
mod num;
mod ops;
mod option;
mod pattern;
mod ptr;
mod result;
mod slice;
mod str;
mod tuple;
<|endoftext|>


<commit_before>use core::condition::Condition;
use core::register::Apsr;
use core::PSR;
use bit_field::BitField;

pub fn sign_extend(word: u32, topbit: u8, size: u8) -> u64 {
    if word & (1 << topbit) == (1 << topbit) {
        return u64::from(word) | u64::from(((1_u64 << (size - topbit)) - 1) << topbit);
    }
    word as u64
}

//
// Add two numbers and carry
//
// x + y + carry
//
// return tuple of (result, carry, overflow)
//
pub fn add_with_carry(x: u32, y: u32, carry_in: bool) -> (u32, bool, bool) {
    let unsigned_sum = u64::from(x) + u64::from(y) + (carry_in as u64);
    let signed_sum = (x as i32)
        .wrapping_add((y as i32))
        .wrapping_add((carry_in as i32));
    let result = (unsigned_sum & 0xffff_ffff) as u32; // same value as signed_sum<N-1:0>
    let carry_out = u64::from(result) != unsigned_sum;
    let overflow = (result as i32) != signed_sum;

    (result, carry_out, overflow)
}

#[test]
fn test_add_with_carry() {
    let (result, carry, overflow) = add_with_carry(0x410, 4, false);
    assert!(result == 0x414);
    assert!(carry == false);
    assert!(overflow == false);
}

//
// This function performs the condition test for an instruction, based on:
// • the two Thumb conditional branch encodings, encodings T1 and T3 of the B instruction
// • the current values of the xPSR.IT[7:0] bits for other Thumb instructions.
//
pub fn condition_passed(condition: &Condition, psr: &PSR) -> bool {
    match *condition {
        Condition::EQ => psr.get_z(),
        Condition::NE => !psr.get_z(),
        Condition::CS => psr.get_c(),
        Condition::CC => !psr.get_c(),
        Condition::MI => psr.get_n(),
        Condition::PL => !psr.get_n(),

        Condition::VS => psr.get_v(),
        Condition::VC => !psr.get_v(),

        Condition::HI => psr.get_c() && !psr.get_z(),
        Condition::LS => !(psr.get_c() && !psr.get_z()),

        Condition::GE => psr.get_n() == psr.get_v(),
        Condition::LT => !(psr.get_n() == psr.get_v()),

        Condition::GT => (psr.get_n() == psr.get_v()) && !psr.get_z(),
        Condition::LE => !((psr.get_n() == psr.get_v()) && !psr.get_z()),

        Condition::AL => true,
    }
}

#[derive(Debug, PartialEq)]
pub enum SRType {
    LSL,
    LSR,
    ASR,
    RRX,
    ROR,
}

// Decode immedate shift type
// input: bits[2], immedate
// output: (shitft type, immedate to use)
//
pub fn decode_imm_shift(typebits: u8, imm5: u8) -> (SRType, u8) {
    match typebits.get_bits(0..3) {
        0b00 => (SRType::LSL, imm5),
        0b01 => (SRType::LSR, if imm5 == 0 { 32 } else { imm5 }),
        0b10 => (SRType::ASR, if imm5 == 0 { 32 } else { imm5 }),
        0b11 => match imm5 {
            0 => (SRType::RRX, 1),
            _ => (SRType::ROR, imm5),
        },
        _ => panic!("invalid typebits"),
    }
}

fn lsl_c(value: u32, shift: u32) -> (u32, bool) {
    assert!(shift > 0);
    let extended = u64::from(value) << shift;

    (extended.get_bits(0..32) as u32, extended.get_bit(32))
}

fn lsr_c(value: u32, shift: u8) -> (u32, bool) {
    assert!(shift > 0);

    let extended = u64::from(value);

    (
        extended.get_bits(shift..(shift + 32)) as u32,
        extended.get_bit(shift - 1),
    )
}

fn asr_c(value: u32, shift: u8) -> (u32, bool) {
    assert!(shift > 0);

    let extended = sign_extend(value, 31, 32 + shift);

    (
        extended.get_bits(shift..(shift + 32)) as u32,
        extended.get_bit(shift - 1),
    )
}

pub fn shift_c(value: u32, shift_t: SRType, amount: u32, carry_in: bool) -> (u32, bool) {
    assert!(!((shift_t == SRType::RRX) && (amount != 1)));
    if amount == 0 {
        (value, carry_in)
    } else {
        match shift_t {
            SRType::LSL => lsl_c(value, amount),
            SRType::LSR => lsr_c(value, amount as u8),
            SRType::ASR => asr_c(value, amount as u8),
            _ => panic!("not implemented"),
        }
    }
}

#[test]
fn test_shift_c() {
    {
        let (result, carry) = shift_c(0xFFFFFFF8, SRType::ASR, 8, false);
        assert!(result == 0xFFFFFFFF);
        assert!(carry == true);
    }
    {
        let (result, carry) = shift_c(0xef, SRType::ASR, 9, false);
        assert!(result == 0);
        assert!(carry == false);
    }
    {
        let (result, carry) = shift_c(0xFFFFFFC0, SRType::ASR, 1, false);
        assert!(result == 0xFFFFFFE0);
        assert!(carry == false);
    }
}
<commit_msg>improve test coverage on add_with_carry<commit_after>use core::condition::Condition;
use core::register::Apsr;
use core::PSR;
use bit_field::BitField;

pub fn sign_extend(word: u32, topbit: u8, size: u8) -> u64 {
    if word & (1 << topbit) == (1 << topbit) {
        return u64::from(word) | u64::from(((1_u64 << (size - topbit)) - 1) << topbit);
    }
    word as u64
}

//
// Add two numbers and carry
//
// x + y + carry
//
// return tuple of (result, carry, overflow)
//
pub fn add_with_carry(x: u32, y: u32, carry_in: bool) -> (u32, bool, bool) {
    let unsigned_sum = u64::from(x) + u64::from(y) + (carry_in as u64);
    let signed_sum = (x as i32)
        .wrapping_add((y as i32))
        .wrapping_add((carry_in as i32));
    let result = (unsigned_sum & 0xffff_ffff) as u32; // same value as signed_sum<N-1:0>
    let carry_out = u64::from(result) != unsigned_sum;
    let overflow = (result as i32) != signed_sum;

    (result, carry_out, overflow)
}

#[test]
fn test_add_with_carry() {
    let (result, carry, overflow) = add_with_carry(0x410, 4, false);
    assert_eq!(result,0x414);
    assert_eq!(carry,false);
    assert_eq!(overflow,false);
}

#[test]
fn test_add_with_carry_basic() {
    let (result, carry, overflow) = add_with_carry(0x0, 0xffff_ffff, false);
    assert_eq!(result,0xffff_ffff);
    assert_eq!(carry,false);
    assert_eq!(overflow,false);
}

#[test]
fn test_add_with_carry_basic2() {
    let (result, carry, overflow) = add_with_carry(0x0, 0xffff_ffff, true);
    assert_eq!(result,0);
    assert_eq!(carry,true);
    assert_eq!(overflow,false);
}

#[test]
fn test_add_with_carry_basic3() {
    let (result, carry, overflow) = add_with_carry(0x0, 0, true);
    assert_eq!(result,1);
    assert_eq!(carry,false);
    assert_eq!(overflow,false);
}

#[test]
fn test_add_with_carry_basic4() {
    let (result, carry, overflow) = add_with_carry(0xffff_ffff, 0, true);
    assert_eq!(result,0);
    assert_eq!(carry,true);
    assert_eq!(overflow,false);
}

#[test]
fn test_add_with_carry_basic5() {
    let (result, carry, overflow) = add_with_carry(0xffff_ffff, 0xffff_ffff, true);
    assert_eq!(result,0xffff_ffff);
    assert_eq!(carry,true);
    assert_eq!(overflow,false);
}

#[test]
fn test_add_with_carry_basic6() {
    let (result, carry, overflow) = add_with_carry(0xffff_ffff, 0xffff_ffff, false);
    assert_eq!(result,0xffff_fffe);
    assert_eq!(carry,true);
    assert_eq!(overflow,false);
}

//
// This function performs the condition test for an instruction, based on:
// • the two Thumb conditional branch encodings, encodings T1 and T3 of the B instruction
// • the current values of the xPSR.IT[7:0] bits for other Thumb instructions.
//
pub fn condition_passed(condition: &Condition, psr: &PSR) -> bool {
    match *condition {
        Condition::EQ => psr.get_z(),
        Condition::NE => !psr.get_z(),
        Condition::CS => psr.get_c(),
        Condition::CC => !psr.get_c(),
        Condition::MI => psr.get_n(),
        Condition::PL => !psr.get_n(),

        Condition::VS => psr.get_v(),
        Condition::VC => !psr.get_v(),

        Condition::HI => psr.get_c() && !psr.get_z(),
        Condition::LS => !(psr.get_c() && !psr.get_z()),

        Condition::GE => psr.get_n() == psr.get_v(),
        Condition::LT => !(psr.get_n() == psr.get_v()),

        Condition::GT => (psr.get_n() == psr.get_v()) && !psr.get_z(),
        Condition::LE => !((psr.get_n() == psr.get_v()) && !psr.get_z()),

        Condition::AL => true,
    }
}

#[derive(Debug, PartialEq)]
pub enum SRType {
    LSL,
    LSR,
    ASR,
    RRX,
    ROR,
}

// Decode immedate shift type
// input: bits[2], immedate
// output: (shitft type, immedate to use)
//
pub fn decode_imm_shift(typebits: u8, imm5: u8) -> (SRType, u8) {
    match typebits.get_bits(0..3) {
        0b00 => (SRType::LSL, imm5),
        0b01 => (SRType::LSR, if imm5 == 0 { 32 } else { imm5 }),
        0b10 => (SRType::ASR, if imm5 == 0 { 32 } else { imm5 }),
        0b11 => match imm5 {
            0 => (SRType::RRX, 1),
            _ => (SRType::ROR, imm5),
        },
        _ => panic!("invalid typebits"),
    }
}

fn lsl_c(value: u32, shift: u32) -> (u32, bool) {
    assert!(shift > 0);
    let extended = u64::from(value) << shift;

    (extended.get_bits(0..32) as u32, extended.get_bit(32))
}

fn lsr_c(value: u32, shift: u8) -> (u32, bool) {
    assert!(shift > 0);

    let extended = u64::from(value);

    (
        extended.get_bits(shift..(shift + 32)) as u32,
        extended.get_bit(shift - 1),
    )
}

fn asr_c(value: u32, shift: u8) -> (u32, bool) {
    assert!(shift > 0);

    let extended = sign_extend(value, 31, 32 + shift);

    (
        extended.get_bits(shift..(shift + 32)) as u32,
        extended.get_bit(shift - 1),
    )
}

pub fn shift_c(value: u32, shift_t: SRType, amount: u32, carry_in: bool) -> (u32, bool) {
    assert!(!((shift_t == SRType::RRX) && (amount != 1)));
    if amount == 0 {
        (value, carry_in)
    } else {
        match shift_t {
            SRType::LSL => lsl_c(value, amount),
            SRType::LSR => lsr_c(value, amount as u8),
            SRType::ASR => asr_c(value, amount as u8),
            _ => panic!("not implemented"),
        }
    }
}

#[test]
fn test_shift_c() {
    {
        let (result, carry) = shift_c(0xFFFFFFF8, SRType::ASR, 8, false);
        assert!(result == 0xFFFFFFFF);
        assert!(carry == true);
    }
    {
        let (result, carry) = shift_c(0xef, SRType::ASR, 9, false);
        assert!(result == 0);
        assert!(carry == false);
    }
    {
        let (result, carry) = shift_c(0xFFFFFFC0, SRType::ASR, 1, false);
        assert!(result == 0xFFFFFFE0);
        assert!(carry == false);
    }
}
<|endoftext|>