<commit_before>/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use aws_sdk_s3::{Client, Config, Error, Region, PKG_VERSION};
use aws_types::region;
use aws_types::region::ProvideRegion;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// The AWS Region.
    #[structopt(short, long)]
    region: Option<String>,

    /// Whether to display additional information.
    #[structopt(short, long)]
    verbose: bool,
}

/// Lists your Amazon S3 buckets in the Region.
/// # Arguments
///
/// * `[-r REGION]` - The Region in which the client is created.
///   If not supplied, uses the value of the **AWS_REGION** environment variable.
///   If the environment variable is not set, defaults to **us-west-2**.
/// * `[-v]` - Whether to display additional information.
#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt::init();

    let Opt { region, verbose } = Opt::from_args();

    let region = region::ChainProvider::first_try(region.map(Region::new))
        .or_default_provider()
        .or_else(Region::new("us-west-2"));

    println!();

    if verbose {
        println!("S3 client version: {}", PKG_VERSION);
        println!("Region:            {}", region.region().unwrap().as_ref());
        println!();
    }

    let conf = Config::builder().region(region).build();
    let client = Client::from_conf(conf);

    let resp = client.list_buckets().send().await?;
    let buckets = resp.buckets.unwrap_or_default();
    let num_buckets = buckets.len();

    for bucket in &buckets {
        println!("{}", bucket.name.as_deref().unwrap_or_default());
    }

    println!();
    println!("Found {} buckets", num_buckets);

    Ok(())
}
<commit_msg>Added filter to S3 ListBuckets operation in Rust to only see buckets in region<commit_after>/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use aws_sdk_s3::{Client, Config, Error, Region, PKG_VERSION};
use aws_types::region;
use aws_types::region::ProvideRegion;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// The AWS Region.
    #[structopt(short, long)]
    region: Option<String>,

    /// Whether to only get buckets in the Region.
    #[structopt(short, long)]
    strict: bool,

    /// Whether to display additional information.
    #[structopt(short, long)]
    verbose: bool,
}

/// Lists your Amazon S3 buckets, or just the buckets in the Region.
/// # Arguments
///
/// * `[-s]` - Only list bucket in the Region.
/// * `[-r REGION]` - The Region in which the client is created.
///   If not supplied, uses the value of the **AWS_REGION** environment variable.
///   If the environment variable is not set, defaults to **us-west-2**.
/// * `[-v]` - Whether to display additional information.
#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt::init();

    let Opt {
        region,
        strict,
        verbose,
    } = Opt::from_args();

    let region = region::ChainProvider::first_try(region.map(Region::new))
        .or_default_provider()
        .or_else(Region::new("us-west-2"));

    let region_str: String = String::from(region.region().unwrap().as_ref());

    if verbose {
        println!("S3 client version: {}", PKG_VERSION);
        println!("Region:            {}", region_str);

        if strict {
            println!("Only lists buckets in the Region.");
        } else {
            println!("Lists all buckets.");
        }

        println!();
    }

    let conf = Config::builder().region(region.region()).build();
    let client = Client::from_conf(conf);

    let resp = client.list_buckets().send().await?;
    let buckets = resp.buckets.unwrap_or_default();
    let num_buckets = buckets.len();

    let mut in_region = 0;

    for bucket in &buckets {
        if strict {
            let r = client
                .get_bucket_location()
                .bucket(bucket.name.as_deref().unwrap_or_default())
                .send()
                .await?;

            if r.location_constraint.unwrap().as_ref() == region_str {
                println!("{}", bucket.name.as_deref().unwrap_or_default());
                in_region += 1;
            }
        } else {
            println!("{}", bucket.name.as_deref().unwrap_or_default());
        }
    }

    println!();
    if strict {
        println!(
            "Found {} buckets in the {} region out of a total of {} buckets.",
            in_region, region_str, num_buckets
        );
    } else {
        println!("Found {} buckets in all regions.", num_buckets);
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Logging wrapper to be used throughout all crates in the workspace
use std::ops::Deref;
use Mutex;

use backtrace::Backtrace;
use std::{panic, thread};

use types::{LogLevel, LoggingConfig};

use log::{LevelFilter, Record};
use log4rs;
use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::append::rolling_file::{
	policy::compound::roll::fixed_window::FixedWindowRoller,
	policy::compound::trigger::size::SizeTrigger, policy::compound::CompoundPolicy,
	RollingFileAppender,
};
use log4rs::append::Append;
use log4rs::config::{Appender, Config, Root};
use log4rs::encode::pattern::PatternEncoder;
use log4rs::filter::{threshold::ThresholdFilter, Filter, Response};

fn convert_log_level(in_level: &LogLevel) -> LevelFilter {
	match *in_level {
		LogLevel::Info => LevelFilter::Info,
		LogLevel::Warning => LevelFilter::Warn,
		LogLevel::Debug => LevelFilter::Debug,
		LogLevel::Trace => LevelFilter::Trace,
		LogLevel::Error => LevelFilter::Error,
	}
}

lazy_static! {
	/// Flag to observe whether logging was explicitly initialised (don't output otherwise)
	static ref WAS_INIT: Mutex<bool> = Mutex::new(false);
	/// Flag to observe whether tui is running, and we therefore don't want to attempt to write
	/// panics to stdout
	static ref TUI_RUNNING: Mutex<bool> = Mutex::new(false);
	/// Static Logging configuration, should only be set once, before first logging call
	static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());
}

/// This filter is rejecting messages that doesn't start with "grin"
/// in order to save log space for only Grin-related records
#[derive(Debug)]
struct GrinFilter;

impl Filter for GrinFilter {
	fn filter(&self, record: &Record) -> Response {
		if let Some(module_path) = record.module_path() {
			if module_path.starts_with("grin") {
				return Response::Neutral;
			}
		}

		Response::Reject
	}
}

/// Initialize the logger with the given configuration
pub fn init_logger(config: Option<LoggingConfig>) {
	if let Some(c) = config {
		let tui_running = c.tui_running.unwrap_or(false);
		if tui_running {
			let mut tui_running_ref = TUI_RUNNING.lock();
			*tui_running_ref = true;
		}

		// Save current logging configuration
		let mut config_ref = LOGGING_CONFIG.lock();
		*config_ref = c.clone();

		let level_stdout = convert_log_level(&c.stdout_log_level);
		let level_file = convert_log_level(&c.file_log_level);
		let level_minimum;

		// Determine minimum logging level for Root logger
		if level_stdout > level_file {
			level_minimum = level_stdout;
		} else {
			level_minimum = level_file;
		}

		// Start logger
		let stdout = ConsoleAppender::builder()
			.encoder(Box::new(PatternEncoder::default()))
			.build();

		let mut root = Root::builder();

		let mut appenders = vec![];

		if c.log_to_stdout && !tui_running {
			let filter = Box::new(ThresholdFilter::new(level_stdout));
			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("stdout", Box::new(stdout)),
			);

			root = root.appender("stdout");
		}

		if c.log_to_file {
			// If maximum log size is specified, use rolling file appender
			// or use basic one otherwise
			let filter = Box::new(ThresholdFilter::new(level_file));
			let file: Box<Append> = {
				if let Some(size) = c.log_max_size {
					let roller = FixedWindowRoller::builder()
						.build(&format!("{}.{{}}.gz", c.log_file_path), 32)
						.unwrap();
					let trigger = SizeTrigger::new(size);

					let policy = CompoundPolicy::new(Box::new(trigger), Box::new(roller));

					Box::new(
						RollingFileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new("{d} {l} {M} - {m}{n}")))
							.build(c.log_file_path, Box::new(policy))
							.unwrap(),
					)
				} else {
					Box::new(
						FileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new("{d} {l} {M} - {m}{n}")))
							.build(c.log_file_path)
							.unwrap(),
					)
				}
			};

			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("file", file),
			);
			root = root.appender("file");
		}

		let config = Config::builder()
			.appenders(appenders)
			.build(root.build(level_minimum))
			.unwrap();

		let _ = log4rs::init_config(config).unwrap();

		info!(
			"log4rs is initialized, file level: {:?}, stdout level: {:?}, min. level: {:?}",
			level_file, level_stdout, level_minimum
		);

		// Mark logger as initialized
		let mut was_init_ref = WAS_INIT.lock();
		*was_init_ref = true;
	}

	send_panic_to_log();
}

/// Initializes the logger for unit and integration tests
pub fn init_test_logger() {
	let mut was_init_ref = WAS_INIT.lock();
	if *was_init_ref.deref() {
		return;
	}
	let mut logger = LoggingConfig::default();
	logger.log_to_file = false;
	logger.stdout_log_level = LogLevel::Debug;
	let mut config_ref = LOGGING_CONFIG.lock();
	*config_ref = logger;
	*was_init_ref = true;
}

