<commit_before>/// # `repository` - configuration data and other persistent data w.r.t. a single repository.
///
/// An Attaca repository's metadata is stored in the `.attaca` folder of a repository. The internal
/// structure of the metadata folder looks like this:
///
/// ```ignore
/// _ .attaca
/// +-- config.toml
/// +-_ catalogs
///    +-- <remote-name>.catalog
/// +-- local.catalog
/// +-_ blobs
///    +-- ... locally stored blobs named by hash
/// ```

use std::borrow::Cow;
use std::collections::HashMap;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::sync::Mutex;

use itertools::Itertools;
use toml;

use {METADATA_PATH, BLOBS_PATH, CONFIG_PATH, REMOTE_CATALOGS_PATH, LOCAL_CATALOG_PATH};
use catalog::{Catalog, CatalogTrie};
use errors::*;

/// The persistent configuration data for a single pool of a RADOS cluster.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CephCfg {
    /// Path to a ceph.conf file.
    pub conf_file: Option<PathBuf>,

    /// The working RADOS object pool.
    pub pool: String,

    /// The working RADOS user.
    pub user: String,

    /// Ceph configuration options, stored directly.
    #[serde(serialize_with = "toml::ser::tables_last")]
    pub conf_options: HashMap<String, String>,
}

/// The persistent configuration data for an etcd cluster.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EtcdCfg {
    /// A list of cluster members to attempt connections to.
    pub cluster: Vec<String>,
}

/// The persistent configuration data for a single remote.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RemoteCfg {
    /// The remote object store.
    ///
    /// TODO: Support object stores other than Ceph/RADOS.
    pub object_store: CephCfg,

    /// The remote ref store.
    ///
    /// TODO: Support ref stores other than etcd.
    pub ref_store: EtcdCfg,
}

/// The persistent data, stored in a repository's config.toml.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    /// Named remotes for this repository.
    #[serde(serialize_with = "toml::ser::tables_last")]
    pub remotes: HashMap<String, RemoteCfg>,
}

impl Default for Config {
    fn default() -> Config {
        Config { remotes: HashMap::new() }
    }
}

/// The type of a valid repository.
#[derive(Debug)]
pub struct Repository {
    /// Loaded configuration from `.attaca/config.toml`.
    pub config: Config,

    /// Catalogs for local and remote object stores.
    catalogs: Mutex<HashMap<Option<String>, Option<Catalog>>>,

    /// The absolute path to the root of the repository.
    path: PathBuf,

    /// The absolute path to the repository's config file.
    config_path: PathBuf,

    /// The absolute path to the blob store of the repository.
    blob_path: PathBuf,

    /// The absolute path to the local catalog.
    local_catalog_path: PathBuf,

    /// The absolute path to the remote catalog directory of the repository.
    remote_catalogs_path: PathBuf,
}

impl Repository {
    /// Initialize a repository.
    pub fn init<P: AsRef<Path>>(path: P) -> Result<()> {
        let path_ref = path.as_ref();

        let metadata_path = path_ref.join(*METADATA_PATH);
        if metadata_path.is_dir() {
            bail!(
                "a repository already exists at {}!",
                metadata_path.to_string_lossy()
            );
        }

        fs::create_dir_all(&metadata_path).chain_err(|| {
            format!("error creating {}", metadata_path.display())
        })?;

        let blobs_path = path_ref.join(&*BLOBS_PATH);
        fs::create_dir_all(&blobs_path).chain_err(|| {
            format!("error creating {}", blobs_path.display())
        })?;

        let remote_catalogs_path = path_ref.join(&*REMOTE_CATALOGS_PATH);
        fs::create_dir_all(&remote_catalogs_path).chain_err(|| {
            format!("error creating {}", remote_catalogs_path.display())
        })?;

        let config_path = path_ref.join(&*CONFIG_PATH);
        File::create(&config_path)
            .and_then(|mut cfg_file| {
                cfg_file.write_all(&toml::to_vec(&Config::default()).unwrap())
            })
            .chain_err(|| format!("error creating {}", config_path.display()))?;

        Ok(())
    }

    /// Load repository data.
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Repository> {
        let path_ref = path.as_ref();

        let metadata_path = path_ref.join(&*METADATA_PATH);

        if !metadata_path.is_dir() {
            bail!(
                "no repository found at {}!",
                metadata_path.to_string_lossy()
            );
        }

        let config_path = path_ref.join(&*CONFIG_PATH);

        let config = {
            let mut config_file = File::open(&config_path).chain_err(|| {
                format!(
                    "malformed repository at {}",
                    metadata_path.to_string_lossy()
                )
            })?;
            let mut config_string = String::new();
            config_file.read_to_string(&mut config_string)?;

            toml::from_str::<Config>(&config_string)?
        };

        let catalogs = {
            let mut catalog_map: HashMap<_, _> = config
                .remotes
                .keys()
                .map(|key| (Some(key.to_owned()), None))
                .collect();
            catalog_map.insert(None, None);

            Mutex::new(catalog_map)
        };

        Ok(Repository {
            config,
            catalogs,
            path: path_ref.to_owned(),
            config_path,
            blob_path: path_ref.join(&*BLOBS_PATH),
            local_catalog_path: path_ref.join(&*LOCAL_CATALOG_PATH),
            remote_catalogs_path: path_ref.join(&*REMOTE_CATALOGS_PATH),
        })
    }

    /// Move backwards towards the root of the filesystem searching for a valid repository.
    pub fn find<P: AsRef<Path>>(path: P) -> Result<Repository> {
        let mut attaca_path = path.as_ref().to_owned();

        while !attaca_path.join(".attaca").is_dir() {
            if !attaca_path.pop() {
                bail!(
                    "the directory {} is not a subdirectory of a repository!",
                    path.as_ref().to_string_lossy()
                );
            }
        }

        Self::load(attaca_path)
    }

    pub fn make_local_catalog(&self) -> Result<Catalog> {
        let mut objects = CatalogTrie::new();

        for byte0_res in self.blob_path.read_dir()? {
            let byte0 = byte0_res?;

            for byte1_res in byte0.path().read_dir()? {
                let byte1 = byte1_res?;

                for object_res in byte1.path().read_dir()? {
                    let object = object_res?;

                    // Turn the path back into a hash.
                    let path = object.path();
                    let hash_ending = path.file_name().unwrap().to_string_lossy();
                    let ending_parent = path.parent().unwrap();
                    let hash_second = ending_parent.file_name().unwrap().to_string_lossy();
                    let hash_first = ending_parent
                        .parent()
                        .unwrap()
                        .file_name()
                        .unwrap()
                        .to_string_lossy();

                    let hash_string = [hash_first, hash_second, hash_ending].into_iter().join("");
                    let hash = hash_string.parse()?;

                    objects.insert(hash);
                }
            }
        }

        Catalog::new(objects, self.local_catalog_path.clone())
    }

    pub fn get_catalog(&self, name_opt: Option<String>) -> Result<Catalog> {
        let mut catalogs_lock = self.catalogs.lock().unwrap();

        match catalogs_lock.get(&name_opt) {
            Some(&Some(ref catalog)) => return Ok(catalog.clone()),
            Some(&None) => {}
            None => bail!(ErrorKind::CatalogNotFound(name_opt)),
        }

        let catalog_path = match name_opt {
            Some(ref name) => {
                Cow::Owned(self.remote_catalogs_path.join(format!("{}.catalog", name)))
            }
            None => Cow::Borrowed(&self.local_catalog_path),
        };
        let catalog = Catalog::load(catalog_path.clone().into_owned()).chain_err(|| {
            ErrorKind::CatalogLoad(catalog_path.into_owned())
        })?;
        catalogs_lock.insert(name_opt, Some(catalog.clone()));

        Ok(catalog)
    }

    pub fn get_blob_path(&self) -> &Path {
        &self.blob_path
    }

    /// Update the `config.toml` file.
    fn write_config(&mut self) -> Result<()> {
        let config = toml::to_vec(&self.config)?;
        let mut file = File::create(&self.config_path)?;
        file.write_all(&config)?;
        Ok(())
    }
}

impl Drop for Repository {
    fn drop(&mut self) {
        self.write_config().unwrap();
    }
}
<commit_msg>Fix docs, correct remote catalogs directory path<commit_after>/// # `repository` - configuration data and other persistent data w.r.t. a single repository.
///
/// An Attaca repository's metadata is stored in the `.attaca` folder of a repository. The internal
/// structure of the metadata folder looks like this:
///
/// ```ignore
/// _ .attaca
/// +-- config.toml
/// +-_ remote-catalogs
///    +-- <remote-name>.catalog
/// +-- local.catalog
/// +-_ blobs
///    +-- ... locally stored blobs named by hash
/// ```

use std::borrow::Cow;
use std::collections::HashMap;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::sync::Mutex;

use itertools::Itertools;
use toml;

use {METADATA_PATH, BLOBS_PATH, CONFIG_PATH, REMOTE_CATALOGS_PATH, LOCAL_CATALOG_PATH};
use catalog::{Catalog, CatalogTrie};
use errors::*;

/// The persistent configuration data for a single pool of a RADOS cluster.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CephCfg {
    /// Path to a ceph.conf file.
    pub conf_file: Option<PathBuf>,

    /// The working RADOS object pool.
    pub pool: String,

    /// The working RADOS user.
    pub user: String,

    /// Ceph configuration options, stored directly.
    #[serde(serialize_with = "toml::ser::tables_last")]
    pub conf_options: HashMap<String, String>,
}

/// The persistent configuration data for an etcd cluster.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EtcdCfg {
    /// A list of cluster members to attempt connections to.
    pub cluster: Vec<String>,
}

/// The persistent configuration data for a single remote.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RemoteCfg {
    /// The remote object store.
    ///
    /// TODO: Support object stores other than Ceph/RADOS.
    pub object_store: CephCfg,

    /// The remote ref store.
    ///
    /// TODO: Support ref stores other than etcd.
    pub ref_store: EtcdCfg,
}

/// The persistent data, stored in a repository's config.toml.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    /// Named remotes for this repository.
    #[serde(serialize_with = "toml::ser::tables_last")]
    pub remotes: HashMap<String, RemoteCfg>,
}

impl Default for Config {
    fn default() -> Config {
        Config { remotes: HashMap::new() }
    }
}

/// The type of a valid repository.
#[derive(Debug)]
pub struct Repository {
    /// Loaded configuration from `.attaca/config.toml`.
    pub config: Config,

    /// Catalogs for local and remote object stores.
    catalogs: Mutex<HashMap<Option<String>, Option<Catalog>>>,

    /// The absolute path to the root of the repository.
    path: PathBuf,

    /// The absolute path to the repository's config file.
    config_path: PathBuf,

    /// The absolute path to the blob store of the repository.
    blob_path: PathBuf,

    /// The absolute path to the local catalog.
    local_catalog_path: PathBuf,

    /// The absolute path to the remote catalog directory of the repository.
    remote_catalogs_path: PathBuf,
}

