<commit_before>use libc;
use std::str::FromStr;
use std::cmp::{self,Ord};
use std::sync::{Mutex, Once, ONCE_INIT};
use std::cell::RefCell;
use std::fmt::{Arguments,format,write};
use std::io::{stdout,Stdout,Write};
use std::ascii::AsciiExt;
use std::net::{SocketAddr,UdpSocket};
use std::net::TcpStream;
use mio_uds::UnixDatagram;

lazy_static! {
  pub static ref LOGGER: Mutex<Logger> = Mutex::new(Logger::new());
  pub static ref PID:    i32 = unsafe { libc::getpid() };
}

pub struct Logger {
  directives: Vec<LogDirective>,
  backend:    LoggerBackend,
}

impl Logger {
  pub fn new() -> Logger {
    Logger {
      directives: vec!(LogDirective {
        name:  None,
        level: LogLevelFilter::Error,
      }),
      backend: LoggerBackend::Stdout(stdout())
    }
  }

  pub fn init(spec: &str, backend: LoggerBackend) {
    let directives = parse_logging_spec(spec);
    if let Ok(ref mut logger) = LOGGER.lock() {
      logger.set_directives(directives);
      logger.backend = backend;
    }
  }

  pub fn log<'a>(&mut self, meta: &LogMetadata, args: Arguments) {
    if self.enabled(meta) {
      match self.backend {
        LoggerBackend::Stdout(ref mut stdout) => {
          stdout.write_fmt(args);
          stdout.write(b"\n");
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Unix(ref mut socket) => {
          socket.send(format(args).as_bytes());
          socket.send(&b"\n"[..]);
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Udp(ref mut socket, ref address) => {
          socket.send_to(format(args).as_bytes(), address);
          socket.send_to(&b"\n"[..], address);
        }
        LoggerBackend::Tcp(ref mut socket) => {
          socket.write_fmt(args);
          socket.write(b"\n");
        },
      }
    }
  }

  pub fn set_directives(&mut self, directives: Vec<LogDirective>) {
    self.directives = directives;
  }

  fn enabled(&self, meta: &LogMetadata) -> bool {
    // Search for the longest match, the vector is assumed to be pre-sorted.
    for directive in self.directives.iter().rev() {
      match directive.name {
        Some(ref name) if !meta.target.starts_with(&**name) => {},
        Some(..) | None => {
          return meta.level <= directive.level
        }
      }
    }
    false
  }
}

#[derive(Debug)]
pub enum LoggerBackend {
  Stdout(Stdout),
  Unix(UnixDatagram),
  Udp(UdpSocket, SocketAddr),
  Tcp(TcpStream)
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevel {
    /// The "error" level.
    ///
    /// Designates very serious errors.
    Error = 1, // This way these line up with the discriminants for LogLevelFilter below
    /// The "warn" level.
    ///
    /// Designates hazardous situations.
    Warn,
    /// The "info" level.
    ///
    /// Designates useful information.
    Info,
    /// The "debug" level.
    ///
    /// Designates lower priority information.
    Debug,
    /// The "trace" level.
    ///
    /// Designates very low priority, often extremely verbose, information.
    Trace,
}

static LOG_LEVEL_NAMES: [&'static str; 6] = ["OFF", "ERROR", "WARN", "INFO",
                                             "DEBUG", "TRACE"];

impl Clone for LogLevel {
    #[inline]
    fn clone(&self) -> LogLevel {
        *self
    }
}

impl PartialEq for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevelFilter> for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialOrd for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevelFilter> for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some((*self as usize).cmp(&(*other as usize)))
    }
}

impl Ord for LogLevel {
    #[inline]
    fn cmp(&self, other: &LogLevel) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl LogLevel {
    fn from_usize(u: usize) -> Option<LogLevel> {
        match u {
            1 => Some(LogLevel::Error),
            2 => Some(LogLevel::Warn),
            3 => Some(LogLevel::Info),
            4 => Some(LogLevel::Debug),
            5 => Some(LogLevel::Trace),
            _ => None
        }
    }

    /// Returns the most verbose logging level.
    #[inline]
    pub fn max() -> LogLevel {
        LogLevel::Trace
    }

    /// Converts the `LogLevel` to the equivalent `LogLevelFilter`.
    #[inline]
    pub fn to_log_level_filter(&self) -> LogLevelFilter {
        LogLevelFilter::from_usize(*self as usize).unwrap()
    }
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevelFilter {
    Off,
    Error,
    Warn,
    Info,
    Debug,
    Trace,
}

impl Clone for LogLevelFilter {
    #[inline]
    fn clone(&self) -> LogLevelFilter {
        *self
    }
}

impl PartialEq for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevel> for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        other.eq(self)
    }
}

impl PartialOrd for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevel> for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        other.partial_cmp(self).map(|x| x.reverse())
    }
}

impl Ord for LogLevelFilter {
    #[inline]
    fn cmp(&self, other: &LogLevelFilter) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl FromStr for LogLevelFilter {
    type Err = ();
    fn from_str(level: &str) -> Result<LogLevelFilter, ()> {
        ok_or(LOG_LEVEL_NAMES.iter()
                    .position(|&name| name.eq_ignore_ascii_case(level))
                    .map(|p| LogLevelFilter::from_usize(p).unwrap()), ())
    }
}

impl LogLevelFilter {
    fn from_usize(u: usize) -> Option<LogLevelFilter> {
        match u {
            0 => Some(LogLevelFilter::Off),
            1 => Some(LogLevelFilter::Error),
            2 => Some(LogLevelFilter::Warn),
            3 => Some(LogLevelFilter::Info),
            4 => Some(LogLevelFilter::Debug),
            5 => Some(LogLevelFilter::Trace),
            _ => None
        }
    }
    /// Returns the most verbose logging level filter.
    #[inline]
    pub fn max() -> LogLevelFilter {
        LogLevelFilter::Trace
    }

    /// Converts `self` to the equivalent `LogLevel`.
    ///
    /// Returns `None` if `self` is `LogLevelFilter::Off`.
    #[inline]
    pub fn to_log_level(&self) -> Option<LogLevel> {
        LogLevel::from_usize(*self as usize)
    }
}

/// Metadata about a log message.
pub struct LogMetadata {
  pub level:  LogLevel,
  pub target: &'static str,
}

pub struct LogDirective {
    name:  Option<String>,
    level: LogLevelFilter,
}

fn ok_or<T, E>(t: Option<T>, e: E) -> Result<T, E> {
    match t {
        Some(t) => Ok(t),
        None => Err(e),
    }
}

pub fn parse_logging_spec(spec: &str) -> Vec<LogDirective> {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let filter = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', \
                 ignoring it (too many '/'s)", spec);
        return dirs;
    }
    mods.map(|m| { for s in m.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match part0.parse() {
                    Ok(num) => (num, None),
                    Err(_) => (LogLevelFilter::max(), Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (LogLevelFilter::max(), Some(part0)),
            (Some(part0), Some(part1), None) => {
                match part1.parse() {
                    Ok(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }});

    return dirs;
}

#[macro_export]
macro_rules! log {
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
      use $crate::logging::LOGGER;
      static _META: $crate::logging::LogMetadata = $crate::logging::LogMetadata {
          level:  $lvl,
          target: module_path!(),
      };
      LOGGER.lock().unwrap().log(&_META, format_args!($($arg)+));
    });
    ($lvl:expr, $($arg:tt)+) => (log!(target: module_path!(), $lvl, $($arg)+));
}

#[macro_export]
macro_rules! error {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Error, concat!("{}\t{}\t{}\t{}\t", $format),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "ERROR", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Error, concat!("{}\t{}\t{}\t{}\t", $format),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "ERROR");
    };
}

#[macro_export]
macro_rules! warn {
    ($format:expr, $($arg:tt)*) => {
        use time;
        use logging::PID;
        log!($crate::logging::LogLevel::Warn, concat!("{}\t{}\t{}\t{}\t", $format),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "WARN", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Warn, concat!("{}\t{}\t{}\t{}\t", $format),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "WARN");
    }
}

#[macro_export]
macro_rules! info {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Info, concat!("{}\t{}\t{}\t{}\t", $format),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "INFO", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Info, concat!("{}\t{}\t{}\t{}\t", $format),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "INFO");
    }
}

#[macro_export]
macro_rules! debug {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Debug, concat!("{}\t{}\t{}\t{}\t{}\t", $format),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "DEBUG", module_path!(), $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Debug, concat!("{}\t{}\t{}\t{}\t{}\t", $format),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "DEBUG", module_path!());
    }
}

#[macro_export]
macro_rules! trace {
    ($format:expr, $($arg:tt)*) => (
        log!($crate::logging::LogLevel::Trace, concat!("{}\t{}\t{}\t{}\t{}\t", $format),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "TRACE", module_path!(), $($arg)*);
    );
    ($format:expr) => (
        log!($crate::logging::LogLevel::Trace, concat!("{}\t{}\t{}\t{}\t{}\t", $format),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "TRACE", module_path!());
    )
}

<commit_msg>make ends of lines part of formatting<commit_after>use libc;
use std::str::FromStr;
use std::cmp::{self,Ord};
use std::sync::{Mutex, Once, ONCE_INIT};
use std::cell::RefCell;
use std::fmt::{Arguments,format,write};
use std::io::{stdout,Stdout,Write};
use std::ascii::AsciiExt;
use std::net::{SocketAddr,UdpSocket};
use std::net::TcpStream;
use mio_uds::UnixDatagram;

lazy_static! {
  pub static ref LOGGER: Mutex<Logger> = Mutex::new(Logger::new());
  pub static ref PID:    i32 = unsafe { libc::getpid() };
}

pub struct Logger {
  directives: Vec<LogDirective>,
  backend:    LoggerBackend,
}