/// hook to send panics to logs as well as stderr
fn send_panic_to_log() {
	panic::set_hook(Box::new(|info| {
		let backtrace = Backtrace::new();

		let thread = thread::current();
		let thread = thread.name().unwrap_or("unnamed");

		let msg = match info.payload().downcast_ref::<&'static str>() {
			Some(s) => *s,
			None => match info.payload().downcast_ref::<String>() {
				Some(s) => &**s,
				None => "Box<Any>",
			},
		};

		match info.location() {
			Some(location) => {
				error!(
					"\nthread '{}' panicked at '{}': {}:{}{:?}\n\n",
					thread,
					msg,
					location.file(),
					location.line(),
					backtrace
				);
			}
			None => error!("thread '{}' panicked at '{}'{:?}", thread, msg, backtrace),
		}
		//also print to stderr
		let tui_running = TUI_RUNNING.lock().clone();
		if !tui_running {
			let config = LOGGING_CONFIG.lock();

			eprintln!(
				"Thread '{}' panicked with message:\n\"{}\"\nSee {} for further details.",
				thread, msg, config.log_file_path
			);
		}
	}));
}
<commit_msg>fix: more readable timestamp format for logging (#1912)<commit_after>// Copyright 2018 The Grin Developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Logging wrapper to be used throughout all crates in the workspace
use std::ops::Deref;
use Mutex;

use backtrace::Backtrace;
use std::{panic, thread};

use types::{LogLevel, LoggingConfig};

use log::{LevelFilter, Record};
use log4rs;
use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::append::rolling_file::{
	policy::compound::roll::fixed_window::FixedWindowRoller,
	policy::compound::trigger::size::SizeTrigger, policy::compound::CompoundPolicy,
	RollingFileAppender,
};
use log4rs::append::Append;
use log4rs::config::{Appender, Config, Root};
use log4rs::encode::pattern::PatternEncoder;
use log4rs::filter::{threshold::ThresholdFilter, Filter, Response};

fn convert_log_level(in_level: &LogLevel) -> LevelFilter {
	match *in_level {
		LogLevel::Info => LevelFilter::Info,
		LogLevel::Warning => LevelFilter::Warn,
		LogLevel::Debug => LevelFilter::Debug,
		LogLevel::Trace => LevelFilter::Trace,
		LogLevel::Error => LevelFilter::Error,
	}
}

lazy_static! {
	/// Flag to observe whether logging was explicitly initialised (don't output otherwise)
	static ref WAS_INIT: Mutex<bool> = Mutex::new(false);
	/// Flag to observe whether tui is running, and we therefore don't want to attempt to write
	/// panics to stdout
	static ref TUI_RUNNING: Mutex<bool> = Mutex::new(false);
	/// Static Logging configuration, should only be set once, before first logging call
	static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());
}

const LOGGING_PATTERN: &str = "{d(%Y%m%d %H:%M:%S%.3f)} {h({l})} {M} - {m}{n}";

/// This filter is rejecting messages that doesn't start with "grin"
/// in order to save log space for only Grin-related records
#[derive(Debug)]
struct GrinFilter;

impl Filter for GrinFilter {
	fn filter(&self, record: &Record) -> Response {
		if let Some(module_path) = record.module_path() {
			if module_path.starts_with("grin") {
				return Response::Neutral;
			}
		}

		Response::Reject
	}
}

/// Initialize the logger with the given configuration
pub fn init_logger(config: Option<LoggingConfig>) {
	if let Some(c) = config {
		let tui_running = c.tui_running.unwrap_or(false);
		if tui_running {
			let mut tui_running_ref = TUI_RUNNING.lock();
			*tui_running_ref = true;
		}

		// Save current logging configuration
		let mut config_ref = LOGGING_CONFIG.lock();
		*config_ref = c.clone();

		let level_stdout = convert_log_level(&c.stdout_log_level);
		let level_file = convert_log_level(&c.file_log_level);
		let level_minimum;

		// Determine minimum logging level for Root logger
		if level_stdout > level_file {
			level_minimum = level_stdout;
		} else {
			level_minimum = level_file;
		}

		// Start logger
		let stdout = ConsoleAppender::builder()
			.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
			.build();

		let mut root = Root::builder();

		let mut appenders = vec![];

		if c.log_to_stdout && !tui_running {
			let filter = Box::new(ThresholdFilter::new(level_stdout));
			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("stdout", Box::new(stdout)),
			);

			root = root.appender("stdout");
		}

		if c.log_to_file {
			// If maximum log size is specified, use rolling file appender
			// or use basic one otherwise
			let filter = Box::new(ThresholdFilter::new(level_file));
			let file: Box<Append> = {
				if let Some(size) = c.log_max_size {
					let roller = FixedWindowRoller::builder()
						.build(&format!("{}.{{}}.gz", c.log_file_path), 32)
						.unwrap();
					let trigger = SizeTrigger::new(size);

					let policy = CompoundPolicy::new(Box::new(trigger), Box::new(roller));

					Box::new(
						RollingFileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
							.build(c.log_file_path, Box::new(policy))
							.unwrap(),
					)
				} else {
					Box::new(
						FileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
							.build(c.log_file_path)
							.unwrap(),
					)
				}
			};

			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("file", file),
			);
			root = root.appender("file");
		}

		let config = Config::builder()
			.appenders(appenders)
			.build(root.build(level_minimum))
			.unwrap();

		let _ = log4rs::init_config(config).unwrap();

		info!(
			"log4rs is initialized, file level: {:?}, stdout level: {:?}, min. level: {:?}",
			level_file, level_stdout, level_minimum
		);

		// Mark logger as initialized
		let mut was_init_ref = WAS_INIT.lock();
		*was_init_ref = true;
	}

	send_panic_to_log();
}

/// Initializes the logger for unit and integration tests
pub fn init_test_logger() {
	let mut was_init_ref = WAS_INIT.lock();
	if *was_init_ref.deref() {
		return;
	}
	let mut logger = LoggingConfig::default();
	logger.log_to_file = false;
	logger.stdout_log_level = LogLevel::Debug;
	let mut config_ref = LOGGING_CONFIG.lock();
	*config_ref = logger;
	*was_init_ref = true;
}

/// hook to send panics to logs as well as stderr
fn send_panic_to_log() {
	panic::set_hook(Box::new(|info| {
		let backtrace = Backtrace::new();

		let thread = thread::current();
		let thread = thread.name().unwrap_or("unnamed");

		let msg = match info.payload().downcast_ref::<&'static str>() {
			Some(s) => *s,
			None => match info.payload().downcast_ref::<String>() {
				Some(s) => &**s,
				None => "Box<Any>",
			},
		};

		match info.location() {
			Some(location) => {
				error!(
					"\nthread '{}' panicked at '{}': {}:{}{:?}\n\n",
					thread,
					msg,
					location.file(),
					location.line(),
					backtrace
				);
			}
			None => error!("thread '{}' panicked at '{}'{:?}", thread, msg, backtrace),
		}
		//also print to stderr
		let tui_running = TUI_RUNNING.lock().clone();
		if !tui_running {
			let config = LOGGING_CONFIG.lock();

			eprintln!(
				"Thread '{}' panicked with message:\n\"{}\"\nSee {} for further details.",
				thread, msg, config.log_file_path
			);
		}
	}));
}
<|endoftext|>


<commit_before>extern crate c_ares_sys;

use std::fmt;
use std::mem;
use std::net::Ipv6Addr;
use std::os::raw::{
    c_int,
    c_uchar,
    c_void,
};
use std::ptr;
use std::slice;

use error::AresError;
use types::MAX_ADDRTTLS;
use utils::{
    ares_error,
    ipv6_address_from_bytes,
};

/// The result of a successful AAAA lookup.
pub struct AAAAResults {
    naddr6ttls: usize,
    addr6ttls: [c_ares_sys::Struct_ares_addr6ttl; MAX_ADDRTTLS],
}

/// The contents of a single AAAA record.
#[derive(Clone, Copy)]
pub struct AAAAResult<'a> {
    addr6ttl: &'a c_ares_sys::Struct_ares_addr6ttl,
}

impl AAAAResults {
    /// Obtain an `AAAAResults` from the response to an AAAA lookup.
    pub fn parse_from(data: &[u8]) -> Result<AAAAResults, AresError> {
        let mut results: AAAAResults = AAAAResults {
            naddr6ttls: MAX_ADDRTTLS,
            addr6ttls: unsafe { mem::uninitialized() },
        };
        let parse_status = unsafe {
            c_ares_sys::ares_parse_aaaa_reply(
                data.as_ptr(),
                data.len() as c_int,
                ptr::null_mut(),
                results.addr6ttls.as_mut_ptr(),
                &mut results.naddr6ttls as *mut _ as *mut c_int)
        };
        if parse_status == c_ares_sys::ARES_SUCCESS {
            Ok(results)
        } else {
            Err(ares_error(parse_status))
        }
    }

    /// Returns an iterator over the `AAAAResult` values in this `AAAAResults`.
    pub fn iter(&self) -> AAAAResultsIter {
        AAAAResultsIter {
            addr6ttls: self.addr6ttls[0 .. self.naddr6ttls].iter()
        }
    }
}

impl fmt::Display for AAAAResults {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "["));
        let mut first = true;
        for aaaa_result in self {
            let prefix = if first { "" } else { ", " };
            first = false;
            try!(write!(fmt, "{}{{{}}}", prefix, aaaa_result));
        }
        try!(write!(fmt, "]"));
        Ok(())
    }
}

/// Iterator of `AAAAResult`s.
#[derive(Clone)]
pub struct AAAAResultsIter<'a> {
    addr6ttls: slice::Iter<'a, c_ares_sys::Struct_ares_addr6ttl>,
}

impl<'a> Iterator for AAAAResultsIter<'a> {
    type Item = AAAAResult<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        self.addr6ttls.next().map(|addr6ttl| AAAAResult { addr6ttl: addr6ttl })
    }
}

impl<'a> IntoIterator for &'a AAAAResults {
    type Item = AAAAResult<'a>;
    type IntoIter = AAAAResultsIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> AAAAResult<'a> {
    /// Returns the IPv6 address in this `AAAAResult`.
    pub fn ipv6(&self) -> Ipv6Addr {
        let bytes = &self.addr6ttl.ip6addr._S6_un._bindgen_data_;
        ipv6_address_from_bytes(bytes)
    }

    /// Returns the time-to-live in this `AAAAResult`.
    pub fn ttl(&self) -> i32 {
        self.addr6ttl.ttl as i32
    }
}

impl<'a> fmt::Display for AAAAResult<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "IPv6: {}, ", self.ipv6()));
        try!(write!(fmt, "TTL: {}, ", self.ttl()));
        Ok(())
    }
}

pub unsafe extern "C" fn query_aaaa_callback<F>(
    arg: *mut c_void,
    status: c_int,
    _timeouts: c_int,
    abuf: *mut c_uchar,
    alen: c_int)
    where F: FnOnce(Result<AAAAResults, AresError>) + 'static {
    let result = if status == c_ares_sys::ARES_SUCCESS {
        let data = slice::from_raw_parts(abuf, alen as usize);
        AAAAResults::parse_from(data)
    } else {
        Err(ares_error(status))
    };
    let handler = Box::from_raw(arg as *mut F);
    handler(result);
}
<commit_msg>Clippy<commit_after>extern crate c_ares_sys;