impl Repository {
    /// Initialize a repository.
    pub fn init<P: AsRef<Path>>(path: P) -> Result<()> {
        let path_ref = path.as_ref();

        let metadata_path = path_ref.join(*METADATA_PATH);
        if metadata_path.is_dir() {
            bail!(
                "a repository already exists at {}!",
                metadata_path.to_string_lossy()
            );
        }

        fs::create_dir_all(&metadata_path).chain_err(|| {
            format!("error creating {}", metadata_path.display())
        })?;

        let blobs_path = path_ref.join(&*BLOBS_PATH);
        fs::create_dir_all(&blobs_path).chain_err(|| {
            format!("error creating {}", blobs_path.display())
        })?;

        let remote_catalogs_path = path_ref.join(&*REMOTE_CATALOGS_PATH);
        fs::create_dir_all(&remote_catalogs_path).chain_err(|| {
            format!("error creating {}", remote_catalogs_path.display())
        })?;

        let config_path = path_ref.join(&*CONFIG_PATH);
        File::create(&config_path)
            .and_then(|mut cfg_file| {
                cfg_file.write_all(&toml::to_vec(&Config::default()).unwrap())
            })
            .chain_err(|| format!("error creating {}", config_path.display()))?;

        Ok(())
    }

    /// Load repository data.
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Repository> {
        let path_ref = path.as_ref();

        let metadata_path = path_ref.join(&*METADATA_PATH);

        if !metadata_path.is_dir() {
            bail!(
                "no repository found at {}!",
                metadata_path.to_string_lossy()
            );
        }

        let config_path = path_ref.join(&*CONFIG_PATH);

        let config = {
            let mut config_file = File::open(&config_path).chain_err(|| {
                format!(
                    "malformed repository at {}",
                    metadata_path.to_string_lossy()
                )
            })?;
            let mut config_string = String::new();
            config_file.read_to_string(&mut config_string)?;

            toml::from_str::<Config>(&config_string)?
        };

        let catalogs = {
            let mut catalog_map: HashMap<_, _> = config
                .remotes
                .keys()
                .map(|key| (Some(key.to_owned()), None))
                .collect();
            catalog_map.insert(None, None);

            Mutex::new(catalog_map)
        };

        Ok(Repository {
            config,
            catalogs,
            path: path_ref.to_owned(),
            config_path,
            blob_path: path_ref.join(&*BLOBS_PATH),
            local_catalog_path: path_ref.join(&*LOCAL_CATALOG_PATH),
            remote_catalogs_path: path_ref.join(&*REMOTE_CATALOGS_PATH),
        })
    }

    /// Move backwards towards the root of the filesystem searching for a valid repository.
    pub fn find<P: AsRef<Path>>(path: P) -> Result<Repository> {
        let mut attaca_path = path.as_ref().to_owned();

        while !attaca_path.join(".attaca").is_dir() {
            if !attaca_path.pop() {
                bail!(
                    "the directory {} is not a subdirectory of a repository!",
                    path.as_ref().to_string_lossy()
                );
            }
        }

        Self::load(attaca_path)
    }

    pub fn make_local_catalog(&self) -> Result<Catalog> {
        let mut objects = CatalogTrie::new();

        for byte0_res in self.blob_path.read_dir()? {
            let byte0 = byte0_res?;

            for byte1_res in byte0.path().read_dir()? {
                let byte1 = byte1_res?;

                for object_res in byte1.path().read_dir()? {
                    let object = object_res?;

                    // Turn the path back into a hash.
                    let path = object.path();
                    let hash_ending = path.file_name().unwrap().to_string_lossy();
                    let ending_parent = path.parent().unwrap();
                    let hash_second = ending_parent.file_name().unwrap().to_string_lossy();
                    let hash_first = ending_parent
                        .parent()
                        .unwrap()
                        .file_name()
                        .unwrap()
                        .to_string_lossy();

                    let hash_string = [hash_first, hash_second, hash_ending].into_iter().join("");
                    let hash = hash_string.parse()?;

                    objects.insert(hash);
                }
            }
        }

        Catalog::new(objects, self.local_catalog_path.clone())
    }

    pub fn get_catalog(&self, name_opt: Option<String>) -> Result<Catalog> {
        let mut catalogs_lock = self.catalogs.lock().unwrap();

        match catalogs_lock.get(&name_opt) {
            Some(&Some(ref catalog)) => return Ok(catalog.clone()),
            Some(&None) => {}
            None => bail!(ErrorKind::CatalogNotFound(name_opt)),
        }

        let catalog_path = match name_opt {
            Some(ref name) => {
                Cow::Owned(self.remote_catalogs_path.join(format!("{}.catalog", name)))
            }
            None => Cow::Borrowed(&self.local_catalog_path),
        };
        let catalog = Catalog::load(catalog_path.clone().into_owned()).chain_err(|| {
            ErrorKind::CatalogLoad(catalog_path.into_owned())
        })?;
        catalogs_lock.insert(name_opt, Some(catalog.clone()));

        Ok(catalog)
    }

    pub fn get_blob_path(&self) -> &Path {
        &self.blob_path
    }

    /// Update the `config.toml` file.
    fn write_config(&mut self) -> Result<()> {
        let config = toml::to_vec(&self.config)?;
        let mut file = File::create(&self.config_path)?;
        file.write_all(&config)?;
        Ok(())
    }
}

impl Drop for Repository {
    fn drop(&mut self) {
        self.write_config().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::{ReadStream, Stream, StreamProducer};
use flac::metadata;
use flac::metadata::VorbisComment;

use std::env;
use std::fs::File;

const USAGE: &'static str = "
Usage: metadata streaminfo [options] <filename>
       metadata comments [options] <filename>
       metadata --help

Options:
  --block-size       Show both the max and min block size from StreamInfo.
  --frame-size       Show both the max and min frame size from StreamInfo.
  --sample-rate      Show the sample rate from StreamInfo.
  --channels         Show the number of channels from StreamInfo.
  --bits-per-sample  Show the size in bits for each sample from StreamInfo.
  --total-samples    Show total number of samples from StreamInfo.
  --md5              Show the MD5 signature from StreamInfo.
  --vendor           Show the vendor string from VorbisComment.
  --name=NAME        Show the comments matching the `NAME` from VorbisComment.
  -h, --help         Show this message.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_filename: String,
  cmd_streaminfo: bool,
  cmd_comments: bool,
  flag_block_size: bool,
  flag_frame_size: bool,
  flag_sample_rate: bool,
  flag_channels: bool,
  flag_bits_per_sample: bool,
  flag_total_samples: bool,
  flag_md5: bool,
  flag_vendor: bool,
  flag_name: Option<String>,
}

macro_rules! format_print (
  ($format_str: expr, $opt_str: expr, $data: expr, $no_flag: expr) => (
    {
      println!($format_str, if $no_flag {
        $opt_str
      } else {
        ""
      }, $data);
    }
  );
);

fn print_stream_info<P>(stream: &Stream<P>, args: &Arguments)
 where P: StreamProducer {
  let info     = stream.info();
  let no_flags = (args.flag_block_size      || args.flag_frame_size    ||
                  args.flag_sample_rate     || args.flag_channels      ||
                  args.flag_bits_per_sample || args.flag_total_samples ||
                  args.flag_md5) == false;

  if no_flags || args.flag_block_size {
    println!("Minimum block size: {} samples", info.min_block_size);
    println!("Maximum block size: {} samples", info.max_block_size);
  }

  if no_flags || args.flag_frame_size {
    println!("Minimum frame size: {} bytes", info.min_frame_size);
    println!("Maximum frame size: {} bytes", info.max_frame_size);
  }

  if no_flags || args.flag_sample_rate {
    format_print!("{}{} Hz", "Sample rate: ", info.sample_rate, no_flags);
  }

  if no_flags || args.flag_channels {
    format_print!("{}{}", "Number of channels: ", info.channels, no_flags);
  }

  if no_flags || args.flag_bits_per_sample {
    format_print!("{}{}", "Bits per samples: ", info.bits_per_sample,
                                                no_flags);
  }

  if no_flags || args.flag_total_samples {
    format_print!("{}{}", "Total samples: ", info.total_samples, no_flags);
  }

  if no_flags || args.flag_md5 {
    let mut md5  = String::with_capacity(32);

    for byte in &info.md5_sum {
      let hex = format!("{:02x}", byte);

      md5.push_str(&hex);
    }

    format_print!("{}{}", "MD5 sum: ", md5, no_flags);
  }
}

fn print_vorbis_comments(vorbis_comment: &VorbisComment, args: &Arguments) {
  let no_flags  = (args.flag_vendor || args.flag_name.is_some()) == false;

  if no_flags || args.flag_vendor {
    format_print!("{}{}", "Vendor string: ", vorbis_comment.vendor_string,
                                             no_flags);
  }

  if no_flags {
    let mut index = 1;

    println!("Number of Comments: {}", vorbis_comment.comments.len());

    for (name, value) in &vorbis_comment.comments {
      println!("  {}: \"{}\" = {}", index, name, value);

      index += 1;
    }
  } else {
    if let Some(ref name) = args.flag_name {
      vorbis_comment.comments.get(name)
                             .map(|value| println!("{}", value));
    }
  }
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  let stream = Stream::<ReadStream<File>>::from_file(&args.arg_filename)
                 .expect("Couldn't parse file");

  if args.cmd_streaminfo {
    print_stream_info(&stream, &args);
  }

  for meta in stream.metadata() {
    match meta.data {
      metadata::Data::VorbisComment(ref v) => {
        if args.cmd_comments {
          print_vorbis_comments(v, &args)
        }
      }
      _                                    => continue,
    }
  }
}
<commit_msg>Add a seektable subcommand<commit_after>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::{ReadStream, Stream, StreamProducer};
use flac::metadata;
use flac::metadata::VorbisComment;

use std::env;
use std::fs::File;

const USAGE: &'static str = "
Usage: metadata streaminfo [options] <filename>
       metadata comments [options] <filename>
       metadata seektable <filename>
       metadata --help

Options:
  --block-size       Show both the max and min block size from StreamInfo.
  --frame-size       Show both the max and min frame size from StreamInfo.
  --sample-rate      Show the sample rate from StreamInfo.
  --channels         Show the number of channels from StreamInfo.
  --bits-per-sample  Show the size in bits for each sample from StreamInfo.
  --total-samples    Show total number of samples from StreamInfo.
  --md5              Show the MD5 signature from StreamInfo.
  --vendor           Show the vendor string from VorbisComment.
  --name=NAME        Show the comments matching the `NAME` from VorbisComment.
  -h, --help         Show this message.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_filename: String,
  cmd_streaminfo: bool,
  cmd_comments: bool,
  cmd_seektable: bool,
  flag_block_size: bool,
  flag_frame_size: bool,
  flag_sample_rate: bool,
  flag_channels: bool,
  flag_bits_per_sample: bool,
  flag_total_samples: bool,
  flag_md5: bool,
  flag_vendor: bool,
  flag_name: Option<String>,
}

macro_rules! format_print (
  ($format_str: expr, $opt_str: expr, $data: expr, $no_flag: expr) => (
    {
      println!($format_str, if $no_flag {
        $opt_str
      } else {
        ""
      }, $data);
    }
  );
);