impl Logger {
  pub fn new() -> Logger {
    Logger {
      directives: vec!(LogDirective {
        name:  None,
        level: LogLevelFilter::Error,
      }),
      backend: LoggerBackend::Stdout(stdout())
    }
  }

  pub fn init(spec: &str, backend: LoggerBackend) {
    let directives = parse_logging_spec(spec);
    if let Ok(ref mut logger) = LOGGER.lock() {
      logger.set_directives(directives);
      logger.backend = backend;
    }
  }

  pub fn log<'a>(&mut self, meta: &LogMetadata, args: Arguments) {
    if self.enabled(meta) {
      match self.backend {
        LoggerBackend::Stdout(ref mut stdout) => {
          stdout.write_fmt(args);
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Unix(ref mut socket) => {
          socket.send(format(args).as_bytes());
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Udp(ref mut socket, ref address) => {
          socket.send_to(format(args).as_bytes(), address);
        }
        LoggerBackend::Tcp(ref mut socket) => {
          socket.write_fmt(args);
        },
      }
    }
  }

  pub fn set_directives(&mut self, directives: Vec<LogDirective>) {
    self.directives = directives;
  }

  fn enabled(&self, meta: &LogMetadata) -> bool {
    // Search for the longest match, the vector is assumed to be pre-sorted.
    for directive in self.directives.iter().rev() {
      match directive.name {
        Some(ref name) if !meta.target.starts_with(&**name) => {},
        Some(..) | None => {
          return meta.level <= directive.level
        }
      }
    }
    false
  }
}

#[derive(Debug)]
pub enum LoggerBackend {
  Stdout(Stdout),
  Unix(UnixDatagram),
  Udp(UdpSocket, SocketAddr),
  Tcp(TcpStream)
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevel {
    /// The "error" level.
    ///
    /// Designates very serious errors.
    Error = 1, // This way these line up with the discriminants for LogLevelFilter below
    /// The "warn" level.
    ///
    /// Designates hazardous situations.
    Warn,
    /// The "info" level.
    ///
    /// Designates useful information.
    Info,
    /// The "debug" level.
    ///
    /// Designates lower priority information.
    Debug,
    /// The "trace" level.
    ///
    /// Designates very low priority, often extremely verbose, information.
    Trace,
}

static LOG_LEVEL_NAMES: [&'static str; 6] = ["OFF", "ERROR", "WARN", "INFO",
                                             "DEBUG", "TRACE"];

impl Clone for LogLevel {
    #[inline]
    fn clone(&self) -> LogLevel {
        *self
    }
}

impl PartialEq for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevelFilter> for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialOrd for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevelFilter> for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some((*self as usize).cmp(&(*other as usize)))
    }
}

impl Ord for LogLevel {
    #[inline]
    fn cmp(&self, other: &LogLevel) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl LogLevel {
    fn from_usize(u: usize) -> Option<LogLevel> {
        match u {
            1 => Some(LogLevel::Error),
            2 => Some(LogLevel::Warn),
            3 => Some(LogLevel::Info),
            4 => Some(LogLevel::Debug),
            5 => Some(LogLevel::Trace),
            _ => None
        }
    }

    /// Returns the most verbose logging level.
    #[inline]
    pub fn max() -> LogLevel {
        LogLevel::Trace
    }

    /// Converts the `LogLevel` to the equivalent `LogLevelFilter`.
    #[inline]
    pub fn to_log_level_filter(&self) -> LogLevelFilter {
        LogLevelFilter::from_usize(*self as usize).unwrap()
    }
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevelFilter {
    Off,
    Error,
    Warn,
    Info,
    Debug,
    Trace,
}

impl Clone for LogLevelFilter {
    #[inline]
    fn clone(&self) -> LogLevelFilter {
        *self
    }
}

impl PartialEq for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevel> for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        other.eq(self)
    }
}

impl PartialOrd for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevel> for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        other.partial_cmp(self).map(|x| x.reverse())
    }
}

impl Ord for LogLevelFilter {
    #[inline]
    fn cmp(&self, other: &LogLevelFilter) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl FromStr for LogLevelFilter {
    type Err = ();
    fn from_str(level: &str) -> Result<LogLevelFilter, ()> {
        ok_or(LOG_LEVEL_NAMES.iter()
                    .position(|&name| name.eq_ignore_ascii_case(level))
                    .map(|p| LogLevelFilter::from_usize(p).unwrap()), ())
    }
}

impl LogLevelFilter {
    fn from_usize(u: usize) -> Option<LogLevelFilter> {
        match u {
            0 => Some(LogLevelFilter::Off),
            1 => Some(LogLevelFilter::Error),
            2 => Some(LogLevelFilter::Warn),
            3 => Some(LogLevelFilter::Info),
            4 => Some(LogLevelFilter::Debug),
            5 => Some(LogLevelFilter::Trace),
            _ => None
        }
    }
    /// Returns the most verbose logging level filter.
    #[inline]
    pub fn max() -> LogLevelFilter {
        LogLevelFilter::Trace
    }

    /// Converts `self` to the equivalent `LogLevel`.
    ///
    /// Returns `None` if `self` is `LogLevelFilter::Off`.
    #[inline]
    pub fn to_log_level(&self) -> Option<LogLevel> {
        LogLevel::from_usize(*self as usize)
    }
}

/// Metadata about a log message.
pub struct LogMetadata {
  pub level:  LogLevel,
  pub target: &'static str,
}

pub struct LogDirective {
    name:  Option<String>,
    level: LogLevelFilter,
}

fn ok_or<T, E>(t: Option<T>, e: E) -> Result<T, E> {
    match t {
        Some(t) => Ok(t),
        None => Err(e),
    }
}

pub fn parse_logging_spec(spec: &str) -> Vec<LogDirective> {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let filter = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', \
                 ignoring it (too many '/'s)", spec);
        return dirs;
    }
    mods.map(|m| { for s in m.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match part0.parse() {
                    Ok(num) => (num, None),
                    Err(_) => (LogLevelFilter::max(), Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (LogLevelFilter::max(), Some(part0)),
            (Some(part0), Some(part1), None) => {
                match part1.parse() {
                    Ok(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }});

    return dirs;
}

#[macro_export]
macro_rules! log {
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
      use $crate::logging::LOGGER;
      static _META: $crate::logging::LogMetadata = $crate::logging::LogMetadata {
          level:  $lvl,
          target: module_path!(),
      };
      LOGGER.lock().unwrap().log(&_META, format_args!($($arg)+));
    });
    ($lvl:expr, $($arg:tt)+) => (log!(target: module_path!(), $lvl, $($arg)+));
}

#[macro_export]
macro_rules! error {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Error, concat!("{}\t{}\t{}\t{}\t", $format, '\n'),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "ERROR", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Error, concat!("{}\t{}\t{}\t{}\t", $format, '\n'),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "ERROR");
    };
}

#[macro_export]
macro_rules! warn {
    ($format:expr, $($arg:tt)*) => {
        use time;
        use logging::PID;
        log!($crate::logging::LogLevel::Warn, concat!("{}\t{}\t{}\t{}\t", $format, '\n'),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "WARN", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Warn, concat!("{}\t{}\t{}\t{}\t", $format, '\n'),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "WARN");
    }
}

#[macro_export]
macro_rules! info {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Info, concat!("{}\t{}\t{}\t{}\t", $format, '\n'),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "INFO", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Info, concat!("{}\t{}\t{}\t{}\t", $format, '\n'),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "INFO");
    }
}

#[macro_export]
macro_rules! debug {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Debug, concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "DEBUG", module_path!(), $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Debug, concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "DEBUG", module_path!());
    }
}

#[macro_export]
macro_rules! trace {
    ($format:expr, $($arg:tt)*) => (
        log!($crate::logging::LogLevel::Trace, concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "TRACE", module_path!(), $($arg)*);
    );
    ($format:expr) => (
        log!($crate::logging::LogLevel::Trace, concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
          ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
          "TRACE", module_path!());
    )
}

<|endoftext|>


<commit_before>// clap used as argument handler
extern crate clap;

use clap::{App, Arg};

// This Struct is later given to our main program,
// it contains all the needed information to make suggestions of films
#[derive(Debug, Clone)]
struct SearchParams {
    genre: Vec<String>,
    movies: Vec<String>,
    actors: Vec<String>,
}

impl SearchParams {
    // initialize a SearchParams type with empty fields
    fn init() -> Self {
        SearchParams {
            genre: Vec::new(),
            movies: Vec::new(),
            actors: Vec::new(),
        }
    }
}

// Creates struct SearchParams in which all given parameters are included.
fn get_search_params() -> SearchParams {
    // later given to main program, contains all arguments given in
    // command line
    let mut search_params = SearchParams::init();

    // our matches, we can later use those to handle our commandline input
    let matches = App::new("FOM")
        .arg(Arg::with_name("genre")
            .short("g")
            .takes_value(true))
        .arg(Arg::with_name("actor")
            .short("a")
            .takes_value(true))
        .arg(Arg::with_name("movie")
            .short("m")
            .takes_value(true)
            .multiple(true))
        .get_matches();

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("genre"){
        let genre =
            match matches.value_of("genre") {
                Some(genre) => genre,
                None => panic!(),
        };
        search_params.genre.push(genre.into());
        // Debug
        // println!("Genre: {}", genre);
    }

    // If an actor was given, save it in our SearchParams Type
    if matches.is_present("actor"){
        let actor =
            match matches.value_of("actor") {
                Some(actor) => actor,
                None => panic!(),
        };
        search_params.actors.push(actor.into());
        // Debug
        // println!("Actor: {}", actor);
    }

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("movie"){
        let movies:Vec<String> =
            match matches.values_of("movie") {
                Some(vals) => vals
                    .map(|x| x.to_string())
                    .collect(),
                None => panic!(),
        };
        search_params.movies = movies;
        // Debug
        // println!("Movies: {:?}", search_params.genre);
    }
    // Debug
    // println!("{:?}", search_params);

    // return struct with all needed search_params
    search_params
}