use std::fmt;
use std::mem;
use std::net::Ipv6Addr;
use std::os::raw::{
    c_int,
    c_uchar,
    c_void,
};
use std::ptr;
use std::slice;

use error::AresError;
use types::MAX_ADDRTTLS;
use utils::{
    ares_error,
    ipv6_address_from_bytes,
};

/// The result of a successful AAAA lookup.
pub struct AAAAResults {
    naddr6ttls: usize,
    addr6ttls: [c_ares_sys::Struct_ares_addr6ttl; MAX_ADDRTTLS],
}

/// The contents of a single AAAA record.
#[derive(Clone, Copy)]
pub struct AAAAResult<'a> {
    addr6ttl: &'a c_ares_sys::Struct_ares_addr6ttl,
}

impl AAAAResults {
    /// Obtain an `AAAAResults` from the response to an AAAA lookup.
    pub fn parse_from(data: &[u8]) -> Result<AAAAResults, AresError> {
        let mut results: AAAAResults = AAAAResults {
            naddr6ttls: MAX_ADDRTTLS,
            addr6ttls: unsafe { mem::uninitialized() },
        };
        let parse_status = unsafe {
            c_ares_sys::ares_parse_aaaa_reply(
                data.as_ptr(),
                data.len() as c_int,
                ptr::null_mut(),
                results.addr6ttls.as_mut_ptr(),
                &mut results.naddr6ttls as *mut _ as *mut c_int)
        };
        if parse_status == c_ares_sys::ARES_SUCCESS {
            Ok(results)
        } else {
            Err(ares_error(parse_status))
        }
    }

    /// Returns an iterator over the `AAAAResult` values in this `AAAAResults`.
    pub fn iter(&self) -> AAAAResultsIter {
        AAAAResultsIter {
            addr6ttls: self.addr6ttls[0 .. self.naddr6ttls].iter()
        }
    }
}

impl fmt::Display for AAAAResults {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "["));
        let mut first = true;
        for aaaa_result in self {
            let prefix = if first { "" } else { ", " };
            first = false;
            try!(write!(fmt, "{}{{{}}}", prefix, aaaa_result));
        }
        try!(write!(fmt, "]"));
        Ok(())
    }
}

/// Iterator of `AAAAResult`s.
#[derive(Clone)]
pub struct AAAAResultsIter<'a> {
    addr6ttls: slice::Iter<'a, c_ares_sys::Struct_ares_addr6ttl>,
}

impl<'a> Iterator for AAAAResultsIter<'a> {
    type Item = AAAAResult<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        self.addr6ttls.next().map(|addr6ttl| AAAAResult { addr6ttl: addr6ttl })
    }
}

impl<'a> IntoIterator for &'a AAAAResults {
    type Item = AAAAResult<'a>;
    type IntoIter = AAAAResultsIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> AAAAResult<'a> {
    /// Returns the IPv6 address in this `AAAAResult`.
    #[cfg_attr(feature="clippy", allow(used_underscore_binding))]
    pub fn ipv6(&self) -> Ipv6Addr {
        let bytes = &self.addr6ttl.ip6addr._S6_un._bindgen_data_;
        ipv6_address_from_bytes(bytes)
    }

    /// Returns the time-to-live in this `AAAAResult`.
    pub fn ttl(&self) -> i32 {
        self.addr6ttl.ttl as i32
    }
}

impl<'a> fmt::Display for AAAAResult<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "IPv6: {}, ", self.ipv6()));
        try!(write!(fmt, "TTL: {}, ", self.ttl()));
        Ok(())
    }
}

pub unsafe extern "C" fn query_aaaa_callback<F>(
    arg: *mut c_void,
    status: c_int,
    _timeouts: c_int,
    abuf: *mut c_uchar,
    alen: c_int)
    where F: FnOnce(Result<AAAAResults, AresError>) + 'static {
    let result = if status == c_ares_sys::ARES_SUCCESS {
        let data = slice::from_raw_parts(abuf, alen as usize);
        AAAAResults::parse_from(data)
    } else {
        Err(ares_error(status))
    };
    let handler = Box::from_raw(arg as *mut F);
    handler(result);
}
<|endoftext|>


<commit_before>use super::*;

use std::iter;

/// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Attribute {
    pub style: AttrStyle,
    pub name: Ident,
    pub tts: Vec<TokenTree>,
    pub is_sugared_doc: bool,
}

impl Attribute {
    pub fn meta_item(&self) -> Option<MetaItem> {
        if self.tts.is_empty() {
            return Some(MetaItem::Word);
        }

        if self.tts.len() == 1 {
            if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, ref tts }) = self.tts[0] {
                fn nested_meta_item_from_tokens(tts: &[TokenTree]) -> Option<(NestedMetaItem, &[TokenTree])> {
                    assert!(!tts.is_empty());

                    match tts[0] {
                        TokenTree::Token(Token::Literal(ref lit)) => {
                            Some((NestedMetaItem::Literal(lit.clone()), &tts[1..]))
                        }

                        TokenTree::Token(Token::Ident(ref ident)) => {
                            if tts.len() >= 3 {
                                match (&tts[1], &tts[2]) {
                                    (&TokenTree::Token(Token::Eq), &TokenTree::Token(Token::Literal(ref lit))) => {
                                        return Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::NameValue(lit.clone())), &tts[3..]));
                                    }

                                    _ => {}
                                }
                            }

                            if tts.len() >= 2 {
                                if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, tts: ref inner_tts }) = tts[1] {
                                    return match list_of_nested_meta_items_from_tokens(vec![], inner_tts) {
                                        Some(nested_meta_items) => {
                                            Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::List(nested_meta_items)), &tts[2..]))
                                        }

                                        None => None
                                    };
                                }
                            }

                            Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::Word), &tts[1..]))
                        }

                        _ => None
                    }
                }

                fn list_of_nested_meta_items_from_tokens(mut result: Vec<NestedMetaItem>, tts: &[TokenTree]) -> Option<Vec<NestedMetaItem>> {
                    if tts.is_empty() {
                        return Some(result);
                    }

                    match nested_meta_item_from_tokens(tts) {
                        Some((nested_meta_item, rest)) => {
                            result.push(nested_meta_item);
                            if rest.is_empty() {
                                list_of_nested_meta_items_from_tokens(result, rest)
                            }
                            else {
                                if let TokenTree::Token(Token::Comma) = rest[0] {
                                    list_of_nested_meta_items_from_tokens(result, &rest[1..])
                                }
                                else {
                                   None
                                }
                            }
                        }

                        None => None
                    }
                }

                if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(vec![], tts) {
                    return Some(MetaItem::List(nested_meta_items));
                }
            }
        }

        if self.tts.len() == 2 {
            match (&self.tts[0], &self.tts[1]) {
                (&TokenTree::Token(Token::Eq), &TokenTree::Token(Token::Literal(ref lit))) => {
                    return Some(MetaItem::NameValue(lit.clone()));
                }

                _ => {}
            }
        }

        None
    }
}

/// Distinguishes between Attributes that decorate items and Attributes that
/// are contained as statements within items. These two cases need to be
/// distinguished for pretty-printing.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum AttrStyle {
    /// Attribute of the form `#![...]`.
    Outer,

    /// Attribute of the form `#[...]`.
    Inner,
}

/// A compile-time attribute item.
///
/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum MetaItem {
    /// Word meta item.
    ///
    /// E.g. `test` as in `#[test]`
    Word,

    /// List meta item.
    ///
    /// E.g. `derive(..)` as in `#[derive(..)]`
    List(Vec<NestedMetaItem>),

    /// Name-value meta item.
    ///
    /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
    NameValue(Lit),
}

/// Possible values inside of compile-time attribute lists.
///
/// E.g. the '..' in `#[name(..)]`.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum NestedMetaItem {
    /// A full `MetaItem`.
    ///
    /// E.g. `Copy` in `#[derive(Copy)]` would be a `(Ident::from("Copy"), MetaItem::Word)`.
    MetaItem(Ident, MetaItem),

    /// A Rust literal.
    ///
    /// E.g. `"name"` in `#[rename("name")]`.
    Literal(Lit),
}

pub trait FilterAttrs<'a> {
    type Ret: Iterator<Item = &'a Attribute>;

    fn outer(self) -> Self::Ret;
    fn inner(self) -> Self::Ret;
}