fn print_stream_info<P>(stream: &Stream<P>, args: &Arguments)
 where P: StreamProducer {
  let info     = stream.info();
  let no_flags = (args.flag_block_size      || args.flag_frame_size    ||
                  args.flag_sample_rate     || args.flag_channels      ||
                  args.flag_bits_per_sample || args.flag_total_samples ||
                  args.flag_md5) == false;

  if no_flags || args.flag_block_size {
    println!("Minimum block size: {} samples", info.min_block_size);
    println!("Maximum block size: {} samples", info.max_block_size);
  }

  if no_flags || args.flag_frame_size {
    println!("Minimum frame size: {} bytes", info.min_frame_size);
    println!("Maximum frame size: {} bytes", info.max_frame_size);
  }

  if no_flags || args.flag_sample_rate {
    format_print!("{}{} Hz", "Sample rate: ", info.sample_rate, no_flags);
  }

  if no_flags || args.flag_channels {
    format_print!("{}{}", "Number of channels: ", info.channels, no_flags);
  }

  if no_flags || args.flag_bits_per_sample {
    format_print!("{}{}", "Bits per samples: ", info.bits_per_sample,
                                                no_flags);
  }

  if no_flags || args.flag_total_samples {
    format_print!("{}{}", "Total samples: ", info.total_samples, no_flags);
  }

  if no_flags || args.flag_md5 {
    let mut md5  = String::with_capacity(32);

    for byte in &info.md5_sum {
      let hex = format!("{:02x}", byte);

      md5.push_str(&hex);
    }

    format_print!("{}{}", "MD5 sum: ", md5, no_flags);
  }
}

fn print_vorbis_comments(vorbis_comment: &VorbisComment, args: &Arguments) {
  let no_flags  = (args.flag_vendor || args.flag_name.is_some()) == false;

  if no_flags || args.flag_vendor {
    format_print!("{}{}", "Vendor string: ", vorbis_comment.vendor_string,
                                             no_flags);
  }

  if no_flags {
    let mut index = 1;

    println!("Number of Comments: {}", vorbis_comment.comments.len());

    for (name, value) in &vorbis_comment.comments {
      println!("  {}: \"{}\" = {}", index, name, value);

      index += 1;
    }
  } else {
    if let Some(ref name) = args.flag_name {
      vorbis_comment.comments.get(name)
                             .map(|value| println!("{}", value));
    }
  }
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  let stream = Stream::<ReadStream<File>>::from_file(&args.arg_filename)
                 .expect("Couldn't parse file");

  if args.cmd_streaminfo {
    print_stream_info(&stream, &args);
  }

  for meta in stream.metadata() {
    match meta.data {
      metadata::Data::VorbisComment(ref v) => {
        if args.cmd_comments {
          print_vorbis_comments(v, &args)
        }
      }
      _                                    => continue,
    }
  }
}
<|endoftext|>


<commit_before>extern crate libc;

use self::libc::{size_t, c_void};
use std::ptr;
use std::mem;

const CPUSTATES: usize = 5;

#[repr(C,packed)]
pub struct CPUInfo {
    pub state: [isize; CPUSTATES],
}

impl CPUInfo {
    fn new() -> CPUInfo {
        CPUInfo {
            state: [0, 0, 0, 0, 0],
        }
    }

    pub fn fetch() -> CPUInfo {
        #[cfg(target_os = "openbsd")]
        let mut mib: [libc::c_int; 2] = [ libc::CTL_KERN, libc::KERN_CPTIME ];
        #[cfg(target_os = "freebsd")]
        let mut mib: [libc::c_int; 4] = CPUInfo::cp_time_mib();
        let mut info = CPUInfo::new();
        let buf: *mut c_void = info.state.as_mut_ptr() as *mut c_void;
        let mut size = mem::size_of::<CPUInfo>() as size_t;
        let outbuf: *mut c_void = ptr::null_mut() as *mut c_void;
        unsafe {
            libc::sysctl(&mut mib[0], mib.len() as u32, buf,
                         &mut size, outbuf, 0);
        }
        info
    }

    #[cfg(target_os = "freebsd")]
    fn cp_time_mib() -> [libc::c_int; 4] {
        let mut mib: [libc::c_int; 4] = [0, 0, 0, 0];
        unsafe {
            let mut size: usize = mib.len();
            let sctlname = "kern.cp_time";
            let name: *const i8 = sctlname.as_ptr() as *const i8;
            libc::sysctlnametomib(name, &mut mib[0], &mut size);
        }
        mib
    }

    pub fn ncpus() -> u32 {
        unsafe {
            libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as u32
        }
    }

    pub fn get_busy(&self, old: &CPUInfo) -> u32 {
        let mut diff = self.state.clone();
        let mut sum = 0;
        for i in 0..CPUSTATES {
            diff[i] = self.state[i] - old.state[i];
            sum += diff[i];
        }
        if sum == 0 { sum += 1 }
        (((sum - diff[CPUSTATES - 1]) * 100) / sum) as u32
    }
}
<commit_msg>Correct libc types<commit_after>extern crate libc;

use self::libc::{size_t, c_void, c_int, c_uint, c_char};
use std::ptr;
use std::mem;

const CPUSTATES: usize = 5;

#[repr(C,packed)]
pub struct CPUInfo {
    pub state: [isize; CPUSTATES],
}

impl CPUInfo {
    fn new() -> CPUInfo {
        CPUInfo {
            state: [0, 0, 0, 0, 0],
        }
    }

    pub fn fetch() -> CPUInfo {
        #[cfg(target_os = "openbsd")]
        let mut mib: [c_int; 2] = [ libc::CTL_KERN, libc::KERN_CPTIME ];
        #[cfg(target_os = "freebsd")]
        let mut mib: [c_int; 4] = CPUInfo::cp_time_mib();
        let mut info = CPUInfo::new();
        let buf: *mut c_void = info.state.as_mut_ptr() as *mut c_void;
        let mut size = mem::size_of::<CPUInfo>() as size_t;
        let outbuf: *mut c_void = ptr::null_mut() as *mut c_void;
        unsafe {
            libc::sysctl(&mut mib[0], mib.len() as c_uint, buf,
                         &mut size, outbuf, 0);
        }
        info
    }

    #[cfg(target_os = "freebsd")]
    fn cp_time_mib() -> [c_int; 4] {
        let mut mib: [c_int; 4] = [0, 0, 0, 0];
        unsafe {
            let mut size: size_t = mib.len();
            let sctlname = "kern.cp_time";
            let name: *const c_char =
                sctlname.as_ptr() as *const c_char;
            libc::sysctlnametomib(name, &mut mib[0], &mut size);
        }
        mib
    }

    pub fn ncpus() -> u32 {
        unsafe {
            libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as u32
        }
    }

    pub fn get_busy(&self, old: &CPUInfo) -> u32 {
        let mut diff = self.state.clone();
        let mut sum = 0;
        for i in 0..CPUSTATES {
            diff[i] = self.state[i] - old.state[i];
            sum += diff[i];
        }
        if sum == 0 { sum += 1 }
        (((sum - diff[CPUSTATES - 1]) * 100) / sum) as u32
    }
}
<|endoftext|>


<commit_before>// https://github.com/serde-rs/serde/issues/927

use std::collections::HashMap;

extern crate yaml_rust;
extern crate argparse;
#[macro_use] extern crate log;
#[macro_use] extern crate from_variants;

extern crate serde;
#[macro_use] extern crate serde_json;
extern crate serde_yaml;
#[macro_use] extern crate serde_derive;

#[derive(Clone, Serialize, Deserialize, Debug)]
enum ArgValue {
    None,
    Str(String),
    Bool(bool),
    Byte(u8),
    Int16(i16),
    Int32(i32),
    Int64(i64),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),
    Double(f64),
}

impl ArgValue {
    fn to_json(&self, n: &str) -> String {
        match *self {
            ArgValue::None             =>   "".to_string(),
            ArgValue::Str(ref v)       =>   format!("\"{}\":{}", n, v ),
            ArgValue::Bool(ref v)      =>   format!("\"{}\":{}", n, v ),
            ArgValue::Byte(ref v)      =>   format!("\"{}\":{}", n, v ),
            ArgValue::Int16(ref v)     =>   format!("\"{}\":{}", n, v ),
            ArgValue::Int32(ref v)     =>   format!("\"{}\":{}", n, v ),
            ArgValue::Int64(ref v)     =>   format!("\"{}\":{}", n, v ),
            ArgValue::UInt16(ref v)    =>   format!("\"{}\":{}", n, v ),
            ArgValue::UInt32(ref v)    =>   format!("\"{}\":{}", n, v ),
            ArgValue::UInt64(ref v)    =>   format!("\"{}\":{}", n, v ),
            ArgValue::Double(ref v)    =>   format!("\"{}\":{}", n, v ),
        }
    }
}

#[derive(Clone, Serialize, Deserialize, Debug)]
enum ArgsTag {
    Args,
    Rets,
}

#[derive(Serialize, Deserialize, Debug)]
enum DbusMessageType {
    Method,
    Signal,
}

type NamedArgs = HashMap<String, ArgValue>;
type NamedArgs2 = HashMap<String, serde_json::value::Value>;

#[derive(Serialize, Deserialize)]
struct DbusMessage {
    api_name: String,
    dbus_name: String,
    message_type: DbusMessageType,
    args: NamedArgs,
}

#[derive(Serialize, Deserialize)]
struct DbusMessageRouting(String, String, String, Vec<DbusMessage>);

#[derive(Serialize, Deserialize)]
struct ConfYaml(Vec<DbusMessageRouting>);

#[derive(Serialize, Deserialize, Debug)]
struct ClientRequest {
    #[serde(rename = "type")]
    tp: DbusMessageType,
    name: String,
    args: Option<NamedArgs2>,
    rets: Option<NamedArgs2>,
}

impl ClientRequest {
    fn to_json(&self) -> String {
        fn serialize_args_or_rets(tag: &str, ar: &Option<NamedArgs2>) -> String {
            match ar {
                &Some(ref a) => {
                    let args_serialized: Vec<_> = a.iter().map( |ret| {
                        let (n, val) = ret;
                        //val.to_json(n)
                        format!("\"{}\":{}", n, val)
                        } ).collect();
                    format!("\"{}\": {{ {}", tag, args_serialized.join(","))
                },
                &None =>  "".to_string(),
            }
        }
        let json_reply_prefix = format!("{{\"type\":\"{:?}\",\"name\":\"{}\",", &self.tp, &self.name);
        let args_serialized = serialize_args_or_rets("args", &self.args);
        let rets_serialized = serialize_args_or_rets("rets", &self.rets);
        format!("{}{}{} }} }}",json_reply_prefix, args_serialized, rets_serialized).to_string()
    }
}

#[derive(Serialize, Deserialize)]
struct ClientRequestBody(DbusMessageType, NamedArgs);

type CRequest = HashMap<String, ClientRequestBody>;