// fn main() {
    // Test
    // possible test_input could be
    // cargo run -- -a Name -m Lieblingsfilm1 Lieblingsfilm2 -g horror

    // let args = get_search_params();
    // println!("{:?}", args);
// }
<commit_msg>made things public<commit_after>// clap used as argument handler
extern crate clap;

use clap::{App, Arg};

// This Struct is later given to our main program,
// it contains all the needed information to make suggestions of films
#[derive(Debug, Clone)]
pub struct SearchParams {
    genre: Vec<String>,
    movies: Vec<String>,
    actors: Vec<String>,
}

impl SearchParams {
    // initialize a SearchParams type with empty fields
    fn init() -> Self {
        SearchParams {
            genre: Vec::new(),
            movies: Vec::new(),
            actors: Vec::new(),
        }
    }
}

// Creates struct SearchParams in which all given parameters are included.
pub fn get_search_params() -> SearchParams {
    // later given to main program, contains all arguments given in
    // command line
    let mut search_params = SearchParams::init();

    // our matches, we can later use those to handle our commandline input
    let matches = App::new("FOM")
        .arg(Arg::with_name("genre")
            .short("g")
            .takes_value(true))
        .arg(Arg::with_name("actor")
            .short("a")
            .takes_value(true))
        .arg(Arg::with_name("movie")
            .short("m")
            .takes_value(true)
            .multiple(true))
        .get_matches();

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("genre") {
        let genre = match matches.value_of("genre") {
            Some(genre) => genre,
            None => panic!(),
        };
        search_params.genre.push(genre.into());
        // Debug
        // println!("Genre: {}", genre);
    }

    // If an actor was given, save it in our SearchParams Type
    if matches.is_present("actor") {
        let actor = match matches.value_of("actor") {
            Some(actor) => actor,
            None => panic!(),
        };
        search_params.actors.push(actor.into());
        // Debug
        // println!("Actor: {}", actor);
    }

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("movie") {
        let movies: Vec<String> = match matches.values_of("movie") {
            Some(vals) => {
                vals.map(|x| x.to_string())
                    .collect()
            }
            None => panic!(),
        };
        search_params.movies = movies;
        // Debug
        // println!("Movies: {:?}", search_params.genre);
    }
    // Debug
    // println!("{:?}", search_params);

    // return struct with all needed search_params
    search_params
}
<|endoftext|>


<commit_before>use libc::{c_char, c_ulong, c_int, c_uint, O_RDONLY, read, strerror};
use std::borrow::{Cow, IntoCow};
use std::ffi::{CStr, CString};
use std::{mem, os, str};
use Joystick;

static JSIOCGAXES: c_uint = 2147576337;
static JSIOCGBUTTONS: c_uint = 2147576338;
static JSIOCGID: c_uint = 2151705107;
static JSIOCGID_LEN: usize = 64;

extern {
	fn open(path: *const c_char, oflag: c_int) -> c_int;
	fn close(fd: c_int) -> c_int;
	fn ioctl(fd: c_uint, op: c_uint, result: *mut c_char);
}

fn os_error() -> &'static str {
	unsafe {
		let num = os::errno() as c_int;
		let c_error = CStr::from_ptr(strerror(num) as *const i8);
		str::from_utf8(c_error.to_bytes()).unwrap()
	}
}

/// Scan for joysticks
pub fn scan() -> Vec<NativeJoystick> {
	use std::fs;
	let mut joysticks = Vec::with_capacity(4);
	for entry in fs::walk_dir("/dev/input/").unwrap() {
		if let Ok(entry) = entry {
			let path = entry.path();
			if let Some(name) = path.file_name() {
				let name = name.to_str().unwrap();
				if name.starts_with("js") {
					let index = name[2..].parse().unwrap();
					if let Ok(js) = Joystick::new(index) {
						joysticks.push(js)
					}
				}
			}
		}
	}
	joysticks
}

/// Represents a system joystick
pub struct NativeJoystick {
	index: u8,
	fd: c_int,
	connected: bool
}

impl ::Joystick for NativeJoystick {
	type WithState = StatefulNativeJoystick;
	type NativeEvent = LinuxEvent;
	/// This tries to open the interface `/dev/input/js...` and will return the
	/// OS-level error if it fails to open this
	fn new(index: u8) -> Result<NativeJoystick, &'static str> {
		let path = format!("/dev/input/js{}", index);
		unsafe {
			let c_path = CString::new(path.as_bytes()).unwrap();
			let fd =  open(c_path.as_ptr(), O_RDONLY | 0x800);
			if fd == -1 {
				Err(os_error())
			} else {
				Ok(NativeJoystick {
					index: index,
					fd: fd,
					connected: true
				})
			}
		}
	}
	/// This reads from the interface in non-blocking mode and converts the native
	/// event into a Reminisce event
	fn poll_native(&mut self) -> Option<LinuxEvent> {
		unsafe {
			let mut event:LinuxEvent = mem::uninitialized();
			loop {
				let event_size = mem::size_of::<LinuxEvent>() as c_ulong;
				if read(self.fd, mem::transmute(&mut event), event_size) == -1 {
					match os::errno() {
						19 => self.connected = false,
						11 => (),
						code =>
							panic!("Error while polling joystick {} - {} - {}", self.index, code, os_error())
					}
					return None
				} else if event._type & 0x80 == 0 {
					return Some(event)
				}
			}
		}
	}
	fn is_connected(&self) -> bool {
		self.connected
	}
	fn get_num_axes(&self) -> u8 {
		unsafe {
			let mut num_axes: c_char = mem::uninitialized();
			ioctl(self.fd as u32, JSIOCGAXES, &mut num_axes as *mut i8);
			num_axes as u8
		}
	}
	fn get_num_buttons(&self) -> u8 {
		unsafe {
			let mut num_buttons: c_char = mem::uninitialized();
			ioctl(self.fd as u32, JSIOCGBUTTONS, &mut num_buttons as *mut i8);
			num_buttons as u8
		}
	}
	fn get_id(&self) -> Cow<str> {
		unsafe {
			use std::ffi::CStr;

			let mut bytes = Vec::with_capacity(JSIOCGID_LEN);
			ioctl(self.fd as u32, JSIOCGID, bytes.as_ptr() as *mut i8);
			let length = CStr::from_ptr(bytes.as_ptr() as *const i8).to_bytes().len();
			String::from_raw_parts(bytes.as_mut_ptr(), length, 64).into_cow()
		}
	}
	fn get_index(&self) -> u8 {
		self.index
	}
	/// This is not supported on Linux so None is returned every time
	fn get_battery(&self) -> Option<f32> {
		None
	}
	fn with_state(self) -> StatefulNativeJoystick {
		StatefulNativeJoystick::wrap(self)
	}
}

impl Drop for NativeJoystick {
	/// Close the joystick's file descriptor
	fn drop(&mut self) {
		unsafe {
			if close(self.fd) == -1 {
				panic!("Failed to close joystick {} due to {}", self.index, os_error())
			}
		}
	}
}

/// The default joystick that tracks its state
pub struct StatefulNativeJoystick {
	js: NativeJoystick,
	axes: Vec<i16>,
	buttons: Vec<bool>
}
impl StatefulNativeJoystick {
	/// Wrap a joystick
	pub fn wrap(js: NativeJoystick) -> StatefulNativeJoystick {
		StatefulNativeJoystick {
			axes: vec![0; js.get_num_axes() as usize],
			buttons: vec![false; js.get_num_buttons() as usize],
			js: js
		}
	}
}
impl ::Joystick for StatefulNativeJoystick {
	type WithState = StatefulNativeJoystick;
	type NativeEvent = LinuxEvent;
	fn new(index: u8) -> Result<StatefulNativeJoystick, &'static str> {
		let js = try!(::Joystick::new(index));
		Ok(StatefulNativeJoystick::wrap(js))
	}
	fn is_connected(&self) -> bool {
		self.js.is_connected()
	}
	fn get_id(&self) -> Cow<str> {
		self.js.get_id()
	}
	fn get_index(&self) -> u8 {
		self.js.get_index()
	}
	fn get_num_axes(&self) -> u8 {
		self.js.get_num_axes()
	}
	fn get_num_buttons(&self) -> u8 {
		self.js.get_num_buttons()
	}
	fn get_battery(&self) -> Option<f32> {
		None
	}
	fn poll_native(&mut self) -> Option<LinuxEvent> {
		self.js.poll_native()
	}
	fn poll(&mut self) -> Option<::Event> {
		let event = self.js.poll();
		match event {
			Some(::Event::AxisMoved(i, v)) => self.axes[i as usize] = v,
			Some(::Event::ButtonPressed(i)) => self.buttons[i as usize] = true,
			Some(::Event::ButtonReleased(i)) => self.buttons[i as usize] = false,
			_ => ()
		}
		event
	}
	fn with_state(self) -> StatefulNativeJoystick {
		self
	}
}
impl ::StatefulJoystick for StatefulNativeJoystick {
	fn get_axis(&self, index: ::Axis) -> Option<i16> {
		self.axes.get(index as usize).cloned()
	}
	fn get_button(&self, index: ::Button) -> Option<bool> {
		self.buttons.get(index as usize).cloned()
	}
	fn update(&mut self) {
		while let Some(_) = self.poll() {}
	}
}

#[repr(C)]
pub struct LinuxEvent {
	/// timestamp in milleseconds
	time: u32,
	/// value
	value: i16,
	/// event type
	_type: u8,
	/// axis / button number
	number: u8
}
impl ::IntoEvent for LinuxEvent {
	fn into_event(self) -> ::Event {
		use std::mem::transmute as cast;
		match (self._type, self.value) {
			(1, 0) => ::Event::ButtonReleased(unsafe { cast(self.number) }),
			(1, 1) => ::Event::ButtonPressed(unsafe { cast(self.number) }),
			(2, _) => ::Event::AxisMoved(unsafe { cast(self.number) }, self.value),
			_ => panic!("Bad type and value {} {} for joystick", self._type, self.value)
		}
	}
}
<commit_msg>Nicer joystock querying in Linux<commit_after>use libc::{c_char, c_ulong, c_int, c_uint, O_RDONLY, read, strerror};
use std::borrow::{Cow, IntoCow};
use std::ffi::{CStr, CString};
use std::{mem, os, str};
use Joystick;