impl<'a, T> FilterAttrs<'a> for T
    where T: IntoIterator<Item = &'a Attribute>
{
    type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;

    fn outer(self) -> Self::Ret {
        fn is_outer(attr: &&Attribute) -> bool {
            attr.style == AttrStyle::Outer
        }
        self.into_iter().filter(is_outer)
    }

    fn inner(self) -> Self::Ret {
        fn is_inner(attr: &&Attribute) -> bool {
            attr.style == AttrStyle::Inner
        }
        self.into_iter().filter(is_inner)
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use ident::parsing::ident;
    use lit::{Lit, StrStyle};
    use mac::{Token, TokenTree};
    use mac::parsing::token_trees;
    use synom::space::{block_comment, whitespace};

    #[cfg(feature = "full")]
    named!(pub inner_attr -> Attribute, alt!(
        do_parse!(
            punct!("#") >>
            punct!("!") >>
            name_and_tts: delimited!(
                punct!("["),
                tuple!(ident, token_trees),
                punct!("]")
            ) >>
            ({
                let (name, tts) = name_and_tts;

                Attribute {
                    style: AttrStyle::Inner,
                    name: name,
                    tts: tts,
                    is_sugared_doc: false,
                }
            })
        )
        |
        do_parse!(
            punct!("//!") >>
            content: take_until!("\n") >>
            (Attribute {
                style: AttrStyle::Inner,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(format!("//!{}", content).into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tag!("/*!")) >>
            com: block_comment >>
            (Attribute {
                style: AttrStyle::Inner,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
    ));

    named!(pub outer_attr -> Attribute, alt!(
        do_parse!(
            punct!("#") >>
            name_and_tts: delimited!(
                punct!("["),
                tuple!(ident, token_trees),
                punct!("]")
            ) >>
            ({
                let (name, tts) = name_and_tts;

                Attribute {
                    style: AttrStyle::Outer,
                    name: name,
                    tts: tts,
                    is_sugared_doc: false,
                }
            })
        )
        |
        do_parse!(
            punct!("///") >>
            not!(tag!("/")) >>
            content: take_until!("\n") >>
            (Attribute {
                style: AttrStyle::Outer,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(format!("///{}", content).into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
            com: block_comment >>
            (Attribute {
                style: AttrStyle::Outer,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use lit::{Lit, StrStyle};
    use mac::{Token, TokenTree};
    use quote::{Tokens, ToTokens};

    impl ToTokens for Attribute {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if let Attribute { style, ref name, ref tts, is_sugared_doc: true } = *self {
                if name == "doc" && tts.len() == 2 {
                    match (&tts[0], &tts[1]) {
                        (&TokenTree::Token(Token::Eq),
                         &TokenTree::Token(Token::Literal(Lit::Str(ref value, StrStyle::Cooked)))) => {
                            match style {
                                AttrStyle::Inner if value.starts_with("//!") => {
                                    tokens.append(&format!("{}\n", value));
                                    return;
                                }
                                AttrStyle::Inner if value.starts_with("/*!") => {
                                    tokens.append(value);
                                    return;
                                }
                                AttrStyle::Outer if value.starts_with("///") => {
                                    tokens.append(&format!("{}\n", value));
                                    return;
                                }
                                AttrStyle::Outer if value.starts_with("/**") => {
                                    tokens.append(value);
                                    return;
                                }
                                _ => {}
                            }
                        }

                        _ => {}
                    }
                }
            }

            tokens.append("#");
            if let AttrStyle::Inner = self.style {
                tokens.append("!");
            }
            tokens.append("[");
            self.name.to_tokens(tokens);
            tokens.append_all(&self.tts);
            tokens.append("]");
        }
    }

    impl ToTokens for MetaItem {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                MetaItem::Word => {}
                MetaItem::List(ref inner) => {
                    tokens.append("(");
                    tokens.append_separated(inner, ",");
                    tokens.append(")");
                }
                MetaItem::NameValue(ref value) => {
                    tokens.append("=");
                    value.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for NestedMetaItem {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                NestedMetaItem::MetaItem(ref ident, ref nested) => {
                    ident.to_tokens(tokens);
                    nested.to_tokens(tokens);
                }
                NestedMetaItem::Literal(ref lit) => {
                    lit.to_tokens(tokens);
                }
            }
        }
    }
}
<commit_msg>fixup! Satisfy clippy<commit_after>use super::*;

use std::iter;

/// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Attribute {
    pub style: AttrStyle,
    pub name: Ident,
    pub tts: Vec<TokenTree>,
    pub is_sugared_doc: bool,
}

impl Attribute {
    pub fn meta_item(&self) -> Option<MetaItem> {
        if self.tts.is_empty() {
            return Some(MetaItem::Word);
        }

        if self.tts.len() == 1 {
            if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, ref tts }) = self.tts[0] {
                fn nested_meta_item_from_tokens(tts: &[TokenTree]) -> Option<(NestedMetaItem, &[TokenTree])> {
                    assert!(!tts.is_empty());

                    match tts[0] {
                        TokenTree::Token(Token::Literal(ref lit)) => {
                            Some((NestedMetaItem::Literal(lit.clone()), &tts[1..]))
                        }

                        TokenTree::Token(Token::Ident(ref ident)) => {
                            if tts.len() >= 3 {
                                match (&tts[1], &tts[2]) {
                                    (&TokenTree::Token(Token::Eq), &TokenTree::Token(Token::Literal(ref lit))) => {
                                        return Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::NameValue(lit.clone())), &tts[3..]));
                                    }

                                    _ => {}
                                }
                            }

                            if tts.len() >= 2 {
                                if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, tts: ref inner_tts }) = tts[1] {
                                    return match list_of_nested_meta_items_from_tokens(vec![], inner_tts) {
                                        Some(nested_meta_items) => {
                                            Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::List(nested_meta_items)), &tts[2..]))
                                        }

                                        None => None
                                    };
                                }
                            }

                            Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::Word), &tts[1..]))
                        }

                        _ => None
                    }
                }

                fn list_of_nested_meta_items_from_tokens(mut result: Vec<NestedMetaItem>, tts: &[TokenTree]) -> Option<Vec<NestedMetaItem>> {
                    if tts.is_empty() {
                        return Some(result);
                    }

                    match nested_meta_item_from_tokens(tts) {
                        Some((nested_meta_item, rest)) => {
                            result.push(nested_meta_item);
                            if rest.is_empty() {
                                list_of_nested_meta_items_from_tokens(result, rest)
                            }
                            else if let TokenTree::Token(Token::Comma) = rest[0] {
                                list_of_nested_meta_items_from_tokens(result, &rest[1..])
                            }
                            else {
                                None
                            }
                        }

                        None => None
                    }
                }

                if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(vec![], tts) {
                    return Some(MetaItem::List(nested_meta_items));
                }
            }
        }

        if self.tts.len() == 2 {
            match (&self.tts[0], &self.tts[1]) {
                (&TokenTree::Token(Token::Eq), &TokenTree::Token(Token::Literal(ref lit))) => {
                    return Some(MetaItem::NameValue(lit.clone()));
                }

                _ => {}
            }
        }

        None
    }
}

/// Distinguishes between Attributes that decorate items and Attributes that
/// are contained as statements within items. These two cases need to be
/// distinguished for pretty-printing.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum AttrStyle {
    /// Attribute of the form `#![...]`.
    Outer,

    /// Attribute of the form `#[...]`.
    Inner,
}

/// A compile-time attribute item.
///
/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum MetaItem {
    /// Word meta item.
    ///
    /// E.g. `test` as in `#[test]`
    Word,

    /// List meta item.
    ///
    /// E.g. `derive(..)` as in `#[derive(..)]`
    List(Vec<NestedMetaItem>),

    /// Name-value meta item.
    ///
    /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
    NameValue(Lit),
}

/// Possible values inside of compile-time attribute lists.
///
/// E.g. the '..' in `#[name(..)]`.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum NestedMetaItem {
    /// A full `MetaItem`.
    ///
    /// E.g. `Copy` in `#[derive(Copy)]` would be a `(Ident::from("Copy"), MetaItem::Word)`.
    MetaItem(Ident, MetaItem),

    /// A Rust literal.
    ///
    /// E.g. `"name"` in `#[rename("name")]`.
    Literal(Lit),
}

pub trait FilterAttrs<'a> {
    type Ret: Iterator<Item = &'a Attribute>;

    fn outer(self) -> Self::Ret;
    fn inner(self) -> Self::Ret;
}