fn main()
{
    let conf = vec![
        DbusMessageRouting(
            "com.a.b.servicetest".to_string(),
            "/com/a/b/servicetest".to_string(),
            "com.a.b.IServiceTest".to_string(),
            vec![ DbusMessage { api_name: "api_name".to_string(),
                                dbus_name: "dbus_name".to_string(),
                                message_type: DbusMessageType::Method,
                                args: [
                                    ("param1".to_string(), ArgValue::Str("Hi".to_string())),
                                    ("param2".to_string(), ArgValue::Bool(true)),
                                    ("param3".to_string(), ArgValue::Int64(17i64)),
                                    ("param4".to_string(), ArgValue::Double(2.718281828f64)),
                                ].iter().cloned().collect()
                              }
            ]
        )
    ];

    let s = serde_yaml::to_string(&conf).unwrap();
    println!("s : {}", s);

    let r = ClientRequest { tp: DbusMessageType::Method, name: "api_name".to_string(),
                            args: Some([    ("param1".to_string(), json!("Hi")),
                                            ("param2".to_string(), json!(true)),
                                            ("param3".to_string(), json!(17i64)),
                                            ("param4".to_string(), json!(2.718281828f64)),
                                       ].iter().cloned().collect()),
                            rets: None,
                          };
    let rs = serde_json::to_string(&r).unwrap();
    println!("rs : {}", rs);

    let d: ClientRequest = serde_json::from_str(&rs).expect("json deserialization error");
    println!("d: {:?}", d);

    let data = "{\"type\":\"Method\",\"name\":\"utest_4p2r\",\"rets\":{\"parm1\":71,\"parm2\":12.12 } }";
    let d2: ClientRequest = serde_json::from_str(&data).expect("json deserialization error");
    println!("d2: {:?}", d2);
    println!("d2.to_json(): {}", d2.to_json());

    let rb = ClientRequestBody(DbusMessageType::Method, [
                                        ("param1".to_string(), ArgValue::Str("Hi".to_string())),
                                        ("param2".to_string(), ArgValue::Bool(true)),
                                        ("param3".to_string(), ArgValue::Int64(17i64)),
                                        ("param4".to_string(), ArgValue::Double(2.718281828f64)),
                                ].iter().cloned().collect()
                          );

    let mut a_request: CRequest = HashMap::new();
    a_request.insert("api_name".to_string(), rb);

    let rsq = serde_json::to_string(&a_request).unwrap();
    println!("rsq : {}", rsq);

    let de: CRequest = serde_json::from_str(&rsq).expect("json deserialization error");

    let rsq2 = serde_json::to_string(&de).expect("json serialization error");
    println!("rsq2 : {}", rsq2);

    for key in de.keys() {
        println!("key {}", key);
    }
    println!("key[0] : {}", de.keys().nth(0).unwrap());

}
<commit_msg>play with array (de)serialization.<commit_after>// https://github.com/serde-rs/serde/issues/927

use std::collections::HashMap;

extern crate yaml_rust;
extern crate argparse;
#[macro_use] extern crate log;
#[macro_use] extern crate from_variants;

extern crate serde;
#[macro_use] extern crate serde_json;
extern crate serde_yaml;
#[macro_use] extern crate serde_derive;

#[derive(Clone, Serialize, Deserialize, Debug)]
enum ArgValue {
    None,
    Str(String),
    Bool(bool),
    Byte(u8),
    Int16(i16),
    Int32(i32),
    Int64(i64),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),
    Double(f64),
    Array(Vec<serde_json::value::Value>),
    //Record(HashMap(String, ArgValue)),
}

impl ArgValue {
    fn to_json(&self, n: &str) -> String {
        match *self {
            ArgValue::None             =>   "".to_string(),
            ArgValue::Str(ref v)       =>   format!("\"{}\":{}", n, v ),
            ArgValue::Bool(ref v)      =>   format!("\"{}\":{}", n, v ),
            ArgValue::Byte(ref v)      =>   format!("\"{}\":{}", n, v ),
            ArgValue::Int16(ref v)     =>   format!("\"{}\":{}", n, v ),
            ArgValue::Int32(ref v)     =>   format!("\"{}\":{}", n, v ),
            ArgValue::Int64(ref v)     =>   format!("\"{}\":{}", n, v ),
            ArgValue::UInt16(ref v)    =>   format!("\"{}\":{}", n, v ),
            ArgValue::UInt32(ref v)    =>   format!("\"{}\":{}", n, v ),
            ArgValue::UInt64(ref v)    =>   format!("\"{}\":{}", n, v ),
            ArgValue::Double(ref v)    =>   format!("\"{}\":{}", n, v ),
            ArgValue::Array(ref v)     =>   format!("\"{}\":{:?}", n, v ),
        }
    }
}

#[derive(Clone, Serialize, Deserialize, Debug)]
enum ArgsTag {
    Args,
    Rets,
}

#[derive(Serialize, Deserialize, Debug)]
enum DbusMessageType {
    Method,
    Signal,
}

type NamedArgs = HashMap<String, ArgValue>;
type NamedArgs2 = HashMap<String, serde_json::value::Value>;

#[derive(Serialize, Deserialize)]
struct DbusMessage {
    api_name: String,
    dbus_name: String,
    message_type: DbusMessageType,
    args: NamedArgs,
}

#[derive(Serialize, Deserialize)]
struct DbusMessageRouting(String, String, String, Vec<DbusMessage>);

#[derive(Serialize, Deserialize)]
struct ConfYaml(Vec<DbusMessageRouting>);

#[derive(Serialize, Deserialize, Debug)]
struct ClientRequest {
    #[serde(rename = "type")]
    tp: DbusMessageType,
    name: String,
    args: Option<NamedArgs2>,
    rets: Option<NamedArgs2>,
}

impl ClientRequest {
    fn to_json(&self) -> String {
        fn serialize_args_or_rets(tag: &str, ar: &Option<NamedArgs2>) -> String {
            match ar {
                &Some(ref a) => {
                    let args_serialized: Vec<_> = a.iter().map( |ret| {
                        let (n, val) = ret;
                        //val.to_json(n)
                        format!("\"{}\":{}", n, val)
                        } ).collect();
                    format!("\"{}\": {{ {}", tag, args_serialized.join(","))
                },
                &None =>  "".to_string(),
            }
        }
        let json_reply_prefix = format!("{{\"type\":\"{:?}\",\"name\":\"{}\",", &self.tp, &self.name);
        let args_serialized = serialize_args_or_rets("args", &self.args);
        let rets_serialized = serialize_args_or_rets("rets", &self.rets);
        format!("{}{}{} }} }}",json_reply_prefix, args_serialized, rets_serialized).to_string()
    }
}

#[derive(Serialize, Deserialize)]
struct ClientRequestBody(DbusMessageType, NamedArgs);

type CRequest = HashMap<String, ClientRequestBody>;

fn main()
{
    let conf = vec![
        DbusMessageRouting(
            "com.a.b.servicetest".to_string(),
            "/com/a/b/servicetest".to_string(),
            "com.a.b.IServiceTest".to_string(),
            vec![ DbusMessage { api_name: "api_name".to_string(),
                                dbus_name: "dbus_name".to_string(),
                                message_type: DbusMessageType::Method,
                                args: [
                                    ("param1".to_string(), ArgValue::Str("Hi".to_string())),
                                    ("param2".to_string(), ArgValue::Bool(true)),
                                    ("param3".to_string(), ArgValue::Int64(17i64)),
                                    ("param4".to_string(), ArgValue::Double(2.718281828f64)),
                                    ("param5".to_string(), ArgValue::Array( vec![ json!(1.1), json!(2.2), json!(3.3), ] )),
                                ].iter().cloned().collect()
                              }
            ]
        )
    ];

    let s = serde_yaml::to_string(&conf).unwrap();
    println!("s : {}", s);

    let r = ClientRequest { tp: DbusMessageType::Method, name: "api_name".to_string(),
                            args: Some([    ("param1".to_string(), json!("Hi")),
                                            ("param2".to_string(), json!(true)),
                                            ("param3".to_string(), json!(17i64)),
                                            ("param4".to_string(), json!(2.718281828f64)),
                                            ("param5".to_string(), json!( vec![ json!(1.1), json!(2.2), json!(3.3), ] )),
                                       ].iter().cloned().collect()),
                            rets: None,
                          };
    let rs = serde_json::to_string(&r).unwrap();
    println!("rs : {}", rs);

    let d: ClientRequest = serde_json::from_str(&rs).expect("json deserialization error");
    println!("d: {:?}", d);

    let ds = serde_json::to_string(&d).unwrap();
    println!(" => ds: {}", ds);

    let data = "{\"type\":\"Method\",\"name\":\"utest_4p2r\",\"rets\":{\"parm1\":71,\"parm2\":12.12 } }";
    let d2: ClientRequest = serde_json::from_str(&data).expect("json deserialization error");
    println!("d2: {:?}", d2);
    println!("d2.to_json(): {}", d2.to_json());

    let rb = ClientRequestBody(DbusMessageType::Method, [
                                        ("param1".to_string(), ArgValue::Str("Hi".to_string())),
                                        ("param2".to_string(), ArgValue::Bool(true)),
                                        ("param3".to_string(), ArgValue::Int64(17i64)),
                                        ("param4".to_string(), ArgValue::Double(2.718281828f64)),
                                ].iter().cloned().collect()
                          );

    let mut a_request: CRequest = HashMap::new();
    a_request.insert("api_name".to_string(), rb);

    let rsq = serde_json::to_string(&a_request).unwrap();
    println!("rsq : {}", rsq);

    let de: CRequest = serde_json::from_str(&rsq).expect("json deserialization error");

    let rsq2 = serde_json::to_string(&de).expect("json serialization error");
    println!("rsq2 : {}", rsq2);

    for key in de.keys() {
        println!("key {}", key);
    }
    println!("key[0] : {}", de.keys().nth(0).unwrap());

}
<|endoftext|>


<commit_before>/*

Rule 110 is a simple cellular automaton that is universal.

The problem is to find the reverse history from a final state,
up to a limited number of iterations.

*/

extern crate quickbacktrack;

use quickbacktrack::{BackTrackSolver, Puzzle, SolveSettings};

#[derive(Clone)]
pub struct Rule110 {
	pub cells: Vec<Vec<u8>>,
}

impl Rule110 {
    pub fn next(&mut self) -> Vec<u8> {
        let last = self.cells.last().unwrap();
        let n = last.len();
        let mut new_row = vec![0; n];
        for i in 0..n {
            let input = (
                last[(i + n - 1) % n],
                last[i],
                last[(i + 1) % n]
            );
            new_row[i] = rule(input);
        }
        new_row
    }