static JSIOCGAXES: c_uint = 2147576337;
static JSIOCGBUTTONS: c_uint = 2147576338;
static JSIOCGID: c_uint = 2151705107;
static JSIOCGID_LEN: usize = 64;

extern {
	fn open(path: *const c_char, oflag: c_int) -> c_int;
	fn close(fd: c_int) -> c_int;
	fn ioctl(fd: c_uint, op: c_uint, result: *mut c_char);
}

fn os_error() -> &'static str {
	unsafe {
		let num = os::errno() as c_int;
		let c_error = CStr::from_ptr(strerror(num) as *const i8);
		str::from_utf8(c_error.to_bytes()).unwrap()
	}
}

/// Scan for joysticks
pub fn scan() -> Vec<NativeJoystick> {
	use std::fs;
	// So many ifs...
	let mut joysticks = Vec::with_capacity(4);
	for entry in fs::walk_dir("/dev/input/").unwrap() {
		if let Ok(entry) = entry {
			let path = entry.path();
			if let Some(name) = path.file_name() {
				if let Some(name) = name.to_str() {
					if name.starts_with("js") {
						if let Ok(index) = name[2..].parse() {
							if let Ok(js) = Joystick::new(index) {
								joysticks.push(js)
							}
						}
					}
				}
			}
		}
	}
	joysticks
}

/// Represents a system joystick
pub struct NativeJoystick {
	index: u8,
	fd: c_int,
	connected: bool
}

impl ::Joystick for NativeJoystick {
	type WithState = StatefulNativeJoystick;
	type NativeEvent = LinuxEvent;
	/// This tries to open the interface `/dev/input/js...` and will return the
	/// OS-level error if it fails to open this
	fn new(index: u8) -> Result<NativeJoystick, &'static str> {
		let path = format!("/dev/input/js{}", index);
		unsafe {
			let c_path = CString::new(path.as_bytes()).unwrap();
			let fd =  open(c_path.as_ptr(), O_RDONLY | 0x800);
			if fd == -1 {
				Err(os_error())
			} else {
				Ok(NativeJoystick {
					index: index,
					fd: fd,
					connected: true
				})
			}
		}
	}
	/// This reads from the interface in non-blocking mode and converts the native
	/// event into a Reminisce event
	fn poll_native(&mut self) -> Option<LinuxEvent> {
		unsafe {
			let mut event:LinuxEvent = mem::uninitialized();
			loop {
				let event_size = mem::size_of::<LinuxEvent>() as c_ulong;
				if read(self.fd, mem::transmute(&mut event), event_size) == -1 {
					match os::errno() {
						19 => self.connected = false,
						11 => (),
						code =>
							panic!("Error while polling joystick {} - {} - {}", self.index, code, os_error())
					}
					return None
				} else if event._type & 0x80 == 0 {
					return Some(event)
				}
			}
		}
	}
	fn is_connected(&self) -> bool {
		self.connected
	}
	fn get_num_axes(&self) -> u8 {
		unsafe {
			let mut num_axes: c_char = mem::uninitialized();
			ioctl(self.fd as u32, JSIOCGAXES, &mut num_axes as *mut i8);
			num_axes as u8
		}
	}
	fn get_num_buttons(&self) -> u8 {
		unsafe {
			let mut num_buttons: c_char = mem::uninitialized();
			ioctl(self.fd as u32, JSIOCGBUTTONS, &mut num_buttons as *mut i8);
			num_buttons as u8
		}
	}
	fn get_id(&self) -> Cow<str> {
		unsafe {
			use std::ffi::CStr;

			let mut bytes = Vec::with_capacity(JSIOCGID_LEN);
			ioctl(self.fd as u32, JSIOCGID, bytes.as_ptr() as *mut i8);
			let length = CStr::from_ptr(bytes.as_ptr() as *const i8).to_bytes().len();
			String::from_raw_parts(bytes.as_mut_ptr(), length, 64).into_cow()
		}
	}
	fn get_index(&self) -> u8 {
		self.index
	}
	/// This is not supported on Linux so None is returned every time
	fn get_battery(&self) -> Option<f32> {
		None
	}
	fn with_state(self) -> StatefulNativeJoystick {
		StatefulNativeJoystick::wrap(self)
	}
}

impl Drop for NativeJoystick {
	/// Close the joystick's file descriptor
	fn drop(&mut self) {
		unsafe {
			if close(self.fd) == -1 {
				panic!("Failed to close joystick {} due to {}", self.index, os_error())
			}
		}
	}
}

/// The default joystick that tracks its state
pub struct StatefulNativeJoystick {
	js: NativeJoystick,
	axes: Vec<i16>,
	buttons: Vec<bool>
}
impl StatefulNativeJoystick {
	/// Wrap a joystick
	pub fn wrap(js: NativeJoystick) -> StatefulNativeJoystick {
		StatefulNativeJoystick {
			axes: vec![0; js.get_num_axes() as usize],
			buttons: vec![false; js.get_num_buttons() as usize],
			js: js
		}
	}
}
impl ::Joystick for StatefulNativeJoystick {
	type WithState = StatefulNativeJoystick;
	type NativeEvent = LinuxEvent;
	fn new(index: u8) -> Result<StatefulNativeJoystick, &'static str> {
		let js = try!(::Joystick::new(index));
		Ok(StatefulNativeJoystick::wrap(js))
	}
	fn is_connected(&self) -> bool {
		self.js.is_connected()
	}
	fn get_id(&self) -> Cow<str> {
		self.js.get_id()
	}
	fn get_index(&self) -> u8 {
		self.js.get_index()
	}
	fn get_num_axes(&self) -> u8 {
		self.js.get_num_axes()
	}
	fn get_num_buttons(&self) -> u8 {
		self.js.get_num_buttons()
	}
	fn get_battery(&self) -> Option<f32> {
		None
	}
	fn poll_native(&mut self) -> Option<LinuxEvent> {
		self.js.poll_native()
	}
	fn poll(&mut self) -> Option<::Event> {
		let event = self.js.poll();
		match event {
			Some(::Event::AxisMoved(i, v)) => self.axes[i as usize] = v,
			Some(::Event::ButtonPressed(i)) => self.buttons[i as usize] = true,
			Some(::Event::ButtonReleased(i)) => self.buttons[i as usize] = false,
			_ => ()
		}
		event
	}
	fn with_state(self) -> StatefulNativeJoystick {
		self
	}
}
impl ::StatefulJoystick for StatefulNativeJoystick {
	fn get_axis(&self, index: ::Axis) -> Option<i16> {
		self.axes.get(index as usize).cloned()
	}
	fn get_button(&self, index: ::Button) -> Option<bool> {
		self.buttons.get(index as usize).cloned()
	}
	fn update(&mut self) {
		while let Some(_) = self.poll() {}
	}
}

#[repr(C)]
pub struct LinuxEvent {
	/// timestamp in milleseconds
	time: u32,
	/// value
	value: i16,
	/// event type
	_type: u8,
	/// axis / button number
	number: u8
}
impl ::IntoEvent for LinuxEvent {
	fn into_event(self) -> ::Event {
		use std::mem::transmute as cast;
		match (self._type, self.value) {
			(1, 0) => ::Event::ButtonReleased(unsafe { cast(self.number) }),
			(1, 1) => ::Event::ButtonPressed(unsafe { cast(self.number) }),
			(2, _) => ::Event::AxisMoved(unsafe { cast(self.number) }, self.value),
			_ => panic!("Bad type and value {} {} for joystick", self._type, self.value)
		}
	}
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{
    convert::TryFrom,
    fmt::{self, Debug},
    hash::{Hash, Hasher},
};

use serde_json::{Map, Value};

use libcryptsetup_rs::SafeMemHandle;

use crate::{
    engine::types::{ClevisInfo, MaybeInconsistent},
    stratis::{StratisError, StratisResult},
};

/// A handle for memory designed to safely handle Stratis passphrases. It can
/// be coerced to a slice reference for use in read-only operations.
pub struct SizedKeyMemory {
    mem: SafeMemHandle,
    size: usize,
}

impl SizedKeyMemory {
    pub fn new(mem: SafeMemHandle, size: usize) -> SizedKeyMemory {
        SizedKeyMemory { mem, size }
    }
}

// This is safe to send across threads because the *mut c_void pointer is always
// allocated in the heap by libcryptsetup which is accessible globally to all threads
// in the process.
unsafe impl Send for SizedKeyMemory {}

impl Debug for SizedKeyMemory {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self.as_ref())
    }
}