impl<'a, T> FilterAttrs<'a> for T
    where T: IntoIterator<Item = &'a Attribute>
{
    type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;

    fn outer(self) -> Self::Ret {
        fn is_outer(attr: &&Attribute) -> bool {
            attr.style == AttrStyle::Outer
        }
        self.into_iter().filter(is_outer)
    }

    fn inner(self) -> Self::Ret {
        fn is_inner(attr: &&Attribute) -> bool {
            attr.style == AttrStyle::Inner
        }
        self.into_iter().filter(is_inner)
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use ident::parsing::ident;
    use lit::{Lit, StrStyle};
    use mac::{Token, TokenTree};
    use mac::parsing::token_trees;
    use synom::space::{block_comment, whitespace};

    #[cfg(feature = "full")]
    named!(pub inner_attr -> Attribute, alt!(
        do_parse!(
            punct!("#") >>
            punct!("!") >>
            name_and_tts: delimited!(
                punct!("["),
                tuple!(ident, token_trees),
                punct!("]")
            ) >>
            ({
                let (name, tts) = name_and_tts;

                Attribute {
                    style: AttrStyle::Inner,
                    name: name,
                    tts: tts,
                    is_sugared_doc: false,
                }
            })
        )
        |
        do_parse!(
            punct!("//!") >>
            content: take_until!("\n") >>
            (Attribute {
                style: AttrStyle::Inner,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(format!("//!{}", content).into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tag!("/*!")) >>
            com: block_comment >>
            (Attribute {
                style: AttrStyle::Inner,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
    ));

    named!(pub outer_attr -> Attribute, alt!(
        do_parse!(
            punct!("#") >>
            name_and_tts: delimited!(
                punct!("["),
                tuple!(ident, token_trees),
                punct!("]")
            ) >>
            ({
                let (name, tts) = name_and_tts;

                Attribute {
                    style: AttrStyle::Outer,
                    name: name,
                    tts: tts,
                    is_sugared_doc: false,
                }
            })
        )
        |
        do_parse!(
            punct!("///") >>
            not!(tag!("/")) >>
            content: take_until!("\n") >>
            (Attribute {
                style: AttrStyle::Outer,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(format!("///{}", content).into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
            com: block_comment >>
            (Attribute {
                style: AttrStyle::Outer,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use lit::{Lit, StrStyle};
    use mac::{Token, TokenTree};
    use quote::{Tokens, ToTokens};

    impl ToTokens for Attribute {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if let Attribute { style, ref name, ref tts, is_sugared_doc: true } = *self {
                if name == "doc" && tts.len() == 2 {
                    match (&tts[0], &tts[1]) {
                        (&TokenTree::Token(Token::Eq),
                         &TokenTree::Token(Token::Literal(Lit::Str(ref value, StrStyle::Cooked)))) => {
                            match style {
                                AttrStyle::Inner if value.starts_with("//!") => {
                                    tokens.append(&format!("{}\n", value));
                                    return;
                                }
                                AttrStyle::Inner if value.starts_with("/*!") => {
                                    tokens.append(value);
                                    return;
                                }
                                AttrStyle::Outer if value.starts_with("///") => {
                                    tokens.append(&format!("{}\n", value));
                                    return;
                                }
                                AttrStyle::Outer if value.starts_with("/**") => {
                                    tokens.append(value);
                                    return;
                                }
                                _ => {}
                            }
                        }

                        _ => {}
                    }
                }
            }

            tokens.append("#");
            if let AttrStyle::Inner = self.style {
                tokens.append("!");
            }
            tokens.append("[");
            self.name.to_tokens(tokens);
            tokens.append_all(&self.tts);
            tokens.append("]");
        }
    }

    impl ToTokens for MetaItem {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                MetaItem::Word => {}
                MetaItem::List(ref inner) => {
                    tokens.append("(");
                    tokens.append_separated(inner, ",");
                    tokens.append(")");
                }
                MetaItem::NameValue(ref value) => {
                    tokens.append("=");
                    value.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for NestedMetaItem {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                NestedMetaItem::MetaItem(ref ident, ref nested) => {
                    ident.to_tokens(tokens);
                    nested.to_tokens(tokens);
                }
                NestedMetaItem::Literal(ref lit) => {
                    lit.to_tokens(tokens);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Solver configuration, contains backend-solver-specific info.
//!
//! Do **NOT** use wildcards when matching over `SmtStyle`. We want the code to fail to compile
//! whenever we add a solver. Likewise, do not use `if let` with `SmtStyle`.

use std::fmt;

use crate::{SmtRes, Solver};

use self::SmtStyle::*;

/// A configuration item is either a keyword or unsupported.
pub type ConfItem = Option<&'static str>;

/// Value of an unsupported configuration item.
#[inline]
fn unsupported() -> ConfItem {
    None
}
/// Keyword for a configuration item.
#[inline]
fn supported(keyword: &'static str) -> ConfItem {
    Some(keyword)
}

/// Solver styles.
///
/// - [z3][z3]: full support
/// - [cvc4][cvc4]: full support in theory, but only partially tested. Note that `get-value` is
///   known to crash some versions of CVC4.
/// - [yices 2][yices 2]: full support in theory, but only partially tested. Command `get-model`
///   will only work on Yices 2 > `2.6.1`, and needs to be activated in [SmtConf][SmtConf] with
///   [`conf.models()`](struct.SmtConf.html#method.models). To understand why, see
///   <https://github.com/SRI-CSL/yices2/issues/162>.
///
/// [z3]: https://github.com/Z3Prover/z3 (z3 github repository)
/// [cvc4]: https://cvc4.github.io/ (cvc4 github pages)
/// [yices 2]: https://yices.csl.sri.com/ (yices 2 official page)
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub enum SmtStyle {
    /// Z3-style smt solver.
    Z3,
    /// CVC4-style smt solver.
    ///
    /// **NB**: CVC4 has only been partially tested at this point.
    CVC4,
    /// Yices-2-style smt solver.
    ///
    /// Yices 2 has only been partially tested at this point.
    Yices2,
}

impl SmtStyle {
    /// Default configuration for a solver style.
    pub fn default(self) -> SmtConf {
        let cmd = self.cmd();
        match self {
            Z3 => SmtConf {
                style: self,
                cmd,
                options: vec!["-in".into(), "-smt2".into()],
                models: true,
                incremental: true,
                parse_success: false,
                unsat_cores: false,
                check_sat_assuming: supported("check-sat-assuming"),
            },
            CVC4 => SmtConf {
                style: self,
                cmd,
                options: vec![
                    "-q".into(),
                    "--no-interactive".into(),
                    "--lang".into(),
                    "smt2".into(),
                ],
                models: false,
                incremental: false,
                parse_success: false,
                unsat_cores: false,
                check_sat_assuming: unsupported(),
            },
            Yices2 => SmtConf {
                style: self,
                cmd,
                options: vec![],
                models: false,
                incremental: false,
                parse_success: false,
                unsat_cores: false,
                check_sat_assuming: supported("check-sat-assuming"),
            },
        }
    }

    /// A solver style from a string.
    #[allow(dead_code)]
    pub fn of_str(s: &str) -> Option<Self> {
        match s {
            "z3" | "Z3" => Some(Z3),
            "cvc4" | "CVC4" => Some(CVC4),
            "Yices2" | "yices2" | "YICES2" | "Yices 2" | "yices 2" | "YICES 2" => Some(CVC4),
            _ => None,
        }
    }
    /// Legal string representations of solver styles.
    #[allow(dead_code)]
    pub fn str_keys() -> Vec<&'static str> {
        vec![
            "z3", "Z3", "cvc4", "CVC4", "Yices2", "yices2", "YICES2", "Yices 2", "yices 2",
            "YICES 2",
        ]
    }

    /// Default command for a solver style.
    #[cfg(not(windows))]
    pub fn cmd(self) -> String {
        match self {
            Z3 => "z3".to_string(),
            CVC4 => "cvc4".to_string(),
            Yices2 => "yices-smt2".to_string(),
        }
    }
    /// Default command for a solver style.
    #[cfg(windows)]
    pub fn cmd(self) -> String {
        match self {
            Z3 => "z3.exe".to_string(),
            CVC4 => "cvc4.exe".to_string(),
            Yices2 => "yices-smt2.exe".to_string(),
        }
    }
}

impl fmt::Display for SmtStyle {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Z3 => write!(fmt, "z3"),
            CVC4 => write!(fmt, "cvc4"),
            Yices2 => write!(fmt, "yices2"),
        }
    }
}

/// Configuration and solver specific info.
///
/// - [z3][z3]: full support
/// - [cvc4][cvc4]: full support in theory, but only partially tested. Note that `get-value` is
///   known to crash some versions of CVC4.
/// - [yices 2][yices 2]: full support in theory, but only partially tested. Command `get-model`
///   will only work on Yices 2 > `2.6.1`, and needs to be activated in [SmtConf][SmtConf] with
///   [`conf.models()`](struct.SmtConf.html#method.models). To understand why, see
///   <https://github.com/SRI-CSL/yices2/issues/162>.
///
/// [z3]: https://github.com/Z3Prover/z3 (z3 github repository)
/// [cvc4]: https://cvc4.github.io/ (cvc4 github pages)
/// [yices 2]: https://yices.csl.sri.com/ (yices 2 official page)
#[derive(Debug, Clone)]
pub struct SmtConf {
    /// Solver style.
    style: SmtStyle,
    /// Solver command.
    cmd: String,
    /// Options to call the solver with.
    options: Vec<String>,
    /// Model production.
    models: bool,
    /// Incrementality.
    incremental: bool,
    /// Parse success.
    parse_success: bool,
    /// Triggers unsat-core production.
    unsat_cores: bool,
    /// Keyword for check-sat with assumptions.
    check_sat_assuming: ConfItem,
}

impl SmtConf {
    /// Creates a new z3-like solver configuration.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let conf = SmtConf::z3();
    /// assert! {
    ///     conf.get_cmd() == "z3" || conf.get_cmd() == "z3.exe"
    /// }
    /// ```
    #[inline]
    pub fn z3() -> Self {
        Z3.default()
    }

    /// Creates a new cvc4-like solver configuration.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let conf = SmtConf::cvc4();
    /// assert! {
    ///     conf.get_cmd() == "cvc4" || conf.get_cmd() == "cvc4.exe"
    /// }
    /// ```
    #[inline]
    pub fn cvc4() -> Self {
        CVC4.default()
    }

    /// Creates a new yices-2-like solver configuration.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let conf = SmtConf::yices_2();
    /// assert! {
    ///     conf.get_cmd() == "yices-smt2" || conf.get_cmd() == "yices-smt2.exe"
    /// }
    /// ```
    #[inline]
    pub fn yices_2() -> Self {
        Yices2.default()
    }

    /// Spawns the solver.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let _solver = SmtConf::z3().spawn(()).unwrap();
    /// ```
    #[inline]
    pub fn spawn<Parser>(self, parser: Parser) -> SmtRes<Solver<Parser>> {
        Solver::new(self, parser)
    }

    /// Concise description of the underlying solver.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// assert_eq! { SmtConf::z3().desc(), "z3" }
    /// ```
    #[inline]
    pub fn desc(&self) -> &str {
        match self.style {
            Z3 => "z3",
            CVC4 => "cvc4",
            Yices2 => "yices2",
        }
    }

    /// Model production flag.
    pub fn get_models(&self) -> bool {
        self.models
    }
    /// Activates model production.
    pub fn models(&mut self) {
        if self.models {
            return ();
        } else {
            self.models = true
        }
        match self.style {
            CVC4 => self.options.push("--produce-models".into()),
            Yices2 => self.options.push("--smt2-model-format".into()),
            Z3 => (),
        }
    }

    /// Incrementality.
    pub fn get_incremental(&self) -> bool {
        self.incremental
    }
    /// Activates incrementality (push/pop, check-sat-assuming).
    pub fn incremental(&mut self) {
        if self.incremental {
            return ();
        } else {
            self.incremental = true
        }
        match self.style {
            CVC4 | Yices2 => self.options.push("--incremental".into()),
            Z3 => (),
        }
    }

    /// Solver command.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let conf = SmtConf::z3();
    /// assert! {
    ///     conf.get_cmd() == "z3" || conf.get_cmd() == "z3.exe"
    /// }
    /// ```
    #[inline]
    pub fn get_cmd(&self) -> &str {
        &self.cmd
    }

    /// Options of the configuration.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// assert_eq! {
    ///     SmtConf::z3().get_options(), & [ "-in", "-smt2" ]
    /// }
    /// ```
    #[inline]
    pub fn get_options(&self) -> &[String] {
        &self.options
    }

    /// Indicates if print success is active.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// assert! { ! SmtConf::z3().get_print_success() }
    /// ```
    #[inline]
    pub fn get_print_success(&self) -> bool {
        self.parse_success
    }

    /// Indicates if unsat cores is active.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// assert! { ! SmtConf::z3().get_unsat_cores() }
    /// ```
    #[inline]
    pub fn get_unsat_cores(&self) -> bool {
        self.unsat_cores
    }

    /// Keyword for check-sat with assumptions.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// assert_eq! {
    ///     SmtConf::z3().get_check_sat_assuming(), Some("check-sat-assuming")
    /// }
    /// ```
    #[inline]
    pub fn get_check_sat_assuming(&self) -> ConfItem {
        self.check_sat_assuming.as_ref().map(|s| *s)
    }

    /// Adds an option to the configuration.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let mut conf = SmtConf::z3();
    /// conf.option("arith.euclidean_solver=true");
    /// assert_eq! {
    ///     conf.get_options(),
    ///     & [ "-in", "-smt2", "arith.euclidean_solver=true" ]
    /// }
    /// ```
    #[inline]
    pub fn option<S: Into<String>>(&mut self, o: S) -> &mut Self {
        self.options.push(o.into());
        self
    }

    /// Sets the command for the solver.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let mut conf = SmtConf::z3();
    /// conf.cmd("my_custom_z3_command");
    /// assert_eq! { conf.get_cmd(), "my_custom_z3_command" }
    /// ```
    #[inline]
    pub fn cmd<S: Into<String>>(&mut self, cmd: S) -> &mut Self {
        let cmd = cmd.into();
        let mut iter = cmd.split(' ');

        'set_cmd: while let Some(cmd) = iter.next() {
            if !cmd.is_empty() {
                self.cmd = cmd.into();
                break 'set_cmd;
            }
        }

        for option in iter {
            if !option.is_empty() {
                self.options.push(option.into())
            }
        }

        self
    }

    /// Activates parse sucess.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let mut conf = SmtConf::z3();
    /// conf.print_success();
    /// assert! { conf.get_print_success() }
    /// ```
    #[inline]
    #[cfg(not(no_parse_success))]
    pub fn print_success(&mut self) {
        self.parse_success = true
    }

    /// Activates unsat-core production.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let mut conf = SmtConf::z3();
    /// conf.unsat_cores();
    /// assert! { conf.get_unsat_cores() }
    /// ```
    #[inline]
    pub fn unsat_cores(&mut self) {
        self.unsat_cores = true
    }
}

/// ## Solver-specific error-handling
impl SmtConf {
    /// Adds information to a `get-value` error message if needed.
    pub fn enrich_get_values_error(&self, e: crate::errors::Error) -> crate::errors::Error {
        match self.style {
            SmtStyle::CVC4 => e.chain_err(|| {
                "some versions of CVC4 produce errors on `get-value` commands, \
                 consider using `get-model` instead"
            }),
            SmtStyle::Z3 | SmtStyle::Yices2 => e,
        }
    }
}
<commit_msg>changed default yices 2 binary name<commit_after>//! Solver configuration, contains backend-solver-specific info.
//!
//! Do **NOT** use wildcards when matching over `SmtStyle`. We want the code to fail to compile
//! whenever we add a solver. Likewise, do not use `if let` with `SmtStyle`.

use std::fmt;

use crate::{SmtRes, Solver};

use self::SmtStyle::*;

/// A configuration item is either a keyword or unsupported.
pub type ConfItem = Option<&'static str>;

/// Value of an unsupported configuration item.
#[inline]
fn unsupported() -> ConfItem {
    None
}
/// Keyword for a configuration item.
#[inline]
fn supported(keyword: &'static str) -> ConfItem {
    Some(keyword)
}

/// Solver styles.
///
/// - [z3][z3]: full support
/// - [cvc4][cvc4]: full support in theory, but only partially tested. Note that `get-value` is
///   known to crash some versions of CVC4.
/// - [yices 2][yices 2]: full support in theory, but only partially tested. Command `get-model`
///   will only work on Yices 2 > `2.6.1`, and needs to be activated in [SmtConf][SmtConf] with
///   [`conf.models()`](struct.SmtConf.html#method.models). To understand why, see
///   <https://github.com/SRI-CSL/yices2/issues/162>.
///
/// [z3]: https://github.com/Z3Prover/z3 (z3 github repository)
/// [cvc4]: https://cvc4.github.io/ (cvc4 github pages)
/// [yices 2]: https://yices.csl.sri.com/ (yices 2 official page)
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub enum SmtStyle {
    /// Z3-style smt solver.
    Z3,
    /// CVC4-style smt solver.
    ///
    /// **NB**: CVC4 has only been partially tested at this point.
    CVC4,
    /// Yices-2-style smt solver.
    ///
    /// Yices 2 has only been partially tested at this point.
    Yices2,
}

impl SmtStyle {
    /// Default configuration for a solver style.
    pub fn default(self) -> SmtConf {
        let cmd = self.cmd();
        match self {
            Z3 => SmtConf {
                style: self,
                cmd,
                options: vec!["-in".into(), "-smt2".into()],
                models: true,
                incremental: true,
                parse_success: false,
                unsat_cores: false,
                check_sat_assuming: supported("check-sat-assuming"),
            },
            CVC4 => SmtConf {
                style: self,
                cmd,
                options: vec![
                    "-q".into(),
                    "--no-interactive".into(),
                    "--lang".into(),
                    "smt2".into(),
                ],
                models: false,
                incremental: false,
                parse_success: false,
                unsat_cores: false,
                check_sat_assuming: unsupported(),
            },
            Yices2 => SmtConf {
                style: self,
                cmd,
                options: vec![],
                models: false,
                incremental: false,
                parse_success: false,
                unsat_cores: false,
                check_sat_assuming: supported("check-sat-assuming"),
            },
        }
    }

    /// A solver style from a string.
    #[allow(dead_code)]
    pub fn of_str(s: &str) -> Option<Self> {
        match s {
            "z3" | "Z3" => Some(Z3),
            "cvc4" | "CVC4" => Some(CVC4),
            "Yices2" | "yices2" | "YICES2" | "Yices 2" | "yices 2" | "YICES 2" => Some(CVC4),
            _ => None,
        }
    }
    /// Legal string representations of solver styles.
    #[allow(dead_code)]
    pub fn str_keys() -> Vec<&'static str> {
        vec![
            "z3", "Z3", "cvc4", "CVC4", "Yices2", "yices2", "YICES2", "Yices 2", "yices 2",
            "YICES 2",
        ]
    }

    /// Default command for a solver style.
    #[cfg(not(windows))]
    pub fn cmd(self) -> String {
        match self {
            Z3 => "z3".to_string(),
            CVC4 => "cvc4".to_string(),
            Yices2 => "yices".to_string(),
        }
    }
    /// Default command for a solver style.
    #[cfg(windows)]
    pub fn cmd(self) -> String {
        match self {
            Z3 => "z3.exe".to_string(),
            CVC4 => "cvc4.exe".to_string(),
            Yices2 => "yices.exe".to_string(),
        }
    }
}

impl fmt::Display for SmtStyle {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Z3 => write!(fmt, "z3"),
            CVC4 => write!(fmt, "cvc4"),
            Yices2 => write!(fmt, "yices2"),
        }
    }
}

/// Configuration and solver specific info.
///
/// - [z3][z3]: full support
/// - [cvc4][cvc4]: full support in theory, but only partially tested. Note that `get-value` is
///   known to crash some versions of CVC4.
/// - [yices 2][yices 2]: full support in theory, but only partially tested. Command `get-model`
///   will only work on Yices 2 > `2.6.1`, and needs to be activated in [SmtConf][SmtConf] with
///   [`conf.models()`](struct.SmtConf.html#method.models). To understand why, see
///   <https://github.com/SRI-CSL/yices2/issues/162>.
///
/// [z3]: https://github.com/Z3Prover/z3 (z3 github repository)
/// [cvc4]: https://cvc4.github.io/ (cvc4 github pages)
/// [yices 2]: https://yices.csl.sri.com/ (yices 2 official page)
#[derive(Debug, Clone)]
pub struct SmtConf {
    /// Solver style.
    style: SmtStyle,
    /// Solver command.
    cmd: String,
    /// Options to call the solver with.
    options: Vec<String>,
    /// Model production.
    models: bool,
    /// Incrementality.
    incremental: bool,
    /// Parse success.
    parse_success: bool,
    /// Triggers unsat-core production.
    unsat_cores: bool,
    /// Keyword for check-sat with assumptions.
    check_sat_assuming: ConfItem,
}

impl SmtConf {
    /// Creates a new z3-like solver configuration.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let conf = SmtConf::z3();
    /// assert! {
    ///     conf.get_cmd() == "z3" || conf.get_cmd() == "z3.exe"
    /// }
    /// ```
    #[inline]
    pub fn z3() -> Self {
        Z3.default()
    }

    /// Creates a new cvc4-like solver configuration.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let conf = SmtConf::cvc4();
    /// assert! {
    ///     conf.get_cmd() == "cvc4" || conf.get_cmd() == "cvc4.exe"
    /// }
    /// ```
    #[inline]
    pub fn cvc4() -> Self {
        CVC4.default()
    }

    /// Creates a new yices-2-like solver configuration.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let conf = SmtConf::yices_2();
    /// assert! {
    ///     conf.get_cmd() == "yices" || conf.get_cmd() == "yices.exe"
    /// }
    /// ```
    #[inline]
    pub fn yices_2() -> Self {
        Yices2.default()
    }

    /// Spawns the solver.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let _solver = SmtConf::z3().spawn(()).unwrap();
    /// ```
    #[inline]
    pub fn spawn<Parser>(self, parser: Parser) -> SmtRes<Solver<Parser>> {
        Solver::new(self, parser)
    }

    /// Concise description of the underlying solver.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// assert_eq! { SmtConf::z3().desc(), "z3" }
    /// ```
    #[inline]
    pub fn desc(&self) -> &str {
        match self.style {
            Z3 => "z3",
            CVC4 => "cvc4",
            Yices2 => "yices2",
        }
    }

    /// Model production flag.
    pub fn get_models(&self) -> bool {
        self.models
    }
    /// Activates model production.
    pub fn models(&mut self) {
        if self.models {
            return ();
        } else {
            self.models = true
        }
        match self.style {
            CVC4 => self.options.push("--produce-models".into()),
            Yices2 => self.options.push("--smt2-model-format".into()),
            Z3 => (),
        }
    }

    /// Incrementality.
    pub fn get_incremental(&self) -> bool {
        self.incremental
    }
    /// Activates incrementality (push/pop, check-sat-assuming).
    pub fn incremental(&mut self) {
        if self.incremental {
            return ();
        } else {
            self.incremental = true
        }
        match self.style {
            CVC4 | Yices2 => self.options.push("--incremental".into()),
            Z3 => (),
        }
    }

    /// Solver command.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let conf = SmtConf::z3();
    /// assert! {
    ///     conf.get_cmd() == "z3" || conf.get_cmd() == "z3.exe"
    /// }
    /// ```
    #[inline]
    pub fn get_cmd(&self) -> &str {
        &self.cmd
    }

    /// Options of the configuration.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// assert_eq! {
    ///     SmtConf::z3().get_options(), & [ "-in", "-smt2" ]
    /// }
    /// ```
    #[inline]
    pub fn get_options(&self) -> &[String] {
        &self.options
    }

    /// Indicates if print success is active.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// assert! { ! SmtConf::z3().get_print_success() }
    /// ```
    #[inline]
    pub fn get_print_success(&self) -> bool {
        self.parse_success
    }

    /// Indicates if unsat cores is active.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// assert! { ! SmtConf::z3().get_unsat_cores() }
    /// ```
    #[inline]
    pub fn get_unsat_cores(&self) -> bool {
        self.unsat_cores
    }

    /// Keyword for check-sat with assumptions.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// assert_eq! {
    ///     SmtConf::z3().get_check_sat_assuming(), Some("check-sat-assuming")
    /// }
    /// ```
    #[inline]
    pub fn get_check_sat_assuming(&self) -> ConfItem {
        self.check_sat_assuming.as_ref().map(|s| *s)
    }

    /// Adds an option to the configuration.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let mut conf = SmtConf::z3();
    /// conf.option("arith.euclidean_solver=true");
    /// assert_eq! {
    ///     conf.get_options(),
    ///     & [ "-in", "-smt2", "arith.euclidean_solver=true" ]
    /// }
    /// ```
    #[inline]
    pub fn option<S: Into<String>>(&mut self, o: S) -> &mut Self {
        self.options.push(o.into());
        self
    }

    /// Sets the command for the solver.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let mut conf = SmtConf::z3();
    /// conf.cmd("my_custom_z3_command");
    /// assert_eq! { conf.get_cmd(), "my_custom_z3_command" }
    /// ```
    #[inline]
    pub fn cmd<S: Into<String>>(&mut self, cmd: S) -> &mut Self {
        let cmd = cmd.into();
        let mut iter = cmd.split(' ');

        'set_cmd: while let Some(cmd) = iter.next() {
            if !cmd.is_empty() {
                self.cmd = cmd.into();
                break 'set_cmd;
            }
        }

        for option in iter {
            if !option.is_empty() {
                self.options.push(option.into())
            }
        }

        self
    }

    /// Activates parse sucess.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let mut conf = SmtConf::z3();
    /// conf.print_success();
    /// assert! { conf.get_print_success() }
    /// ```
    #[inline]
    #[cfg(not(no_parse_success))]
    pub fn print_success(&mut self) {
        self.parse_success = true
    }

    /// Activates unsat-core production.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rsmt2::SmtConf;
    /// let mut conf = SmtConf::z3();
    /// conf.unsat_cores();
    /// assert! { conf.get_unsat_cores() }
    /// ```
    #[inline]
    pub fn unsat_cores(&mut self) {
        self.unsat_cores = true
    }
}

/// ## Solver-specific error-handling
impl SmtConf {
    /// Adds information to a `get-value` error message if needed.
    pub fn enrich_get_values_error(&self, e: crate::errors::Error) -> crate::errors::Error {
        match self.style {
            SmtStyle::CVC4 => e.chain_err(|| {
                "some versions of CVC4 produce errors on `get-value` commands, \
                 consider using `get-model` instead"
            }),
            SmtStyle::Z3 | SmtStyle::Yices2 => e,
        }
    }
}
<|endoftext|>


<commit_before>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86 systems and
//! provides Unix-like syscalls for primarily Rust applications
//!
//! ## Syscalls
//! Syscalls in Redox are often handled by userspace `schemes`.
//! The essential syscalls in Redox are as follows:
//!
//! ### Open
//! `open(path: &str, flags: usize) -> Result<file_descriptor: usize>`
//!
//! Open a file, providing a path as a `&str` and flags, defined elsewhere.
//!
//! Returns a number, known as a file descriptor, that is passed to other syscalls
//!
//! ### Close
//! `close(file_descriptor: usize) -> Result<()>`
//!
//! Close a file descriptor, providing the file descriptor from `open`
//!
//! Returns an error, `EBADF`, if the file descriptor was not found.
//!
//! This potential error is often ignored by userspace
//!
//! ### Duplicate
//! `dup(file_descriptor: usize) -> Result<file_descriptor: usize>`
//!
//! Duplicate a file descriptor, providing the file descriptor from `open`
//!
//! Returns a new file descriptor, or an error
//!
//! ### Read
//! `read(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read from a file descriptor, providing the file descriptor from `open` and a mutable buffer
//!
//! Returns the number of bytes actually read, or an error
//!
//! ### Write
//! `write(file_descriptor: usize, buffer: &[u8]) -> Result<count: usize>`
//!
//! Write to a file descriptor, providing the file descriptor from `open` and a const buffer
//!
//! Returns the number of bytes actually written, or an error
//!
//! ### Stat
//! `fstat(file_descriptor: usize, stat: &mut Stat) -> Result<()>`
//!
//! Get information from a file descriptor, providing the file descriptor from `open`
//! and a mutable Stat struct, defined elsewhere.
//!
//! Returns an error if the operation failed
//!
//! ### Path
//! `fpath(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read the path of a file descriptor, providing the file descriptor from `open` and
//! a mutable buffer.
//!
//! Returns the number of bytes actually read, or an error
//!
//! The buffer should be 4096 bytes, to ensure that the entire path will fit.
//! An error will be returned, `ENOBUFS`, if the buffer is not long enough for the name.
//! In this case, it is recommended to add one page, 4096 bytes, to the buffer and retry.

#![feature(alloc)]
#![feature(asm)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(drop_types_in_const)]
#![feature(heap_api)]
#![feature(question_mark)]
#![feature(never_type)]
#![feature(thread_local)]
#![no_std]

use arch::interrupt;

/// Architecture specific items (test)
#[cfg(test)]
#[macro_use]
extern crate arch_test as arch;

/// Architecture specific items (ARM)
#[cfg(all(not(test), target_arch = "arm"))]
#[macro_use]
extern crate arch_arm as arch;

/// Architecture specific items (x86_64)
#[cfg(all(not(test), target_arch = "x86_64"))]
#[macro_use]
extern crate arch_x86_64 as arch;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

/// Context management
pub mod context;

/// ELF file parsing
#[cfg(all(not(test), target_arch = "x86_64"))]
pub mod elf;

/// Schemes, filesystem handlers
pub mod scheme;

/// Syscall handlers
pub mod syscall;

/// Tests
#[cfg(test)]
pub mod tests;

#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

pub extern fn userspace_init() {
    assert_eq!(syscall::chdir(b"initfs:bin/"), Ok(0));

    assert_eq!(syscall::open(b"debug:", 0), Ok(0));
    assert_eq!(syscall::open(b"debug:", 0), Ok(1));
    assert_eq!(syscall::open(b"debug:", 0), Ok(2));

    syscall::exec(b"initfs:bin/init", &[]).expect("failed to execute initfs:init");

    panic!("initfs:init returned")
}

#[no_mangle]
pub extern fn kmain() {
    CPU_ID.store(0, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?}", pid);

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                interrupt::enable_and_halt();
            }
        }
    }
}

#[no_mangle]
pub extern fn kmain_ap(id: usize) {
    CPU_ID.store(id, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("AP {}: {:?}", id, pid);

    loop {
        unsafe { interrupt::enable_and_halt() }
    }
}
<commit_msg>Remove unnecessary slash<commit_after>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86 systems and
//! provides Unix-like syscalls for primarily Rust applications
//!
//! ## Syscalls
//! Syscalls in Redox are often handled by userspace `schemes`.
//! The essential syscalls in Redox are as follows:
//!
//! ### Open
//! `open(path: &str, flags: usize) -> Result<file_descriptor: usize>`
//!
//! Open a file, providing a path as a `&str` and flags, defined elsewhere.
//!
//! Returns a number, known as a file descriptor, that is passed to other syscalls
//!
//! ### Close
//! `close(file_descriptor: usize) -> Result<()>`
//!
//! Close a file descriptor, providing the file descriptor from `open`
//!
//! Returns an error, `EBADF`, if the file descriptor was not found.
//!
//! This potential error is often ignored by userspace
//!
//! ### Duplicate
//! `dup(file_descriptor: usize) -> Result<file_descriptor: usize>`
//!
//! Duplicate a file descriptor, providing the file descriptor from `open`
//!
//! Returns a new file descriptor, or an error
//!
//! ### Read
//! `read(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read from a file descriptor, providing the file descriptor from `open` and a mutable buffer
//!
//! Returns the number of bytes actually read, or an error
//!
//! ### Write
//! `write(file_descriptor: usize, buffer: &[u8]) -> Result<count: usize>`
//!
//! Write to a file descriptor, providing the file descriptor from `open` and a const buffer
//!
//! Returns the number of bytes actually written, or an error
//!
//! ### Stat
//! `fstat(file_descriptor: usize, stat: &mut Stat) -> Result<()>`
//!
//! Get information from a file descriptor, providing the file descriptor from `open`
//! and a mutable Stat struct, defined elsewhere.
//!
//! Returns an error if the operation failed
//!
//! ### Path
//! `fpath(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read the path of a file descriptor, providing the file descriptor from `open` and
//! a mutable buffer.
//!
//! Returns the number of bytes actually read, or an error
//!
//! The buffer should be 4096 bytes, to ensure that the entire path will fit.
//! An error will be returned, `ENOBUFS`, if the buffer is not long enough for the name.
//! In this case, it is recommended to add one page, 4096 bytes, to the buffer and retry.

#![feature(alloc)]
#![feature(asm)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(drop_types_in_const)]
#![feature(heap_api)]
#![feature(question_mark)]
#![feature(never_type)]
#![feature(thread_local)]
#![no_std]

use arch::interrupt;

/// Architecture specific items (test)
#[cfg(test)]
#[macro_use]
extern crate arch_test as arch;

/// Architecture specific items (ARM)
#[cfg(all(not(test), target_arch = "arm"))]
#[macro_use]
extern crate arch_arm as arch;

/// Architecture specific items (x86_64)
#[cfg(all(not(test), target_arch = "x86_64"))]
#[macro_use]
extern crate arch_x86_64 as arch;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

/// Context management
pub mod context;

/// ELF file parsing
#[cfg(all(not(test), target_arch = "x86_64"))]
pub mod elf;

/// Schemes, filesystem handlers
pub mod scheme;

/// Syscall handlers
pub mod syscall;

/// Tests
#[cfg(test)]
pub mod tests;

#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

pub extern fn userspace_init() {
    assert_eq!(syscall::chdir(b"initfs:bin"), Ok(0));

    assert_eq!(syscall::open(b"debug:", 0), Ok(0));
    assert_eq!(syscall::open(b"debug:", 0), Ok(1));
    assert_eq!(syscall::open(b"debug:", 0), Ok(2));

    syscall::exec(b"initfs:bin/init", &[]).expect("failed to execute initfs:init");

    panic!("initfs:init returned")
}

#[no_mangle]
pub extern fn kmain() {
    CPU_ID.store(0, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?}", pid);

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                interrupt::enable_and_halt();
            }
        }
    }
}

#[no_mangle]
pub extern fn kmain_ap(id: usize) {
    CPU_ID.store(id, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("AP {}: {:?}", id, pid);

    loop {
        unsafe { interrupt::enable_and_halt() }
    }
}
<|endoftext|>


<commit_before>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86 systems and
//! provides Unix-like syscalls for primarily Rust applications
//!
//! ## Syscalls
//! Syscalls in Redox are often handled by userspace `schemes`.
//! The essential syscalls in Redox are as follows:
//!
//! ### Open
//! `open(path: &str, flags: usize) -> Result<file_descriptor: usize>`
//!
//! Open a file, providing a path as a `&str` and flags, defined elsewhere.
//!
//! Returns a number, known as a file descriptor, that is passed to other syscalls
//!
//! ### Close
//! `close(file_descriptor: usize) -> Result<()>`
//!
//! Close a file descriptor, providing the file descriptor from `open`
//!
//! Returns an error, `EBADF`, if the file descriptor was not found.
//!
//! This potential error is often ignored by userspace
//!
//! ### Duplicate
//! `dup(file_descriptor: usize) -> Result<file_descriptor: usize>`
//!
//! Duplicate a file descriptor, providing the file descriptor from `open`
//!
//! Returns a new file descriptor, or an error
//!
//! ### Read
//! `read(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read from a file descriptor, providing the file descriptor from `open` and a mutable buffer
//!
//! Returns the number of bytes actually read, or an error
//!
//! ### Write
//! `write(file_descriptor: usize, buffer: &[u8]) -> Result<count: usize>`
//!
//! Write to a file descriptor, providing the file descriptor from `open` and a const buffer
//!
//! Returns the number of bytes actually written, or an error
//!
//! ### Stat
//! `fstat(file_descriptor: usize, stat: &mut Stat) -> Result<()>`
//!
//! Get information from a file descriptor, providing the file descriptor from `open`
//! and a mutable Stat struct, defined elsewhere.
//!
//! Returns an error if the operation failed
//!
//! ### Path
//! `fpath(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read the path of a file descriptor, providing the file descriptor from `open` and
//! a mutable buffer.
//!
//! Returns the number of bytes actually read, or an error
//!
//! The buffer should be 4096 bytes, to ensure that the entire path will fit.
//! An error will be returned, `ENOBUFS`, if the buffer is not long enough for the name.
//! In this case, it is recommended to add one page, 4096 bytes, to the buffer and retry.

#![feature(lang_items)]
#![no_std]

#[macro_use]
extern crate bitflags;

use arch::interrupt::{set_interrupts, halt};

/// Architecture specific items
#[macro_use]
extern crate arch;

pub mod panic;

#[no_mangle]
pub extern fn kmain() {
    println!("TEST");

    unsafe { set_interrupts() };
    loop {
        unsafe { halt() };
    }
}
<commit_msg>Add comment<commit_after>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86 systems and
//! provides Unix-like syscalls for primarily Rust applications
//!
//! ## Syscalls
//! Syscalls in Redox are often handled by userspace `schemes`.
//! The essential syscalls in Redox are as follows:
//!
//! ### Open
//! `open(path: &str, flags: usize) -> Result<file_descriptor: usize>`
//!
//! Open a file, providing a path as a `&str` and flags, defined elsewhere.
//!
//! Returns a number, known as a file descriptor, that is passed to other syscalls
//!
//! ### Close
//! `close(file_descriptor: usize) -> Result<()>`
//!
//! Close a file descriptor, providing the file descriptor from `open`
//!
//! Returns an error, `EBADF`, if the file descriptor was not found.
//!
//! This potential error is often ignored by userspace
//!
//! ### Duplicate
//! `dup(file_descriptor: usize) -> Result<file_descriptor: usize>`
//!
//! Duplicate a file descriptor, providing the file descriptor from `open`
//!
//! Returns a new file descriptor, or an error
//!
//! ### Read
//! `read(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read from a file descriptor, providing the file descriptor from `open` and a mutable buffer
//!
//! Returns the number of bytes actually read, or an error
//!
//! ### Write
//! `write(file_descriptor: usize, buffer: &[u8]) -> Result<count: usize>`
//!
//! Write to a file descriptor, providing the file descriptor from `open` and a const buffer
//!
//! Returns the number of bytes actually written, or an error
//!
//! ### Stat
//! `fstat(file_descriptor: usize, stat: &mut Stat) -> Result<()>`
//!
//! Get information from a file descriptor, providing the file descriptor from `open`
//! and a mutable Stat struct, defined elsewhere.
//!
//! Returns an error if the operation failed
//!
//! ### Path
//! `fpath(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read the path of a file descriptor, providing the file descriptor from `open` and
//! a mutable buffer.
//!
//! Returns the number of bytes actually read, or an error
//!
//! The buffer should be 4096 bytes, to ensure that the entire path will fit.
//! An error will be returned, `ENOBUFS`, if the buffer is not long enough for the name.
//! In this case, it is recommended to add one page, 4096 bytes, to the buffer and retry.

#![feature(lang_items)]
#![no_std]

#[macro_use]
extern crate bitflags;

use arch::interrupt::{set_interrupts, halt};

/// Architecture specific items
#[macro_use]
extern crate arch;

/// Intrinsics for panic handling
pub mod panic;

#[no_mangle]
pub extern fn kmain() {
    println!("TEST");

    unsafe { set_interrupts() };
    loop {
        unsafe { halt() };
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use anyhow::Result;
use clap::Parser;
use futures::executor;
use std::fs;
use sxg_rs::{fetcher::NULL_FETCHER, http_cache::NullCache, CreateSignedExchangeParams, SxgWorker};

// TODO: Make this binary generally useful, by documenting the flags and giving them names.

#[derive(Parser)]
pub struct Opts {
    config_yaml: String,
    cert_pem: String,
    issuer_pem: String,
    out_cert_cbor: String,
    out_sxg: String,
}

pub async fn main(opts: Opts) -> Result<()> {
    let worker = SxgWorker::new(
        &fs::read_to_string(opts.config_yaml).unwrap(),
        &fs::read_to_string(opts.cert_pem).unwrap(),
        &fs::read_to_string(opts.issuer_pem).unwrap(),
    )
    .unwrap();
    fs::write(opts.out_cert_cbor, &worker.create_cert_cbor(b"ocsp").await)?;
    let payload_headers = worker
        .transform_payload_headers(vec![("content-type".into(), "text/html".into())])
        .unwrap();
    let runtime = sxg_rs::runtime::Runtime {
        now: std::time::SystemTime::now(),
        sxg_signer: Box::new(worker.create_rust_signer().unwrap()),
        fetcher: Box::new(NULL_FETCHER),
        ..Default::default()
    };
    let sxg = worker.create_signed_exchange(
        &runtime,
        CreateSignedExchangeParams {
            fallback_url: "https://test.example/",
            cert_origin: "https://test.example",
            payload_body: b"This is a test.",
            payload_headers,
            skip_process_link: false,
            status_code: 200,
            header_integrity_cache: NullCache {},
        },
    );
    let sxg = executor::block_on(sxg);
    fs::write(opts.out_sxg, &sxg.unwrap().body)?;
    Ok(())
}
<commit_msg>Remove block_on in async context (#266)<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use anyhow::Result;
use clap::Parser;
use std::fs;
use sxg_rs::{fetcher::NULL_FETCHER, http_cache::NullCache, CreateSignedExchangeParams, SxgWorker};

// TODO: Make this binary generally useful, by documenting the flags and giving them names.

#[derive(Parser)]
pub struct Opts {
    config_yaml: String,
    cert_pem: String,
    issuer_pem: String,
    out_cert_cbor: String,
    out_sxg: String,
}

pub async fn main(opts: Opts) -> Result<()> {
    let worker = SxgWorker::new(
        &fs::read_to_string(opts.config_yaml).unwrap(),
        &fs::read_to_string(opts.cert_pem).unwrap(),
        &fs::read_to_string(opts.issuer_pem).unwrap(),
    )
    .unwrap();
    fs::write(opts.out_cert_cbor, &worker.create_cert_cbor(b"ocsp").await)?;
    let payload_headers = worker
        .transform_payload_headers(vec![("content-type".into(), "text/html".into())])
        .unwrap();
    let runtime = sxg_rs::runtime::Runtime {
        now: std::time::SystemTime::now(),
        sxg_signer: Box::new(worker.create_rust_signer().unwrap()),
        fetcher: Box::new(NULL_FETCHER),
        ..Default::default()
    };
    let sxg = worker.create_signed_exchange(
        &runtime,
        CreateSignedExchangeParams {
            fallback_url: "https://test.example/",
            cert_origin: "https://test.example",
            payload_body: b"This is a test.",
            payload_headers,
            skip_process_link: false,
            status_code: 200,
            header_integrity_cache: NullCache {},
        },
    );
    let sxg = sxg.await;
    fs::write(opts.out_sxg, &sxg.unwrap().body)?;
    Ok(())
}
<|endoftext|>