    /// Returns `false` when a contradition is found.
    /// This is checked by checking all affected cells in next step.
    pub fn is_satisfied(&self, pos: [usize; 2], val: u8) -> bool {
        let row = pos[0];
        let col = pos[1] as isize;

        let n = self.cells[row].len() as isize;
        if row + 1 < self.cells.len() {
            // Replace with new value if looking up cell at the location.
            let f = |ind: isize| {
                let map_ind = ((col + ind + n) % n) as usize;
                if map_ind == col as usize { val }
                else { self.cells[row][map_ind] }
            };
            // [o o x] [o x o] [x o o]
            for i in -1..2 {
                let input = (
                    f(i - 1),
                    f(i),
                    f(i + 1),
                );

                let col_next = ((col + n + i) % n) as usize;
                let new_value = rule(input);
                let old_value = self.cells[row + 1][col_next];
                match (new_value, old_value) {
                    (_, 0) => {}
                    (0, _) => {}
                    (a, b) if a == b => {}
                    (_, _) => return false,
                }
            }
        }

        // Check that previous row yields value.
        if row > 0 {
            let f = |ind: isize| {
                let map_ind = ((col + ind + n) % n) as usize;
                self.cells[row - 1][map_ind]
            };
            let input = (
                f(-1),
                f(0),
                f(1),
            );
            match (rule(input), val) {
                (_, 0) => {}
                (0, _) => {}
                (a, b) if a == b => {}
                (_, _) => return false,
            }
        }

        true
    }

    pub fn possible(&self, pos: [usize; 2]) -> Vec<u8> {
        let mut res = vec![];
        for v in 1..3 {
            if self.is_satisfied(pos, v) {
                res.push(v);
            }
        }
        res
    }

    pub fn find_min_empty(&self) -> Option<[usize; 2]> {
        let mut min = None;
        let mut min_pos = None;
        for i in 0..self.cells.len() {
            for j in 0..self.cells[i].len() {
                if self.cells[i][j] == 0 {
                    let possible = self.possible([i, j]);
                    if min.is_none() || min.unwrap() >= possible.len() {
                        min = Some(possible.len());
                        min_pos = Some([i, j]);
                    }
                }
            }
        }
        return min_pos;
    }
}

/// Rule 110 extended with unknown inputs.
fn rule(state: (u8, u8, u8)) -> u8 {
    match state {
        (2, 2, 2) => 1,
        (2, 2, 1) => 2,
        (2, 1, 2) => 2,
        (2, 1, 1) => 1,
        (1, 2, 2) => 2,
        (1, 2, 1) => 2,
        (1, 1, 2) => 2,
        (1, 1, 1) => 1,

        // 1 unknown.
        (2, 2, 0) => 0,
        (2, 0, 2) => 0,
        (0, 2, 2) => 0,
        (2, 0, 1) => 0,
        (0, 2, 1) => 2,
        (2, 1, 0) => 0,
        (0, 1, 2) => 2,
        (0, 1, 1) => 1,
        (1, 2, 0) => 2,
        (1, 0, 2) => 2,
        (1, 0, 1) => 0,
        (1, 1, 0) => 0,

        // All with 2 unknowns or more has unknown result.
        (_, _, _) => 0,
    }
}

impl Puzzle for Rule110 {
    type Pos = [usize; 2];
    type Val = u8;

    fn solve_simple(&mut self) {
        loop {
			let mut found_any = false;
			for i in 0..self.cells.len() {
				for j in 0..self.cells[i].len() {
					if self.cells[i][j] != 0 { continue; }
					let possible = self.possible([i, j]);
					if possible.len() == 1 {
						self.cells[i][j] = possible[0];
						found_any = true;
					}
				}
			}
			if !found_any { break; }
		}
    }

    fn set(&mut self, pos: [usize; 2], val: u8) {
        self.cells[pos[0]][pos[1]] = val;
    }

    fn is_solved(&self) -> bool {
        for row in &self.cells {
            for col in row {
                if *col == 0 { return false; }
            }
        }
        true
    }

    fn remove(&mut self, other: &Rule110) {
        for i in 0..self.cells.len() {
            for j in 0..self.cells[i].len() {
                if other.cells[i][j] != 0 {
                    self.cells[i][j] = 0;
                }
            }
        }
    }

    fn print(&self) {
        println!("");
        for row in &self.cells {
            for cell in row {
                if *cell == 2 { print!("o"); }
                else if *cell == 1 { print!("."); }
                else { print!(" "); }
            }
            println!("")
        }
        println!("");
    }
}

fn main() {
    let x = Rule110 {
        cells: vec![
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 2, 0],
        ]
    };

    let settings = SolveSettings::new()
		.solve_simple(true)
		.debug(false)
		.difference(true)
		.sleep_ms(50)
	;
    let solver = BackTrackSolver::new(x, settings);
    let difference = solver.solve(|s| s.find_min_empty(), |s, p| s.possible(p))
		.expect("Expected solution").puzzle;
	println!("Solution:");
	difference.print();
}

pub fn example1() -> Rule110 {
    Rule110 {
        cells: vec![
            vec![1, 1, 1, 2, 1],
            vec![1, 0, 0, 0, 1],
            vec![1, 0, 0, 0, 1],
            vec![2, 2, 1, 2, 1],
        ]
    }
}

pub fn example2() -> Rule110 {
    Rule110 {
        cells: vec![
            vec![1, 1, 0, 0, 0],
            vec![0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0],
            vec![2, 2, 1, 2, 1],
        ]
    }
}
<commit_msg>Added more information<commit_after>/*

Rule 110 is a simple cellular automaton that is universal.

For more information, see https://en.wikipedia.org/wiki/Rule_110

This solver reconstructs a space-time of cell states from known states.
It works remarkably well, considering the simple strategy of picking
the most constrained cell.

*/

extern crate quickbacktrack;

use quickbacktrack::{BackTrackSolver, Puzzle, SolveSettings};

#[derive(Clone)]
pub struct Rule110 {
	pub cells: Vec<Vec<u8>>,
}

impl Rule110 {
    pub fn next(&mut self) -> Vec<u8> {
        let last = self.cells.last().unwrap();
        let n = last.len();
        let mut new_row = vec![0; n];
        for i in 0..n {
            let input = (
                last[(i + n - 1) % n],
                last[i],
                last[(i + 1) % n]
            );
            new_row[i] = rule(input);
        }
        new_row
    }

    /// Returns `false` when a contradition is found.
    /// This is checked by checking all affected cells in next step.
    /// Also checks the previous step.
    pub fn is_satisfied(&self, pos: [usize; 2], val: u8) -> bool {
        let row = pos[0];
        let col = pos[1] as isize;

        let n = self.cells[row].len() as isize;
        if row + 1 < self.cells.len() {
            // Replace with new value if looking up cell at the location.
            let f = |ind: isize| {
                let map_ind = ((col + ind + n) % n) as usize;
                if map_ind == col as usize { val }
                else { self.cells[row][map_ind] }
            };
            // [o o x] [o x o] [x o o]
            for i in -1..2 {
                let input = (
                    f(i - 1),
                    f(i),
                    f(i + 1),
                );

                let col_next = ((col + n + i) % n) as usize;
                let new_value = rule(input);
                let old_value = self.cells[row + 1][col_next];
                match (new_value, old_value) {
                    (_, 0) => {}
                    (0, _) => {}
                    (a, b) if a == b => {}
                    (_, _) => return false,
                }
            }
        }

        // Check that previous row yields value.
        if row > 0 {
            let f = |ind: isize| {
                let map_ind = ((col + ind + n) % n) as usize;
                self.cells[row - 1][map_ind]
            };
            let input = (
                f(-1),
                f(0),
                f(1),
            );
            match (rule(input), val) {
                (_, 0) => {}
                (0, _) => {}
                (a, b) if a == b => {}
                (_, _) => return false,
            }
        }

        true
    }

    pub fn possible(&self, pos: [usize; 2]) -> Vec<u8> {
        let mut res = vec![];
        for v in 1..3 {
            if self.is_satisfied(pos, v) {
                res.push(v);
            }
        }
        res
    }

    pub fn find_min_empty(&self) -> Option<[usize; 2]> {
        let mut min = None;
        let mut min_pos = None;
        for i in 0..self.cells.len() {
            for j in 0..self.cells[i].len() {
                if self.cells[i][j] == 0 {
                    let possible = self.possible([i, j]);
                    if min.is_none() || min.unwrap() >= possible.len() {
                        min = Some(possible.len());
                        min_pos = Some([i, j]);
                    }
                }
            }
        }
        return min_pos;
    }
}

/// Rule 110 extended with unknown inputs.
fn rule(state: (u8, u8, u8)) -> u8 {
    match state {
        (2, 2, 2) => 1,
        (2, 2, 1) => 2,
        (2, 1, 2) => 2,
        (2, 1, 1) => 1,
        (1, 2, 2) => 2,
        (1, 2, 1) => 2,
        (1, 1, 2) => 2,
        (1, 1, 1) => 1,

        // 1 unknown.
        (2, 2, 0) => 0,
        (2, 0, 2) => 0,
        (0, 2, 2) => 0,
        (2, 0, 1) => 0,
        (0, 2, 1) => 2,
        (2, 1, 0) => 0,
        (0, 1, 2) => 2,
        (0, 1, 1) => 1,
        (1, 2, 0) => 2,
        (1, 0, 2) => 2,
        (1, 0, 1) => 0,
        (1, 1, 0) => 0,

        // All with 2 unknowns or more has unknown result.
        (_, _, _) => 0,
    }
}

impl Puzzle for Rule110 {
    type Pos = [usize; 2];
    type Val = u8;

    fn solve_simple(&mut self) {
        loop {
			let mut found_any = false;
			for i in 0..self.cells.len() {
				for j in 0..self.cells[i].len() {
					if self.cells[i][j] != 0 { continue; }
					let possible = self.possible([i, j]);
					if possible.len() == 1 {
						self.cells[i][j] = possible[0];
						found_any = true;
					}
				}
			}
			if !found_any { break; }
		}
    }

    fn set(&mut self, pos: [usize; 2], val: u8) {
        self.cells[pos[0]][pos[1]] = val;
    }

    fn is_solved(&self) -> bool {
        for row in &self.cells {
            for col in row {
                if *col == 0 { return false; }
            }
        }
        true
    }

    fn remove(&mut self, other: &Rule110) {
        for i in 0..self.cells.len() {
            for j in 0..self.cells[i].len() {
                if other.cells[i][j] != 0 {
                    self.cells[i][j] = 0;
                }
            }
        }
    }

    fn print(&self) {
        println!("");
        for row in &self.cells {
            for cell in row {
                if *cell == 2 { print!("o"); }
                else if *cell == 1 { print!("."); }
                else { print!(" "); }
            }
            println!("")
        }
        println!("");
    }
}

fn main() {
    let x = Rule110 {
        cells: vec![
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            vec![1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 2, 0],
        ]
    };

    let settings = SolveSettings::new()
		.solve_simple(true)
		.debug(false)
		.difference(true)
		.sleep_ms(50)
	;
    let solver = BackTrackSolver::new(x, settings);
    let difference = solver.solve(|s| s.find_min_empty(), |s, p| s.possible(p))
		.expect("Expected solution").puzzle;
	println!("Solution:");
	difference.print();
}

pub fn example1() -> Rule110 {
    Rule110 {
        cells: vec![
            vec![1, 1, 1, 2, 1],
            vec![1, 0, 0, 0, 1],
            vec![1, 0, 0, 0, 1],
            vec![2, 2, 1, 2, 1],
        ]
    }
}