impl AsRef<[u8]> for SizedKeyMemory {
    fn as_ref(&self) -> &[u8] {
        &self.mem.as_ref()[..self.size]
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum EncryptionInfo {
    KeyDesc(KeyDescription),
    ClevisInfo(ClevisInfo),
    Both(KeyDescription, ClevisInfo),
}

impl EncryptionInfo {
    /// Convert two optional encryption parameters into an EncryptionInfo enum.
    pub fn from_options(options: (Option<KeyDescription>, Option<ClevisInfo>)) -> Option<Self> {
        match options {
            (Some(kd), Some(ci)) => Some(EncryptionInfo::Both(kd, ci)),
            (Some(kd), _) => Some(EncryptionInfo::KeyDesc(kd)),
            (_, Some(ci)) => Some(EncryptionInfo::ClevisInfo(ci)),
            (None, None) => None,
        }
    }

    /// Set the key description.
    pub fn set_key_desc(self, key_desc: KeyDescription) -> Self {
        match self {
            EncryptionInfo::KeyDesc(_) => EncryptionInfo::KeyDesc(key_desc),
            EncryptionInfo::ClevisInfo(ci) => EncryptionInfo::Both(key_desc, ci),
            EncryptionInfo::Both(_, ci) => EncryptionInfo::Both(key_desc, ci),
        }
    }

    /// Unset the key description. If only Clevis info is set, no action is taken.
    /// Precondition: matches!(self, EncryptionInfo::Both(_, _) | EncryptonInfo::ClevisInfo(_))
    pub fn unset_key_desc(self) -> Self {
        match self {
            EncryptionInfo::KeyDesc(_) => {
                panic!("Cannot convert from encrypted to unencrypted device");
            }
            EncryptionInfo::Both(_, ci) => EncryptionInfo::ClevisInfo(ci),
            unchanged => unchanged,
        }
    }

    /// Set Clevis information.
    pub fn set_clevis_info(self, clevis_info: ClevisInfo) -> Self {
        match self {
            EncryptionInfo::ClevisInfo(_) => EncryptionInfo::ClevisInfo(clevis_info),
            EncryptionInfo::KeyDesc(kd) => EncryptionInfo::Both(kd, clevis_info),
            EncryptionInfo::Both(kd, _) => EncryptionInfo::Both(kd, clevis_info),
        }
    }

    /// Unset the Clevis info. If only the key description is set, no action is taken.
    /// Precondition: matches!(self, EncryptionInfo::Both(_, _) | EncryptonInfo::KeyDesc(_))
    pub fn unset_clevis_info(self) -> Self {
        match self {
            EncryptionInfo::ClevisInfo(_) => {
                panic!("Cannot convert from encrypted to unencrypted device");
            }
            EncryptionInfo::Both(kd, _) => EncryptionInfo::KeyDesc(kd),
            unchanged => unchanged,
        }
    }

    /// Get an optional key description from the encryption information.
    pub fn key_description(&self) -> Option<&KeyDescription> {
        match self {
            EncryptionInfo::Both(kd, _) | EncryptionInfo::KeyDesc(kd) => Some(kd),
            _ => None,
        }
    }

    /// Get optional Clevis information from the encryption information.
    pub fn clevis_info(&self) -> Option<&ClevisInfo> {
        match self {
            EncryptionInfo::Both(_, ci) | EncryptionInfo::ClevisInfo(ci) => Some(ci),
            _ => None,
        }
    }
}

impl fmt::Display for EncryptionInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let key_desc_str = if let Some(kd) = self.key_description() {
            format!("key description: \"{}\"", kd.as_application_str())
        } else {
            "no key description".to_string()
        };
        if let Some((pin, config)) = self.clevis_info() {
            write!(
                f,
                "{}, clevis pin: \"{}\", clevis configuration: \"{}\"",
                key_desc_str, pin, config
            )
        } else {
            write!(f, "{}, no Clevis information", key_desc_str)
        }
    }
}

// Implement Hash explicitly because Value does not implement Hash.
// The reason Value does not implement Hash is that some JSON is really big
// and hashing it would be expensive. This JSON probably won't be, but it
// serves no obvious purpose to stringify it and then hash it.
// Necessary Hash Property: \forall x_1, x_2 in EncryptionInfo,
// if x_1 == x_2, then hash(x_1) == hash(x_2) obviously holds.
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for EncryptionInfo {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.key_description().hash(state);
        self.clevis_info().map(|(pin, _)| pin).hash(state);
    }
}

impl<'a> Into<Value> for &'a EncryptionInfo {
    fn into(self) -> Value {
        let mut json = Map::new();
        if let Some(kd) = self.key_description() {
            json.insert(
                "key_description".to_string(),
                Value::from(kd.as_application_str()),
            );
        }
        if let Some(info) = self.clevis_info() {
            json.insert("clevis_pin".to_string(), Value::from(info.0.to_owned()));
            json.insert("clevis_config".to_string(), info.1.clone());
        }
        Value::from(json)
    }
}

impl TryFrom<PoolEncryptionInfo> for EncryptionInfo {
    type Error = StratisError;

    fn try_from(pei: PoolEncryptionInfo) -> StratisResult<Self> {
        match pei {
            PoolEncryptionInfo::KeyDesc(MaybeInconsistent::No(kd)) => {
                Ok(EncryptionInfo::KeyDesc(kd))
            },
            PoolEncryptionInfo::ClevisInfo(MaybeInconsistent::No(ci)) => {
                Ok(EncryptionInfo::ClevisInfo(ci))
            },
            PoolEncryptionInfo::Both(MaybeInconsistent::No(kd), MaybeInconsistent::No(ci)) => {
                Ok(EncryptionInfo::Both(kd, ci))
            },
            _ => {
                Err(StratisError::Msg("Cannot determine encryption information from metadata that is inconsistent across devices in a pool".to_string()))
            }
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum PoolEncryptionInfo {
    KeyDesc(MaybeInconsistent<KeyDescription>),
    ClevisInfo(MaybeInconsistent<ClevisInfo>),
    Both(
        MaybeInconsistent<KeyDescription>,
        MaybeInconsistent<ClevisInfo>,
    ),
}

impl PoolEncryptionInfo {
    /// Reconcile two PoolEncryptionInfo records.
    ///
    /// Because rollback failure can result in some devices having a key description
    /// or Clevis info and some not having that information, any reconciliation
    /// for Some(_) and None will result in Some(MaybeInconsistent::Yes).
    fn add_enc_info<I>(self, info: I) -> Self
    where
        PoolEncryptionInfo: From<I>,
    {
        let pei = PoolEncryptionInfo::from(info);
        match (self, pei) {
            (PoolEncryptionInfo::KeyDesc(kd1), PoolEncryptionInfo::KeyDesc(kd2)) => {
                if kd1 != kd2 {
                    PoolEncryptionInfo::KeyDesc(MaybeInconsistent::Yes)
                } else {
                    PoolEncryptionInfo::KeyDesc(kd1)
                }
            }
            (PoolEncryptionInfo::ClevisInfo(ci1), PoolEncryptionInfo::ClevisInfo(ci2)) => {
                if ci1 != ci2 {
                    PoolEncryptionInfo::ClevisInfo(MaybeInconsistent::Yes)
                } else {
                    PoolEncryptionInfo::ClevisInfo(ci1)
                }
            }
            (PoolEncryptionInfo::Both(kd1, ci1), PoolEncryptionInfo::Both(kd2, ci2)) => {
                PoolEncryptionInfo::Both(
                    if kd1 != kd2 {
                        MaybeInconsistent::Yes
                    } else {
                        kd1
                    },
                    if ci1 != ci2 {
                        MaybeInconsistent::Yes
                    } else {
                        ci1
                    },
                )
            }
            (PoolEncryptionInfo::KeyDesc(_), PoolEncryptionInfo::ClevisInfo(_))
            | (PoolEncryptionInfo::ClevisInfo(_), PoolEncryptionInfo::KeyDesc(_)) => {
                PoolEncryptionInfo::Both(MaybeInconsistent::Yes, MaybeInconsistent::Yes)
            }
            (PoolEncryptionInfo::KeyDesc(kd1), PoolEncryptionInfo::Both(kd2, _))
            | (PoolEncryptionInfo::Both(kd1, _), PoolEncryptionInfo::KeyDesc(kd2)) => {
                PoolEncryptionInfo::Both(
                    if kd1 != kd2 {
                        MaybeInconsistent::Yes
                    } else {
                        kd1
                    },
                    MaybeInconsistent::Yes,
                )
            }
            (PoolEncryptionInfo::ClevisInfo(ci1), PoolEncryptionInfo::Both(_, ci2))
            | (PoolEncryptionInfo::Both(_, ci1), PoolEncryptionInfo::ClevisInfo(ci2)) => {
                PoolEncryptionInfo::Both(
                    MaybeInconsistent::Yes,
                    if ci1 != ci2 {
                        MaybeInconsistent::Yes
                    } else {
                        ci1
                    },
                )
            }
        }
    }

    pub fn is_inconsistent(&self) -> bool {
        matches!(
            self,
            PoolEncryptionInfo::KeyDesc(MaybeInconsistent::Yes)
                | PoolEncryptionInfo::ClevisInfo(MaybeInconsistent::Yes)
                | PoolEncryptionInfo::Both(MaybeInconsistent::Yes, _)
                | PoolEncryptionInfo::Both(_, MaybeInconsistent::Yes)
        )
    }

    pub fn key_description(&self) -> StratisResult<Option<&KeyDescription>> {
        match self {
            PoolEncryptionInfo::KeyDesc(kd) | PoolEncryptionInfo::Both(kd, _) => {
                if let MaybeInconsistent::No(ref key_description) = kd {
                    Ok(Some(key_description))
                } else {
                    Err(StratisError::Msg(
                        "Key description is inconsistent across devices".to_string(),
                    ))
                }
            }
            _ => Ok(None),
        }
    }

    pub fn clevis_info(&self) -> StratisResult<Option<&ClevisInfo>> {
        match self {
            PoolEncryptionInfo::ClevisInfo(ci) | PoolEncryptionInfo::Both(_, ci) => {
                if let MaybeInconsistent::No(ref clevis_info) = ci {
                    Ok(Some(clevis_info))
                } else {
                    Err(StratisError::Msg(
                        "Clevis information is inconsistent across devices".to_string(),
                    ))
                }
            }
            _ => Ok(None),
        }
    }
}

impl From<&EncryptionInfo> for PoolEncryptionInfo {
    fn from(enc_info: &EncryptionInfo) -> Self {
        match enc_info {
            EncryptionInfo::KeyDesc(ref kd) => {
                PoolEncryptionInfo::KeyDesc(MaybeInconsistent::No(kd.to_owned()))
            }
            EncryptionInfo::ClevisInfo(ref ci) => {
                PoolEncryptionInfo::ClevisInfo(MaybeInconsistent::No(ci.to_owned()))
            }
            EncryptionInfo::Both(ref kd, ref ci) => PoolEncryptionInfo::Both(
                MaybeInconsistent::No(kd.to_owned()),
                MaybeInconsistent::No(ci.to_owned()),
            ),
        }
    }
}

impl<'a, I> From<I> for PoolEncryptionInfo
where
    I: IntoIterator<Item = &'a EncryptionInfo>,
{
    // Precondition: Iterator must have at least one item.
    fn from(into_iterator: I) -> Self {
        let mut iterator = into_iterator.into_iter();
        match iterator.next() {
            Some(ei) => iterator.fold(PoolEncryptionInfo::from(ei), |pool_enc_info, next| {
                pool_enc_info.add_enc_info(next)
            }),
            None => panic!("Cannot supply empty iterator"),
        }
    }
}

/// A data type respresenting a key description for the kernel keyring
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct KeyDescription(String);

impl KeyDescription {
    /// Return the application-level key description (the key description with no
    /// Stratis prefix added).
    pub fn as_application_str(&self) -> &str {
        &self.0
    }
}

// Key descriptions with ';'s are disallowed because a key description
// containing a ';' will not be able to be correctly parsed from the kernel's
// describe string, which uses ';'s as field delimiters.
impl TryFrom<String> for KeyDescription {
    type Error = StratisError;

    fn try_from(s: String) -> StratisResult<KeyDescription> {
        if s.contains(';') {
            Err(StratisError::Msg(format!(
                "Key description {} contains a ';'",
                s
            )))
        } else {
            Ok(KeyDescription(s))
        }
    }
}

impl<'a> TryFrom<&'a String> for KeyDescription {
    type Error = StratisError;

    fn try_from(s: &String) -> StratisResult<KeyDescription> {
        KeyDescription::try_from(s.to_owned())
    }
}
<commit_msg>Allow clippy non_send_fields_in_send_ty for SizedKeyMemory<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{
    convert::TryFrom,
    fmt::{self, Debug},
    hash::{Hash, Hasher},
};

use serde_json::{Map, Value};

use libcryptsetup_rs::SafeMemHandle;

use crate::{
    engine::types::{ClevisInfo, MaybeInconsistent},
    stratis::{StratisError, StratisResult},
};

/// A handle for memory designed to safely handle Stratis passphrases. It can
/// be coerced to a slice reference for use in read-only operations.
#[allow(clippy::non_send_fields_in_send_ty)]
pub struct SizedKeyMemory {
    mem: SafeMemHandle,
    size: usize,
}

impl SizedKeyMemory {
    pub fn new(mem: SafeMemHandle, size: usize) -> SizedKeyMemory {
        SizedKeyMemory { mem, size }
    }
}

// This is safe to send across threads because the *mut c_void pointer is always
// allocated in the heap by libcryptsetup which is accessible globally to all threads
// in the process.
unsafe impl Send for SizedKeyMemory {}

impl Debug for SizedKeyMemory {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self.as_ref())
    }
}

impl AsRef<[u8]> for SizedKeyMemory {
    fn as_ref(&self) -> &[u8] {
        &self.mem.as_ref()[..self.size]
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum EncryptionInfo {
    KeyDesc(KeyDescription),
    ClevisInfo(ClevisInfo),
    Both(KeyDescription, ClevisInfo),
}

impl EncryptionInfo {
    /// Convert two optional encryption parameters into an EncryptionInfo enum.
    pub fn from_options(options: (Option<KeyDescription>, Option<ClevisInfo>)) -> Option<Self> {
        match options {
            (Some(kd), Some(ci)) => Some(EncryptionInfo::Both(kd, ci)),
            (Some(kd), _) => Some(EncryptionInfo::KeyDesc(kd)),
            (_, Some(ci)) => Some(EncryptionInfo::ClevisInfo(ci)),
            (None, None) => None,
        }
    }

    /// Set the key description.
    pub fn set_key_desc(self, key_desc: KeyDescription) -> Self {
        match self {
            EncryptionInfo::KeyDesc(_) => EncryptionInfo::KeyDesc(key_desc),
            EncryptionInfo::ClevisInfo(ci) => EncryptionInfo::Both(key_desc, ci),
            EncryptionInfo::Both(_, ci) => EncryptionInfo::Both(key_desc, ci),
        }
    }

    /// Unset the key description. If only Clevis info is set, no action is taken.
    /// Precondition: matches!(self, EncryptionInfo::Both(_, _) | EncryptonInfo::ClevisInfo(_))
    pub fn unset_key_desc(self) -> Self {
        match self {
            EncryptionInfo::KeyDesc(_) => {
                panic!("Cannot convert from encrypted to unencrypted device");
            }
            EncryptionInfo::Both(_, ci) => EncryptionInfo::ClevisInfo(ci),
            unchanged => unchanged,
        }
    }

    /// Set Clevis information.
    pub fn set_clevis_info(self, clevis_info: ClevisInfo) -> Self {
        match self {
            EncryptionInfo::ClevisInfo(_) => EncryptionInfo::ClevisInfo(clevis_info),
            EncryptionInfo::KeyDesc(kd) => EncryptionInfo::Both(kd, clevis_info),
            EncryptionInfo::Both(kd, _) => EncryptionInfo::Both(kd, clevis_info),
        }
    }

    /// Unset the Clevis info. If only the key description is set, no action is taken.
    /// Precondition: matches!(self, EncryptionInfo::Both(_, _) | EncryptonInfo::KeyDesc(_))
    pub fn unset_clevis_info(self) -> Self {
        match self {
            EncryptionInfo::ClevisInfo(_) => {
                panic!("Cannot convert from encrypted to unencrypted device");
            }
            EncryptionInfo::Both(kd, _) => EncryptionInfo::KeyDesc(kd),
            unchanged => unchanged,
        }
    }

    /// Get an optional key description from the encryption information.
    pub fn key_description(&self) -> Option<&KeyDescription> {
        match self {
            EncryptionInfo::Both(kd, _) | EncryptionInfo::KeyDesc(kd) => Some(kd),
            _ => None,
        }
    }

    /// Get optional Clevis information from the encryption information.
    pub fn clevis_info(&self) -> Option<&ClevisInfo> {
        match self {
            EncryptionInfo::Both(_, ci) | EncryptionInfo::ClevisInfo(ci) => Some(ci),
            _ => None,
        }
    }
}

impl fmt::Display for EncryptionInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let key_desc_str = if let Some(kd) = self.key_description() {
            format!("key description: \"{}\"", kd.as_application_str())
        } else {
            "no key description".to_string()
        };
        if let Some((pin, config)) = self.clevis_info() {
            write!(
                f,
                "{}, clevis pin: \"{}\", clevis configuration: \"{}\"",
                key_desc_str, pin, config
            )
        } else {
            write!(f, "{}, no Clevis information", key_desc_str)
        }
    }
}

// Implement Hash explicitly because Value does not implement Hash.
// The reason Value does not implement Hash is that some JSON is really big
// and hashing it would be expensive. This JSON probably won't be, but it
// serves no obvious purpose to stringify it and then hash it.
// Necessary Hash Property: \forall x_1, x_2 in EncryptionInfo,
// if x_1 == x_2, then hash(x_1) == hash(x_2) obviously holds.
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for EncryptionInfo {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.key_description().hash(state);
        self.clevis_info().map(|(pin, _)| pin).hash(state);
    }
}

impl<'a> Into<Value> for &'a EncryptionInfo {
    fn into(self) -> Value {
        let mut json = Map::new();
        if let Some(kd) = self.key_description() {
            json.insert(
                "key_description".to_string(),
                Value::from(kd.as_application_str()),
            );
        }
        if let Some(info) = self.clevis_info() {
            json.insert("clevis_pin".to_string(), Value::from(info.0.to_owned()));
            json.insert("clevis_config".to_string(), info.1.clone());
        }
        Value::from(json)
    }
}

impl TryFrom<PoolEncryptionInfo> for EncryptionInfo {
    type Error = StratisError;