pub fn example2() -> Rule110 {
    Rule110 {
        cells: vec![
            vec![1, 1, 0, 0, 0],
            vec![0, 0, 0, 0, 0],
            vec![0, 0, 0, 0, 0],
            vec![2, 2, 1, 2, 1],
        ]
    }
}
<|endoftext|>


<commit_before>/* Copyright 2016 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

#[macro_use]
extern crate clear_coat;
extern crate iup_sys;
extern crate smallvec;

use std::rc::Rc;
use iup_sys::*;
use smallvec::SmallVec;

use clear_coat::*;
use clear_coat::common_attrs_cbs::*;

struct CursorsCanvas {
    canvas: Canvas,
}

impl CursorsCanvas {
    pub fn new() -> Self {
        CursorsCanvas {
            canvas: Canvas::new(),
        }
    }
}

impl CursorAttribute for CursorsCanvas {}

unsafe impl Control for CursorsCanvas {
    fn handle(&self) -> *mut Ihandle {
        self.canvas.handle()
    }
}

fn create_cursors_page() -> Box<Control> {
    let cursors_canvas = Rc::new(CursorsCanvas::new());

    let radios_info = [
        ("None", Cursor::None),
        ("Arrow", Cursor::Arrow),
        ("Busy", Cursor::Busy),
        ("Cross", Cursor::Cross),
        ("Hand", Cursor::Hand),
        ("Help", Cursor::Help),
        ("Move", Cursor::Move),
        ("ResizeN", Cursor::ResizeN),
        ("ResizeS", Cursor::ResizeS),
        ("ResizeNS", Cursor::ResizeNS),
        ("ResizeW", Cursor::ResizeW),
        ("ResizeE", Cursor::ResizeE),
        ("ResizeWE", Cursor::ResizeWE),
        ("ResizeNE", Cursor::ResizeNE),
        ("ResizeSW", Cursor::ResizeSW),
        ("ResizeNW", Cursor::ResizeNW),
        ("ResizeSE", Cursor::ResizeSE),
        ("Text", Cursor::Text),
    ];

    let mut radios = SmallVec::<[Toggle; 32]>::new();
    for &(text, cur) in radios_info.iter() {
        let toggle = Toggle::new();
        toggle.set_title(text);
        let cursors_canvas2 = cursors_canvas.clone();
        toggle.action_event().add(move |checked| {
            if checked { cursors_canvas2.set_cursor(cur); }
        });
        radios.push(toggle);
    }

    let grid = grid_box!(
        &radios[0],
        &radios[1],
        &radios[2],
        &radios[3],
        &radios[4],
        &radios[5],
        &radios[6],
        &radios[7],
        &radios[8],
        &radios[9],
        &radios[10],
        &radios[11],
        &radios[12],
        &radios[13],
        &radios[14],
        &radios[15],
        &radios[16],
        &radios[17],
    );
    grid.set_num_div(NumDiv::Fixed(2));
    grid.fit_all_to_children();
    let page = vbox!(
        &cursors_canvas,
        hbox!(
            fill!(),
            Radio::with_child(&grid),
            fill!(),
        ),
    );
    Box::new(page)
}

fn create_file_dialog_page() -> Box<Control> {

    let dir_check_box = Toggle::new();
    dir_check_box.set_title("Directory:");

    let show_dialog = Button::with_title("Show Dialog");
    show_dialog.action_event().add(move || {
        let dialog = FileDlg::new();
        dialog.popup(ScreenPosition::CenterParent, ScreenPosition::CenterParent)
              .expect("couldn't show file dialog");
    });

    let page = vbox!(
        dir_check_box,
        show_dialog,
    );
    Box::new(page)
}

fn main() {

    let dialog = Dialog::new();

    let tabs = Tabs::new();

    tabs.append_tabs(&[
        TabInfo::new(&*create_cursors_page()).title("Cursors"),
        TabInfo::new(&*create_file_dialog_page()).title("File Dialog"),
    ]);

    dialog.append(&tabs).expect("failed to build the window");
    dialog.set_title("Showcase");

    dialog.show_xy(ScreenPosition::Center, ScreenPosition::Center)
          .expect("failed to show the window");
    main_loop();
}
<commit_msg>Allow setting the initial directory of a file dialog in Showcase<commit_after>/* Copyright 2016 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

#[macro_use]
extern crate clear_coat;
extern crate iup_sys;
extern crate smallvec;

use std::rc::Rc;
use iup_sys::*;
use smallvec::SmallVec;

use clear_coat::*;
use clear_coat::common_attrs_cbs::*;

struct CursorsCanvas {
    canvas: Canvas,
}

impl CursorsCanvas {
    pub fn new() -> Self {
        CursorsCanvas {
            canvas: Canvas::new(),
        }
    }
}

impl CursorAttribute for CursorsCanvas {}

unsafe impl Control for CursorsCanvas {
    fn handle(&self) -> *mut Ihandle {
        self.canvas.handle()
    }
}

fn create_cursors_page() -> Box<Control> {
    let cursors_canvas = Rc::new(CursorsCanvas::new());

    let radios_info = [
        ("None", Cursor::None),
        ("Arrow", Cursor::Arrow),
        ("Busy", Cursor::Busy),
        ("Cross", Cursor::Cross),
        ("Hand", Cursor::Hand),
        ("Help", Cursor::Help),
        ("Move", Cursor::Move),
        ("ResizeN", Cursor::ResizeN),
        ("ResizeS", Cursor::ResizeS),
        ("ResizeNS", Cursor::ResizeNS),
        ("ResizeW", Cursor::ResizeW),
        ("ResizeE", Cursor::ResizeE),
        ("ResizeWE", Cursor::ResizeWE),
        ("ResizeNE", Cursor::ResizeNE),
        ("ResizeSW", Cursor::ResizeSW),
        ("ResizeNW", Cursor::ResizeNW),
        ("ResizeSE", Cursor::ResizeSE),
        ("Text", Cursor::Text),
    ];

    let mut radios = SmallVec::<[Toggle; 32]>::new();
    for &(text, cur) in radios_info.iter() {
        let toggle = Toggle::new();
        toggle.set_title(text);
        let cursors_canvas2 = cursors_canvas.clone();
        toggle.action_event().add(move |checked| {
            if checked { cursors_canvas2.set_cursor(cur); }
        });
        radios.push(toggle);
    }

    let grid = grid_box!(
        &radios[0],
        &radios[1],
        &radios[2],
        &radios[3],
        &radios[4],
        &radios[5],
        &radios[6],
        &radios[7],
        &radios[8],
        &radios[9],
        &radios[10],
        &radios[11],
        &radios[12],
        &radios[13],
        &radios[14],
        &radios[15],
        &radios[16],
        &radios[17],
    );
    grid.set_num_div(NumDiv::Fixed(2));
    grid.fit_all_to_children();
    let page = vbox!(
        &cursors_canvas,
        hbox!(
            fill!(),
            Radio::with_child(&grid),
            fill!(),
        ),
    );
    Box::new(page)
}

fn create_file_dialog_page() -> Box<Control> {
    let dir_check_box = Toggle::new();
    dir_check_box.set_title("Directory:");

    let dir_text_box = Text::new();

    let show_dialog = Button::with_title("Show Dialog");
    let dir_check_box_capt = dir_check_box.clone();
    let dir_text_box_capt = dir_text_box.clone();
    show_dialog.action_event().add(move || {
        let dialog = FileDlg::new();
        if dir_check_box_capt.value() == ToggleState::On {
            dialog.set_directory(&dir_text_box_capt.value());
        }
        dialog.popup(ScreenPosition::CenterParent, ScreenPosition::CenterParent)
              .expect("couldn't show file dialog");
    });

    let grid = grid_box!(
        dir_check_box,
        dir_text_box,
        fill!(),
        show_dialog,
    );
    grid.set_num_div(NumDiv::Fixed(2));
    grid.fit_all_to_children();
    Box::new(grid)
}

fn main() {

    let dialog = Dialog::new();

    let tabs = Tabs::new();

    tabs.append_tabs(&[
        TabInfo::new(&*create_cursors_page()).title("Cursors"),
        TabInfo::new(&*create_file_dialog_page()).title("File Dialog"),
    ]);

    dialog.append(&tabs).expect("failed to build the window");
    dialog.set_title("Showcase");

    dialog.show_xy(ScreenPosition::Center, ScreenPosition::Center)
          .expect("failed to show the window");
    main_loop();
}
<|endoftext|>


<commit_before>//! This module provides a token source (`GetToken`) that obtains tokens for service accounts.
//! Service accounts are usually used by software (i.e., non-human actors) to get access to
//! resources. Currently, this module only works with RS256 JWTs, which makes it at least suitable for
//! authentication with Google services.
//!
//! Resources:
//! - [Using OAuth 2.0 for Server to Server
//! Applications](https://developers.google.com/identity/protocols/OAuth2ServiceAccount)
//! - [JSON Web Tokens](https://jwt.io/)
//!
//! Copyright (c) 2016 Google Inc (lewinb@google.com).
//!

use crate::error::Error;
use crate::types::TokenInfo;

use std::io;

use hyper::header;
use rustls::{
    self,
    internal::pemfile,
    sign::{self, SigningKey},
    PrivateKey,
};
use serde::{Deserialize, Serialize};
use url::form_urlencoded;

const GRANT_TYPE: &str = "urn:ietf:params:oauth:grant-type:jwt-bearer";
const GOOGLE_RS256_HEAD: &str = r#"{"alg":"RS256","typ":"JWT"}"#;

/// Encodes s as Base64
fn append_base64<T: AsRef<[u8]> + ?Sized>(s: &T, out: &mut String) {
    base64::encode_config_buf(s, base64::URL_SAFE, out)
}

/// Decode a PKCS8 formatted RSA key.
fn decode_rsa_key(pem_pkcs8: &str) -> Result<PrivateKey, io::Error> {
    let private_keys = pemfile::pkcs8_private_keys(&mut pem_pkcs8.as_bytes());

    match private_keys {
        Ok(mut keys) if !keys.is_empty() => {
            keys.truncate(1);
            Ok(keys.remove(0))
        }
        Ok(_) => Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "Not enough private keys in PEM",
        )),
        Err(_) => Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "Error reading key from PEM",
        )),
    }
}

/// JSON schema of secret service account key. You can obtain the key from
/// the Cloud Console at https://console.cloud.google.com/.
///
/// You can use `helpers::read_service_account_key()` as a quick way to read a JSON client
/// secret into a ServiceAccountKey.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ServiceAccountKey {
    #[serde(rename = "type")]
    /// key_type
    pub key_type: Option<String>,
    /// project_id
    pub project_id: Option<String>,
    /// private_key_id
    pub private_key_id: Option<String>,
    /// private_key
    pub private_key: String,
    /// client_email
    pub client_email: String,
    /// client_id
    pub client_id: Option<String>,
    /// auth_uri
    pub auth_uri: Option<String>,
    /// token_uri
    pub token_uri: String,
    /// auth_provider_x509_cert_url
    pub auth_provider_x509_cert_url: Option<String>,
    /// client_x509_cert_url
    pub client_x509_cert_url: Option<String>,
}

/// Permissions requested for a JWT.
/// See https://developers.google.com/identity/protocols/OAuth2ServiceAccount#authorizingrequests.
#[derive(Serialize, Debug)]
struct Claims<'a> {
    iss: &'a str,
    aud: &'a str,
    exp: i64,
    iat: i64,
    subject: Option<&'a str>,
    scope: String,
}

impl<'a> Claims<'a> {
    fn new<T>(key: &'a ServiceAccountKey, scopes: &[T], subject: Option<&'a str>) -> Self
    where
        T: AsRef<str>,
    {
        let iat = chrono::Utc::now().timestamp();
        let expiry = iat + 3600 - 5; // Max validity is 1h.

        let scope = crate::helper::join(scopes, " ");
        Claims {
            iss: &key.client_email,
            aud: &key.token_uri,
            exp: expiry,
            iat,
            subject,
            scope,
        }
    }
}

/// A JSON Web Token ready for signing.
pub(crate) struct JWTSigner {
    signer: Box<dyn rustls::sign::Signer>,
}

impl JWTSigner {
    fn new(private_key: &str) -> Result<Self, io::Error> {
        let key = decode_rsa_key(private_key)?;
        let signing_key = sign::RSASigningKey::new(&key)
            .map_err(|_| io::Error::new(io::ErrorKind::Other, "Couldn't initialize signer"))?;
        let signer = signing_key
            .choose_scheme(&[rustls::SignatureScheme::RSA_PKCS1_SHA256])
            .ok_or_else(|| {
                io::Error::new(io::ErrorKind::Other, "Couldn't choose signing scheme")
            })?;
        Ok(JWTSigner { signer })
    }

    fn sign_claims(&self, claims: &Claims) -> Result<String, rustls::TLSError> {
        let mut jwt_head = Self::encode_claims(claims);
        let signature = self.signer.sign(jwt_head.as_bytes())?;
        jwt_head.push_str(".");
        append_base64(&signature, &mut jwt_head);
        Ok(jwt_head)
    }

    /// Encodes the first two parts (header and claims) to base64 and assembles them into a form
    /// ready to be signed.
    fn encode_claims(claims: &Claims) -> String {
        let mut head = String::new();
        append_base64(GOOGLE_RS256_HEAD, &mut head);
        head.push_str(".");
        append_base64(&serde_json::to_string(&claims).unwrap(), &mut head);
        head
    }
}

pub struct ServiceAccountFlowOpts {
    pub(crate) key: ServiceAccountKey,
    pub(crate) subject: Option<String>,
}

/// ServiceAccountFlow can fetch oauth tokens using a service account.
pub struct ServiceAccountFlow {
    key: ServiceAccountKey,
    subject: Option<String>,
    signer: JWTSigner,
}

impl ServiceAccountFlow {
    pub(crate) fn new(opts: ServiceAccountFlowOpts) -> Result<Self, io::Error> {
        let signer = JWTSigner::new(&opts.key.private_key)?;
        Ok(ServiceAccountFlow {
            key: opts.key,
            subject: opts.subject,
            signer,
        })
    }

    /// Send a request for a new Bearer token to the OAuth provider.
    pub(crate) async fn token<C, T>(
        &self,
        hyper_client: &hyper::Client<C>,
        scopes: &[T],
    ) -> Result<TokenInfo, Error>
    where
        T: AsRef<str>,
        C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
    {
        let claims = Claims::new(&self.key, scopes, self.subject.as_ref().map(|x| x.as_str()));
        let signed = self.signer.sign_claims(&claims).map_err(|_| {
            Error::LowLevelError(io::Error::new(
                io::ErrorKind::Other,
                "unable to sign claims",
            ))
        })?;
        let rqbody = form_urlencoded::Serializer::new(String::new())
            .extend_pairs(&[("grant_type", GRANT_TYPE), ("assertion", signed.as_str())])
            .finish();
        let request = hyper::Request::post(&self.key.token_uri)
            .header(header::CONTENT_TYPE, "application/x-www-form-urlencoded")
            .body(hyper::Body::from(rqbody))
            .unwrap();
        log::debug!("requesting token from service account: {:?}", request);
        let (head, body) = hyper_client.request(request).await?.into_parts();
        let body = hyper::body::to_bytes(body).await?;
        log::debug!("received response; head: {:?}, body: {:?}", head, body);
        TokenInfo::from_json(&body)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::helper::read_service_account_key;
    use hyper_rustls::HttpsConnector;

    // Valid but deactivated key.
    const TEST_PRIVATE_KEY_PATH: &'static str = "examples/Sanguine-69411a0c0eea.json";

    // Uncomment this test to verify that we can successfully obtain tokens.
    //#[tokio::test]
    #[allow(dead_code)]
    async fn test_service_account_e2e() {
        let key = read_service_account_key(TEST_PRIVATE_KEY_PATH)
            .await
            .unwrap();
        let acc = ServiceAccountFlow::new(ServiceAccountFlowOpts { key, subject: None }).unwrap();
        let https = HttpsConnector::new();
        let client = hyper::Client::builder()
            .keep_alive(false)
            .build::<_, hyper::Body>(https);
        println!(
            "{:?}",
            acc.token(&client, &["https://www.googleapis.com/auth/pubsub"])
                .await
        );
    }

    #[tokio::test]
    async fn test_jwt_initialize_claims() {
        let key = read_service_account_key(TEST_PRIVATE_KEY_PATH)
            .await
            .unwrap();
        let scopes = vec!["scope1", "scope2", "scope3"];
        let claims = Claims::new(&key, &scopes, None);

        assert_eq!(
            claims.iss,
            "oauth2-public-test@sanguine-rhythm-105020.iam.gserviceaccount.com".to_string()
        );
        assert_eq!(claims.scope, "scope1 scope2 scope3".to_string());
        assert_eq!(
            claims.aud,
            "https://accounts.google.com/o/oauth2/token".to_string()
        );
        assert!(claims.exp > 1000000000);
        assert!(claims.iat < claims.exp);
        assert_eq!(claims.exp - claims.iat, 3595);
    }

    #[tokio::test]
    async fn test_jwt_sign() {
        let key = read_service_account_key(TEST_PRIVATE_KEY_PATH)
            .await
            .unwrap();
        let scopes = vec!["scope1", "scope2", "scope3"];
        let signer = JWTSigner::new(&key.private_key).unwrap();
        let claims = Claims::new(&key, &scopes, None);
        let signature = signer.sign_claims(&claims);

        assert!(signature.is_ok());

        let signature = signature.unwrap();
        assert_eq!(
            signature.split(".").nth(0).unwrap(),
            "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9"
        );
    }
}
<commit_msg>fix 'subject' name in service-account claim<commit_after>//! This module provides a token source (`GetToken`) that obtains tokens for service accounts.
//! Service accounts are usually used by software (i.e., non-human actors) to get access to
//! resources. Currently, this module only works with RS256 JWTs, which makes it at least suitable for
//! authentication with Google services.
//!
//! Resources:
//! - [Using OAuth 2.0 for Server to Server
//! Applications](https://developers.google.com/identity/protocols/OAuth2ServiceAccount)
//! - [JSON Web Tokens](https://jwt.io/)
//!
//! Copyright (c) 2016 Google Inc (lewinb@google.com).
//!

use crate::error::Error;
use crate::types::TokenInfo;

use std::io;

use hyper::header;
use rustls::{
    self,
    internal::pemfile,
    sign::{self, SigningKey},
    PrivateKey,
};
use serde::{Deserialize, Serialize};
use url::form_urlencoded;

const GRANT_TYPE: &str = "urn:ietf:params:oauth:grant-type:jwt-bearer";
const GOOGLE_RS256_HEAD: &str = r#"{"alg":"RS256","typ":"JWT"}"#;

/// Encodes s as Base64
fn append_base64<T: AsRef<[u8]> + ?Sized>(s: &T, out: &mut String) {
    base64::encode_config_buf(s, base64::URL_SAFE, out)
}

/// Decode a PKCS8 formatted RSA key.
fn decode_rsa_key(pem_pkcs8: &str) -> Result<PrivateKey, io::Error> {
    let private_keys = pemfile::pkcs8_private_keys(&mut pem_pkcs8.as_bytes());

    match private_keys {
        Ok(mut keys) if !keys.is_empty() => {
            keys.truncate(1);
            Ok(keys.remove(0))
        }
        Ok(_) => Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "Not enough private keys in PEM",
        )),
        Err(_) => Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "Error reading key from PEM",
        )),
    }
}

/// JSON schema of secret service account key. You can obtain the key from
/// the Cloud Console at https://console.cloud.google.com/.
///
/// You can use `helpers::read_service_account_key()` as a quick way to read a JSON client
/// secret into a ServiceAccountKey.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ServiceAccountKey {
    #[serde(rename = "type")]
    /// key_type
    pub key_type: Option<String>,
    /// project_id
    pub project_id: Option<String>,
    /// private_key_id
    pub private_key_id: Option<String>,
    /// private_key
    pub private_key: String,
    /// client_email
    pub client_email: String,
    /// client_id
    pub client_id: Option<String>,
    /// auth_uri
    pub auth_uri: Option<String>,
    /// token_uri
    pub token_uri: String,
    /// auth_provider_x509_cert_url
    pub auth_provider_x509_cert_url: Option<String>,
    /// client_x509_cert_url
    pub client_x509_cert_url: Option<String>,
}

/// Permissions requested for a JWT.
/// See https://developers.google.com/identity/protocols/OAuth2ServiceAccount#authorizingrequests.
#[derive(Serialize, Debug)]
struct Claims<'a> {
    iss: &'a str,
    aud: &'a str,
    exp: i64,
    iat: i64,
    #[serde(rename = "sub")]
    subject: Option<&'a str>,
    scope: String,
}

impl<'a> Claims<'a> {
    fn new<T>(key: &'a ServiceAccountKey, scopes: &[T], subject: Option<&'a str>) -> Self
    where
        T: AsRef<str>,
    {
        let iat = chrono::Utc::now().timestamp();
        let expiry = iat + 3600 - 5; // Max validity is 1h.

        let scope = crate::helper::join(scopes, " ");
        Claims {
            iss: &key.client_email,
            aud: &key.token_uri,
            exp: expiry,
            iat,
            subject,
            scope,
        }
    }
}

/// A JSON Web Token ready for signing.
pub(crate) struct JWTSigner {
    signer: Box<dyn rustls::sign::Signer>,
}

impl JWTSigner {
    fn new(private_key: &str) -> Result<Self, io::Error> {
        let key = decode_rsa_key(private_key)?;
        let signing_key = sign::RSASigningKey::new(&key)
            .map_err(|_| io::Error::new(io::ErrorKind::Other, "Couldn't initialize signer"))?;
        let signer = signing_key
            .choose_scheme(&[rustls::SignatureScheme::RSA_PKCS1_SHA256])
            .ok_or_else(|| {
                io::Error::new(io::ErrorKind::Other, "Couldn't choose signing scheme")
            })?;
        Ok(JWTSigner { signer })
    }

    fn sign_claims(&self, claims: &Claims) -> Result<String, rustls::TLSError> {
        let mut jwt_head = Self::encode_claims(claims);
        let signature = self.signer.sign(jwt_head.as_bytes())?;
        jwt_head.push_str(".");
        append_base64(&signature, &mut jwt_head);
        Ok(jwt_head)
    }

    /// Encodes the first two parts (header and claims) to base64 and assembles them into a form
    /// ready to be signed.
    fn encode_claims(claims: &Claims) -> String {
        let mut head = String::new();
        append_base64(GOOGLE_RS256_HEAD, &mut head);
        head.push_str(".");
        append_base64(&serde_json::to_string(&claims).unwrap(), &mut head);
        head
    }
}

pub struct ServiceAccountFlowOpts {
    pub(crate) key: ServiceAccountKey,
    pub(crate) subject: Option<String>,
}

/// ServiceAccountFlow can fetch oauth tokens using a service account.
pub struct ServiceAccountFlow {
    key: ServiceAccountKey,
    subject: Option<String>,
    signer: JWTSigner,
}

impl ServiceAccountFlow {
    pub(crate) fn new(opts: ServiceAccountFlowOpts) -> Result<Self, io::Error> {
        let signer = JWTSigner::new(&opts.key.private_key)?;
        Ok(ServiceAccountFlow {
            key: opts.key,
            subject: opts.subject,
            signer,
        })
    }

    /// Send a request for a new Bearer token to the OAuth provider.
    pub(crate) async fn token<C, T>(
        &self,
        hyper_client: &hyper::Client<C>,
        scopes: &[T],
    ) -> Result<TokenInfo, Error>
    where
        T: AsRef<str>,
        C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
    {
        let claims = Claims::new(&self.key, scopes, self.subject.as_ref().map(|x| x.as_str()));
        let signed = self.signer.sign_claims(&claims).map_err(|_| {
            Error::LowLevelError(io::Error::new(
                io::ErrorKind::Other,
                "unable to sign claims",
            ))
        })?;
        let rqbody = form_urlencoded::Serializer::new(String::new())
            .extend_pairs(&[("grant_type", GRANT_TYPE), ("assertion", signed.as_str())])
            .finish();
        let request = hyper::Request::post(&self.key.token_uri)
            .header(header::CONTENT_TYPE, "application/x-www-form-urlencoded")
            .body(hyper::Body::from(rqbody))
            .unwrap();
        log::debug!("requesting token from service account: {:?}", request);
        let (head, body) = hyper_client.request(request).await?.into_parts();
        let body = hyper::body::to_bytes(body).await?;
        log::debug!("received response; head: {:?}, body: {:?}", head, body);
        TokenInfo::from_json(&body)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::helper::read_service_account_key;
    use hyper_rustls::HttpsConnector;

    // Valid but deactivated key.
    const TEST_PRIVATE_KEY_PATH: &'static str = "examples/Sanguine-69411a0c0eea.json";

    // Uncomment this test to verify that we can successfully obtain tokens.
    //#[tokio::test]
    #[allow(dead_code)]
    async fn test_service_account_e2e() {
        let key = read_service_account_key(TEST_PRIVATE_KEY_PATH)
            .await
            .unwrap();
        let acc = ServiceAccountFlow::new(ServiceAccountFlowOpts { key, subject: None }).unwrap();
        let https = HttpsConnector::new();
        let client = hyper::Client::builder()
            .keep_alive(false)
            .build::<_, hyper::Body>(https);
        println!(
            "{:?}",
            acc.token(&client, &["https://www.googleapis.com/auth/pubsub"])
                .await
        );
    }

    #[tokio::test]
    async fn test_jwt_initialize_claims() {
        let key = read_service_account_key(TEST_PRIVATE_KEY_PATH)
            .await
            .unwrap();
        let scopes = vec!["scope1", "scope2", "scope3"];
        let claims = Claims::new(&key, &scopes, None);

        assert_eq!(
            claims.iss,
            "oauth2-public-test@sanguine-rhythm-105020.iam.gserviceaccount.com".to_string()
        );
        assert_eq!(claims.scope, "scope1 scope2 scope3".to_string());
        assert_eq!(
            claims.aud,
            "https://accounts.google.com/o/oauth2/token".to_string()
        );
        assert!(claims.exp > 1000000000);
        assert!(claims.iat < claims.exp);
        assert_eq!(claims.exp - claims.iat, 3595);
    }

    #[tokio::test]
    async fn test_jwt_sign() {
        let key = read_service_account_key(TEST_PRIVATE_KEY_PATH)
            .await
            .unwrap();
        let scopes = vec!["scope1", "scope2", "scope3"];
        let signer = JWTSigner::new(&key.private_key).unwrap();
        let claims = Claims::new(&key, &scopes, None);
        let signature = signer.sign_claims(&claims);

        assert!(signature.is_ok());

        let signature = signature.unwrap();
        assert_eq!(
            signature.split(".").nth(0).unwrap(),
            "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9"
        );
    }
}
<|endoftext|>


<commit_before>use std::fmt::{ Display, Formatter, Error };
use std::iter::Iterator;
use std::collections::HashMap;
use std::vec::Vec;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

/**
 * test can be deleted.
 * clauses will house all clauses, key is int so that we can use occurrences
 * ID for simplifications later
 * occurrences tracks which clauses literals are used in
 */