    fn try_from(pei: PoolEncryptionInfo) -> StratisResult<Self> {
        match pei {
            PoolEncryptionInfo::KeyDesc(MaybeInconsistent::No(kd)) => {
                Ok(EncryptionInfo::KeyDesc(kd))
            },
            PoolEncryptionInfo::ClevisInfo(MaybeInconsistent::No(ci)) => {
                Ok(EncryptionInfo::ClevisInfo(ci))
            },
            PoolEncryptionInfo::Both(MaybeInconsistent::No(kd), MaybeInconsistent::No(ci)) => {
                Ok(EncryptionInfo::Both(kd, ci))
            },
            _ => {
                Err(StratisError::Msg("Cannot determine encryption information from metadata that is inconsistent across devices in a pool".to_string()))
            }
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum PoolEncryptionInfo {
    KeyDesc(MaybeInconsistent<KeyDescription>),
    ClevisInfo(MaybeInconsistent<ClevisInfo>),
    Both(
        MaybeInconsistent<KeyDescription>,
        MaybeInconsistent<ClevisInfo>,
    ),
}

impl PoolEncryptionInfo {
    /// Reconcile two PoolEncryptionInfo records.
    ///
    /// Because rollback failure can result in some devices having a key description
    /// or Clevis info and some not having that information, any reconciliation
    /// for Some(_) and None will result in Some(MaybeInconsistent::Yes).
    fn add_enc_info<I>(self, info: I) -> Self
    where
        PoolEncryptionInfo: From<I>,
    {
        let pei = PoolEncryptionInfo::from(info);
        match (self, pei) {
            (PoolEncryptionInfo::KeyDesc(kd1), PoolEncryptionInfo::KeyDesc(kd2)) => {
                if kd1 != kd2 {
                    PoolEncryptionInfo::KeyDesc(MaybeInconsistent::Yes)
                } else {
                    PoolEncryptionInfo::KeyDesc(kd1)
                }
            }
            (PoolEncryptionInfo::ClevisInfo(ci1), PoolEncryptionInfo::ClevisInfo(ci2)) => {
                if ci1 != ci2 {
                    PoolEncryptionInfo::ClevisInfo(MaybeInconsistent::Yes)
                } else {
                    PoolEncryptionInfo::ClevisInfo(ci1)
                }
            }
            (PoolEncryptionInfo::Both(kd1, ci1), PoolEncryptionInfo::Both(kd2, ci2)) => {
                PoolEncryptionInfo::Both(
                    if kd1 != kd2 {
                        MaybeInconsistent::Yes
                    } else {
                        kd1
                    },
                    if ci1 != ci2 {
                        MaybeInconsistent::Yes
                    } else {
                        ci1
                    },
                )
            }
            (PoolEncryptionInfo::KeyDesc(_), PoolEncryptionInfo::ClevisInfo(_))
            | (PoolEncryptionInfo::ClevisInfo(_), PoolEncryptionInfo::KeyDesc(_)) => {
                PoolEncryptionInfo::Both(MaybeInconsistent::Yes, MaybeInconsistent::Yes)
            }
            (PoolEncryptionInfo::KeyDesc(kd1), PoolEncryptionInfo::Both(kd2, _))
            | (PoolEncryptionInfo::Both(kd1, _), PoolEncryptionInfo::KeyDesc(kd2)) => {
                PoolEncryptionInfo::Both(
                    if kd1 != kd2 {
                        MaybeInconsistent::Yes
                    } else {
                        kd1
                    },
                    MaybeInconsistent::Yes,
                )
            }
            (PoolEncryptionInfo::ClevisInfo(ci1), PoolEncryptionInfo::Both(_, ci2))
            | (PoolEncryptionInfo::Both(_, ci1), PoolEncryptionInfo::ClevisInfo(ci2)) => {
                PoolEncryptionInfo::Both(
                    MaybeInconsistent::Yes,
                    if ci1 != ci2 {
                        MaybeInconsistent::Yes
                    } else {
                        ci1
                    },
                )
            }
        }
    }

    pub fn is_inconsistent(&self) -> bool {
        matches!(
            self,
            PoolEncryptionInfo::KeyDesc(MaybeInconsistent::Yes)
                | PoolEncryptionInfo::ClevisInfo(MaybeInconsistent::Yes)
                | PoolEncryptionInfo::Both(MaybeInconsistent::Yes, _)
                | PoolEncryptionInfo::Both(_, MaybeInconsistent::Yes)
        )
    }

    pub fn key_description(&self) -> StratisResult<Option<&KeyDescription>> {
        match self {
            PoolEncryptionInfo::KeyDesc(kd) | PoolEncryptionInfo::Both(kd, _) => {
                if let MaybeInconsistent::No(ref key_description) = kd {
                    Ok(Some(key_description))
                } else {
                    Err(StratisError::Msg(
                        "Key description is inconsistent across devices".to_string(),
                    ))
                }
            }
            _ => Ok(None),
        }
    }

    pub fn clevis_info(&self) -> StratisResult<Option<&ClevisInfo>> {
        match self {
            PoolEncryptionInfo::ClevisInfo(ci) | PoolEncryptionInfo::Both(_, ci) => {
                if let MaybeInconsistent::No(ref clevis_info) = ci {
                    Ok(Some(clevis_info))
                } else {
                    Err(StratisError::Msg(
                        "Clevis information is inconsistent across devices".to_string(),
                    ))
                }
            }
            _ => Ok(None),
        }
    }
}

impl From<&EncryptionInfo> for PoolEncryptionInfo {
    fn from(enc_info: &EncryptionInfo) -> Self {
        match enc_info {
            EncryptionInfo::KeyDesc(ref kd) => {
                PoolEncryptionInfo::KeyDesc(MaybeInconsistent::No(kd.to_owned()))
            }
            EncryptionInfo::ClevisInfo(ref ci) => {
                PoolEncryptionInfo::ClevisInfo(MaybeInconsistent::No(ci.to_owned()))
            }
            EncryptionInfo::Both(ref kd, ref ci) => PoolEncryptionInfo::Both(
                MaybeInconsistent::No(kd.to_owned()),
                MaybeInconsistent::No(ci.to_owned()),
            ),
        }
    }
}

impl<'a, I> From<I> for PoolEncryptionInfo
where
    I: IntoIterator<Item = &'a EncryptionInfo>,
{
    // Precondition: Iterator must have at least one item.
    fn from(into_iterator: I) -> Self {
        let mut iterator = into_iterator.into_iter();
        match iterator.next() {
            Some(ei) => iterator.fold(PoolEncryptionInfo::from(ei), |pool_enc_info, next| {
                pool_enc_info.add_enc_info(next)
            }),
            None => panic!("Cannot supply empty iterator"),
        }
    }
}

/// A data type respresenting a key description for the kernel keyring
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct KeyDescription(String);

impl KeyDescription {
    /// Return the application-level key description (the key description with no
    /// Stratis prefix added).
    pub fn as_application_str(&self) -> &str {
        &self.0
    }
}

// Key descriptions with ';'s are disallowed because a key description
// containing a ';' will not be able to be correctly parsed from the kernel's
// describe string, which uses ';'s as field delimiters.
impl TryFrom<String> for KeyDescription {
    type Error = StratisError;

    fn try_from(s: String) -> StratisResult<KeyDescription> {
        if s.contains(';') {
            Err(StratisError::Msg(format!(
                "Key description {} contains a ';'",
                s
            )))
        } else {
            Ok(KeyDescription(s))
        }
    }
}

impl<'a> TryFrom<&'a String> for KeyDescription {
    type Error = StratisError;

    fn try_from(s: &String) -> StratisResult<KeyDescription> {
        KeyDescription::try_from(s.to_owned())
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::sync::{Arc, Condvar, Mutex};

use threadpool::ThreadPool;

use gc::root::Slot;
use gc::{Address, Region};

pub fn start(rootset: &[Slot], heap: Region, perm: Region, number_workers: usize) {
    let mut shared = Shared::new();

    for root in rootset {
        let root_ptr = root.get();

        if heap.contains(root_ptr) {
            let root_obj = root_ptr.to_mut_obj();

            if !root_obj.header().is_marked() {
                root_obj.header_mut().mark();
                shared.queue.push(Segment::with(root_ptr));
            }
        } else {
            debug_assert!(root_ptr.is_null() || perm.contains(root_ptr));
        }
    }

    let shared = Arc::new((Mutex::new(shared), Condvar::new()));
    let pool = ThreadPool::new(number_workers);

    for _ in 0..number_workers {
        let heap_region = heap.clone();
        let perm_region = perm.clone();
        let shared = shared.clone();

        pool.execute(move || {
            let mut local_segment = Segment::new();
            let (shared, cvar) = (&shared.0, &shared.1);

            'outer: loop {
                let object_addr = if !local_segment.is_empty() {
                    local_segment.pop().expect("should be non-empty")
                } else {
                    let mut shared = shared.lock().unwrap();

                    loop {
                        if shared.done {
                            break 'outer;
                        }

                        match shared.queue.pop() {
                            Some(segment) => {
                                local_segment = segment;
                                continue 'outer;
                            }

                            None => {
                                shared.blocked_workers += 1;

                                if shared.blocked_workers == number_workers {
                                    shared.done = true;
                                    cvar.notify_all();
                                    break 'outer;
                                }

                                shared = cvar.wait(shared).unwrap();
                                shared.blocked_workers -= 1;
                            }
                        };
                    }
                };

                let object = object_addr.to_mut_obj();

                object.visit_reference_fields(|field| {
                    let field_addr = field.get();

                    if heap_region.contains(field_addr) {
                        let field_obj = field_addr.to_mut_obj();

                        if !field_obj.header().is_marked() {
                            field_obj.header_mut().mark();

                            if local_segment.has_capacity() {
                                local_segment.push(field_addr);
                            } else {
                                let new_local_segment = Segment::with(field_addr);
                                let old_local_segment =
                                    mem::replace(&mut local_segment, new_local_segment);
                                let mut shared = shared.lock().unwrap();
                                shared.queue.push(old_local_segment);
                                cvar.notify_one();
                            }
                        }
                    } else {
                        debug_assert!(field_addr.is_null() || perm_region.contains(field_addr));
                    }
                });
            }
        });
    }

    pool.join();
}

struct Shared {
    blocked_workers: usize,
    queue: Vec<Segment>,
    done: bool,
}

impl Shared {
    fn new() -> Shared {
        Shared {
            blocked_workers: 0,
            queue: Vec::new(),
            done: false,
        }
    }
}

const SEGMENT_SIZE: usize = 16;

struct Segment {
    data: Vec<Address>,
}

impl Segment {
    fn new() -> Segment {
        Segment {
            data: Vec::with_capacity(SEGMENT_SIZE),
        }
    }

    fn empty() -> Segment {
        Segment {
            data: Vec::new(),
        }
    }

    fn with(addr: Address) -> Segment {
        let mut segment = Segment::new();
        segment.data.push(addr);

        segment
    }

    fn has_capacity(&self) -> bool {
        self.data.len() < SEGMENT_SIZE
    }

    fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    fn push(&mut self, addr: Address) {
        debug_assert!(self.has_capacity());
        self.data.push(addr);
    }

    fn pop(&mut self) -> Option<Address> {
        self.data.pop()
    }
}<commit_msg>swiper: name worker threads<commit_after>use std::mem;
use std::sync::{Arc, Condvar, Mutex};

use threadpool::ThreadPool;

use gc::root::Slot;
use gc::{Address, Region};

pub fn start(rootset: &[Slot], heap: Region, perm: Region, number_workers: usize) {
    let mut shared = Shared::new();

    for root in rootset {
        let root_ptr = root.get();

        if heap.contains(root_ptr) {
            let root_obj = root_ptr.to_mut_obj();

            if !root_obj.header().is_marked() {
                root_obj.header_mut().mark();
                shared.queue.push(Segment::with(root_ptr));
            }
        } else {
            debug_assert!(root_ptr.is_null() || perm.contains(root_ptr));
        }
    }

    let shared = Arc::new((Mutex::new(shared), Condvar::new()));
    let pool = ThreadPool::with_name("gc-worker", number_workers);

    for _ in 0..number_workers {
        let heap_region = heap.clone();
        let perm_region = perm.clone();
        let shared = shared.clone();

        pool.execute(move || {
            let mut local_segment = Segment::new();
            let (shared, cvar) = (&shared.0, &shared.1);

            'outer: loop {
                let object_addr = if !local_segment.is_empty() {
                    local_segment.pop().expect("should be non-empty")
                } else {
                    let mut shared = shared.lock().unwrap();

                    loop {
                        if shared.done {
                            break 'outer;
                        }

                        match shared.queue.pop() {
                            Some(segment) => {
                                local_segment = segment;
                                continue 'outer;
                            }

                            None => {
                                shared.blocked_workers += 1;

                                if shared.blocked_workers == number_workers {
                                    shared.done = true;
                                    cvar.notify_all();
                                    break 'outer;
                                }

                                shared = cvar.wait(shared).unwrap();
                                shared.blocked_workers -= 1;
                            }
                        };
                    }
                };

                let object = object_addr.to_mut_obj();

                object.visit_reference_fields(|field| {
                    let field_addr = field.get();

                    if heap_region.contains(field_addr) {
                        let field_obj = field_addr.to_mut_obj();

                        if !field_obj.header().is_marked() {
                            field_obj.header_mut().mark();

                            if local_segment.has_capacity() {
                                local_segment.push(field_addr);
                            } else {
                                let new_local_segment = Segment::with(field_addr);
                                let old_local_segment =
                                    mem::replace(&mut local_segment, new_local_segment);
                                let mut shared = shared.lock().unwrap();
                                shared.queue.push(old_local_segment);
                                cvar.notify_one();
                            }
                        }
                    } else {
                        debug_assert!(field_addr.is_null() || perm_region.contains(field_addr));
                    }
                });
            }
        });
    }

    pool.join();
}

struct Shared {
    blocked_workers: usize,
    queue: Vec<Segment>,
    done: bool,
}

impl Shared {
    fn new() -> Shared {
        Shared {
            blocked_workers: 0,
            queue: Vec::new(),
            done: false,
        }
    }
}

const SEGMENT_SIZE: usize = 16;

struct Segment {
    data: Vec<Address>,
}

impl Segment {
    fn new() -> Segment {
        Segment {
            data: Vec::with_capacity(SEGMENT_SIZE),
        }
    }

    fn empty() -> Segment {
        Segment {
            data: Vec::new(),
        }
    }

    fn with(addr: Address) -> Segment {
        let mut segment = Segment::new();
        segment.data.push(addr);

        segment
    }

    fn has_capacity(&self) -> bool {
        self.data.len() < SEGMENT_SIZE
    }

    fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    fn push(&mut self, addr: Address) {
        debug_assert!(self.has_capacity());
        self.data.push(addr);
    }

    fn pop(&mut self) -> Option<Address> {
        self.data.pop()
    }
}<|endoftext|>


<commit_before>use crate::prelude::*;

/// Create the `main` function which will initialize the rust runtime and call
/// users main function.
pub fn maybe_create_entry_wrapper(tcx: TyCtxt<'_>, module: &mut Module<impl Backend + 'static>) {
    use rustc::middle::lang_items::StartFnLangItem;
    use rustc::session::config::EntryFnType;

    let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
        Some((def_id, entry_ty)) => (
            def_id,
            match entry_ty {
                EntryFnType::Main => true,
                EntryFnType::Start => false,
            },
        ),
        None => return,
    };

    create_entry_fn(tcx, module, main_def_id, use_start_lang_item);

    fn create_entry_fn(
        tcx: TyCtxt<'_>,
        m: &mut Module<impl Backend + 'static>,
        rust_main_def_id: DefId,
        use_start_lang_item: bool,
    ) {
        let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
        // Given that `main()` has no arguments,
        // then its return type cannot have
        // late-bound regions, since late-bound
        // regions must appear in the argument
        // listing.
        let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap());

        let cmain_sig = Signature {
            params: vec![
                AbiParam::new(m.target_config().pointer_type()),
                AbiParam::new(m.target_config().pointer_type()),
            ],
            returns: vec![AbiParam::new(
                m.target_config().pointer_type(), /*isize*/
            )],
            call_conv: CallConv::triple_default(m.isa().triple()),
        };

        let cmain_func_id = m
            .declare_function("main", Linkage::Export, &cmain_sig)
            .unwrap();

        let instance = Instance::mono(tcx, rust_main_def_id);

        let (main_name, main_sig) =
            get_function_name_and_sig(tcx, m.isa().triple(), instance, false);
        let main_func_id = m
            .declare_function(&main_name, Linkage::Import, &main_sig)
            .unwrap();

        let mut ctx = Context::new();
        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig.clone());
        {
            let mut func_ctx = FunctionBuilderContext::new();
            let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

            let block = bcx.create_block();
            bcx.switch_to_block(block);
            let arg_argc = bcx.append_block_param(block, m.target_config().pointer_type());
            let arg_argv = bcx.append_block_param(block, m.target_config().pointer_type());

            crate::atomic_shim::init_global_lock(m, &mut bcx);

            let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);

            let call_inst = if use_start_lang_item {
                let start_def_id = tcx.require_lang_item(StartFnLangItem, None);
                let start_instance = Instance::resolve(
                    tcx,
                    ParamEnv::reveal_all(),
                    start_def_id,
                    tcx.intern_substs(&[main_ret_ty.into()]),
                )
                .unwrap();
                let start_func_id = import_function(tcx, m, start_instance);

                let main_val = bcx
                    .ins()
                    .func_addr(m.target_config().pointer_type(), main_func_ref);

                let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
                bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
            } else {
                // using user-defined start fn
                bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
            };

            let result = bcx.inst_results(call_inst)[0];
            bcx.ins().return_(&[result]);
            bcx.seal_all_blocks();
            bcx.finalize();
        }
        m.define_function(cmain_func_id, &mut ctx).unwrap();
    }
}
<commit_msg>Check for main in current module before codegen of entry wrapper<commit_after>use crate::prelude::*;