pub struct CNF {
    clauses     : HashMap<i32,Vec<i32>>,
    occurrences : HashMap<i32,Vec<i32>>,
}

impl CNF {
    pub fn new() -> CNF {
        CNF {
            test : "NEW".to_string(),
            clauses : HashMap::new(),
            occurrences : HashMap::new(),
        }
    }

    // Add a clause, return the ID of the inserted clause
    fn add_clause(&mut self, clause : Vec<i32>) -> i32 {
        let id : i32 = self.clauses.len() as i32;
        for var in &clause {
            let occ = self.occurrences.entry(*var).or_insert(Vec::new());
            occ.push(id);
        }
        self.clauses.insert(id, clause);
        id
    }

    pub fn to_string(self) -> String {
        format!("Clauses: {:?}\nOccurrrences: {:?}",self.clauses,self.occurrences)
    }
}

impl Display for CNF {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let mut comma_separated = String::new();
        comma_separated.push_str("Need to implement formatter");
        write!(f, "{}", comma_separated)
    }
}

// End CNF

// Begin Parsing

#[derive(Debug)]
pub enum SatError {
    InvalidSyntax
}

fn parse_dimacs(reader: &mut BufReader<File>) -> Result<CNF, SatError> {
    let mut cnf = CNF::new();
    for line in reader.lines() {
        let line = line.expect("Could not read file");  // Unwrap result
        let words: Vec<&str> = line.split_whitespace().collect();
        match words[0] {
            "c" => println!("Comment"), // Comment, ignore
            "p" => println!("Problem statement"), // Problem statement
            _   => {
                let tokens = words.iter()
                    .map(|s| s.parse().expect("Invalid DMACS File"))
                    .collect();;
                println!("{:?}", tokens);
                cnf.add_clause(tokens);
            }
        }
    }
    Ok(cnf)
}