/// Create the `main` function which will initialize the rust runtime and call
/// users main function.
pub fn maybe_create_entry_wrapper(tcx: TyCtxt<'_>, module: &mut Module<impl Backend + 'static>) {
    use rustc::middle::lang_items::StartFnLangItem;
    use rustc::session::config::EntryFnType;

    let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
        Some((def_id, entry_ty)) => (
            def_id,
            match entry_ty {
                EntryFnType::Main => true,
                EntryFnType::Start => false,
            },
        ),
        None => return,
    };

    let instance = Instance::mono(tcx, main_def_id);
    if module.get_name(&*tcx.symbol_name(instance).name.as_str()).is_none() {
        return;
    }

    create_entry_fn(tcx, module, main_def_id, use_start_lang_item);

    fn create_entry_fn(
        tcx: TyCtxt<'_>,
        m: &mut Module<impl Backend + 'static>,
        rust_main_def_id: DefId,
        use_start_lang_item: bool,
    ) {
        let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
        // Given that `main()` has no arguments,
        // then its return type cannot have
        // late-bound regions, since late-bound
        // regions must appear in the argument
        // listing.
        let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap());

        let cmain_sig = Signature {
            params: vec![
                AbiParam::new(m.target_config().pointer_type()),
                AbiParam::new(m.target_config().pointer_type()),
            ],
            returns: vec![AbiParam::new(
                m.target_config().pointer_type(), /*isize*/
            )],
            call_conv: CallConv::triple_default(m.isa().triple()),
        };

        let cmain_func_id = m
            .declare_function("main", Linkage::Export, &cmain_sig)
            .unwrap();

        let instance = Instance::mono(tcx, rust_main_def_id);

        let (main_name, main_sig) =
            get_function_name_and_sig(tcx, m.isa().triple(), instance, false);
        let main_func_id = m
            .declare_function(&main_name, Linkage::Import, &main_sig)
            .unwrap();

        let mut ctx = Context::new();
        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig.clone());
        {
            let mut func_ctx = FunctionBuilderContext::new();
            let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

            let block = bcx.create_block();
            bcx.switch_to_block(block);
            let arg_argc = bcx.append_block_param(block, m.target_config().pointer_type());
            let arg_argv = bcx.append_block_param(block, m.target_config().pointer_type());

            crate::atomic_shim::init_global_lock(m, &mut bcx);

            let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);

            let call_inst = if use_start_lang_item {
                let start_def_id = tcx.require_lang_item(StartFnLangItem, None);
                let start_instance = Instance::resolve(
                    tcx,
                    ParamEnv::reveal_all(),
                    start_def_id,
                    tcx.intern_substs(&[main_ret_ty.into()]),
                )
                .unwrap();
                let start_func_id = import_function(tcx, m, start_instance);

                let main_val = bcx
                    .ins()
                    .func_addr(m.target_config().pointer_type(), main_func_ref);

                let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
                bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
            } else {
                // using user-defined start fn
                bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
            };

            let result = bcx.inst_results(call_inst)[0];
            bcx.ins().return_(&[result]);
            bcx.seal_all_blocks();
            bcx.finalize();
        }
        m.define_function(cmain_func_id, &mut ctx).unwrap();
    }
}
<|endoftext|>