pub fn parse_dimacs_file(f: File) -> Result<CNF,SatError> {
    // Read the file
    let mut reader = BufReader::new(f);

    // TODO: This is definitely not the correct way to handle errors
    let line = parse_dimacs(&mut reader);
    line
}
<commit_msg>Search for problem stmt before parsing rest<commit_after>use std::fmt::{ Display, Formatter, Error };
use std::iter::Iterator;
use std::collections::HashMap;
use std::vec::Vec;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

/**
 * test can be deleted.
 * clauses will house all clauses, key is int so that we can use occurrences
 * ID for simplifications later
 * occurrences tracks which clauses literals are used in
 */
pub struct CNF {
    nvar        : i32,
    nclause     : i32,
    clauses     : HashMap<i32, Vec<i32>>,
    occurrences : HashMap<i32, Vec<i32>>
}

impl CNF {
    pub fn new(nvar: i32, nclause: i32) -> CNF {
        CNF {
            nvar        : nvar,
            nclause     : nclause,
            clauses     : HashMap::new(),
            occurrences : HashMap::new()
        }
    }

    // Add a clause, return the ID of the inserted clause
    fn add_clause(&mut self, clause : Vec<i32>) -> i32 {
        let id : i32 = self.clauses.len() as i32;
        for var in &clause {
            let occ = self.occurrences.entry(*var).or_insert(Vec::new());
            occ.push(id);
        }
        self.clauses.insert(id, clause);
        id
    }

    pub fn to_string(self) -> String {
        format!("Nvar: {:?} Nclause: {:?}\nClauses: {:?}\nOccurrrences: {:?}",
                self.nvar, self.nclause,
                self.clauses, self.occurrences)
    }
}

impl Display for CNF {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let mut comma_separated = String::new();
        comma_separated.push_str("Need to implement formatter");
        write!(f, "{}", comma_separated)
    }
}

// End CNF

// Begin Parsing

#[derive(Debug)]
pub enum SatError {
    InvalidSyntax
}

fn parse_dimacs(reader: &mut BufReader<File>) -> Result<CNF, SatError> {
    let mut line_iterator = reader.lines();

    let mut nvar: i32 = -1;
    let mut nclause: i32 = -1;
    // DIMACS file must have a problem statement before other lines.
    // This first loop searches for the problem statement.
    for line in &mut line_iterator {
        let line = line.expect("Could not read file");  // Unwrap result
        let words: Vec<&str> = line.split_whitespace().collect();
        match words[0] {
            "c" => { }
            "p" => { // Problem statement
                // Must have format "p cnf nvar nclause"
                if words.len() != 4 || words[1] != "cnf" {
                    return Err(SatError::InvalidSyntax);
                }
                nvar = words[2].parse()
                    .expect(&format!("Invalid number of variables {}", words[2]));
                nclause = words[3].parse()
                    .expect(&format!("Invalid number of clauses {}", words[3]));
                break;
            }
            _ => { return Err(SatError::InvalidSyntax); }
        }
    }
    // Then nvar, nclause were never initialized
    if nvar == -1 || nclause == -1 {
        return Err(SatError::InvalidSyntax);
    }
    // TODO: Different errors for different descriptions (hence why I've split up this if
    // statement)
    if nvar == 0 || nclause == 0 {
        return Err(SatError::InvalidSyntax)
    }

    // Initialize CNF and parse the rest of the file
    let mut cnf = CNF::new(nvar, nclause);
    for line in &mut line_iterator {
        let line = line.expect("Could not read filce");
        let words: Vec<&str> = line.split_whitespace().collect();
        match words[0] {
            "c" => { }
            _   => {
                // TODO: Assert valid set of tokens
                let tokens = words.iter()
                    .map(|s| s.parse().expect("Invalid DIMACS File"))
                    .collect();;
                println!("{:?}", tokens);
                cnf.add_clause(tokens);
            }
        }
    }
    Ok(cnf)
}

pub fn parse_dimacs_file(f: File) -> Result<CNF, SatError> {
    // Read the file
    let mut reader = BufReader::new(f);

    // TODO: This is definitely not the correct way to handle errors.
    // Should parse_dimacs have options for returning an error AND panicking?
    let line = parse_dimacs(&mut reader);
    line
}
<|endoftext|>