<commit_before>use config::Config;
use error::Result;
use ip::IpAddr;
use regex::Regex;
use std::str::FromStr;
use xmlrpc::Client as XMLRPCClient;
use xmlrpc::Request as XMLRPCRequest;
use xmlrpc::Response as XMLRPCResponse;

pub struct DNSProviderFactory;

impl<'a> DNSProviderFactory {
    pub fn build(config: &'a Config) -> Box<DNSProvider + 'a>  {
        Box::new(GandiDNSProvider::new(&config.apikey))
    }
}

pub trait DNSProvider {
    fn init(&mut self, domain: &str) -> Result<()>;
    fn handle_ipv6_addr(&self) -> bool;
    fn is_record_already_declared(&self, record_name: &str) -> Result<Option<IpAddr>>;
    fn update_record(&self, record_name: &str, ip_addr: &IpAddr) -> Result<()>;
    fn create_record(&self, record_name: &str, ip_addr: &IpAddr) -> Result<()>;
}

pub struct GandiDNSProvider<'a> {
    zone_id: u32,
    gandi_rpc: GandiRPC<'a>,
}

impl<'a> GandiDNSProvider<'a> {
    pub fn new(gandi_apikey: &'a str) -> GandiDNSProvider<'a> {

        let gandi_rpc = GandiRPC {
            xmlrpc_server: GandiRpcEndpoint::PROD.url(),
            apikey: gandi_apikey,
        };

        GandiDNSProvider {
            zone_id: 0,
            gandi_rpc: gandi_rpc,
        }
    }
}

impl<'a> DNSProvider for GandiDNSProvider<'a> {
    fn init(&mut self, domain: &str) -> Result<()> {

        let response = &self.gandi_rpc.get_domain_info(domain);

        // TODO: fix this ugly code
        // Handle errors
        let zone_id_pos = response.body.find("zone_id").unwrap();
        let (_, body_end) = response.body.split_at(zone_id_pos);
        let first_int_markup = body_end.find("<int>").unwrap();
        let (_, body_end) = body_end.split_at(first_int_markup + "<int>".len());
        let first_end_int_markup = body_end.find("</int>").unwrap();
        let (zone_id, _) = body_end.split_at(first_end_int_markup);

        self.zone_id = try!(zone_id.parse::<u32>());

        debug!("Zone id: {}", self.zone_id);
        Ok(())
    }

    fn handle_ipv6_addr(&self) -> bool {
        // IPv6 addresses are not handled yet
        false
    }

    fn is_record_already_declared(&self, record_name: &str) -> Result<Option<IpAddr>> {

        let response = &self.gandi_rpc.get_record_list(record_name, &self.zone_id, &0);

        // Extract already configured IP address
        // We are looking for something like that: <value><string>55.32.210.10</string></value>
        let regex = Regex::new(r"<value><string>([0-9.]*)</string></value>").unwrap();

        let caps = regex.captures(&*response.body);

        let result = caps.map_or(None, |caps| caps.at(1))
            .map(|val| IpAddr::from_str(val).unwrap());

        // TODO: handle correctly regex error
        Ok(result)
    }

    fn update_record(&self, record_name: &str, ip_addr: &IpAddr) -> Result<()> {

        // Create a new zone and get returned version

        let new_zone_version = &self.gandi_rpc.create_new_zone(&self.zone_id);

        debug!("New zone version: {}", new_zone_version);

        // Extract new record id

        let new_record_id = &self.gandi_rpc
                                 .get_record_id(record_name, &self.zone_id, &new_zone_version);

        debug!("New record id: {}", new_record_id);

        // Update zone with the new record

        &self.gandi_rpc.update_zone_with_record(record_name,
                                                ip_addr,
                                                &self.zone_id,
                                                new_zone_version,
                                                new_record_id);

        // Activate the new zone
        debug!("Activate version '{}' of the zone '{}'",
               new_zone_version,
               &self.zone_id);

        self.gandi_rpc.update_zone_version(&self.zone_id, &new_zone_version);
        // TODO: check previous result
        Ok(())
    }

    fn create_record(&self, record_name: &str, ip_addr: &IpAddr) -> Result<()> {
        unimplemented!();
    }
}

#[derive(Debug)]
pub enum GandiRpcEndpoint {
    PROD,
    STAGING,
}

impl GandiRpcEndpoint {
    pub fn url(&self) -> &'static str {
        match self {
            &GandiRpcEndpoint::PROD => "https://rpc.gandi.net/xmlrpc/",
            &GandiRpcEndpoint::STAGING => unimplemented!(),
        }
    }
}

struct GandiRPC<'a> {
    xmlrpc_server: &'a str,
    apikey: &'a str,
}

impl<'a> GandiRPC<'a> {
    fn get_gandi_client(&self, rpc_action: &str) -> (XMLRPCClient, XMLRPCRequest) {
        let client = XMLRPCClient::new(self.xmlrpc_server);
        let mut request = XMLRPCRequest::new(rpc_action);
        request = request.argument(&self.apikey.to_string());
        (client, request)
    }

    fn get_domain_info(&self, domain: &'a str) -> XMLRPCResponse {
        let (client, mut request) = self.get_gandi_client("domain.info");
        request = request.argument(&domain.to_string());
        request = request.finalize();

        client.remote_call(&request).unwrap()
    }

    fn get_record_list(&self,
                       record_name: &str,
                       zone_id: &u32,
                       zone_version: &u16)
                       -> XMLRPCResponse {

        let (client, mut request) = self.get_gandi_client("domain.zone.record.list");
        request = request.argument(zone_id);
        request = request.argument(zone_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
        }

        let record = Record {
            name: record_name.to_string(),
            type_: "A".to_string(),
        };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request).unwrap()
    }

    fn create_new_zone(&self, zone_id: &u32) -> u16 {
        let (client, mut request) = self.get_gandi_client("domain.zone.version.new");
        request = request.argument(zone_id);
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        caps.at(1).unwrap().parse::<u16>().ok().unwrap()
    }

    fn get_record_id(&self, record_name: &str, zone_id: &u32, zone_version: &u16) -> u32 {
        let response = &self.get_record_list(record_name, zone_id, zone_version);

        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        caps.at(1).unwrap().parse::<u32>().ok().unwrap()
    }

    fn update_zone_with_record(&self,
                               record_name: &str,
                               ip_addr: &IpAddr,
                               zone_id: &u32,
                               zone_version: &u16,
                               new_record_id: &u32) {
        let (client, mut request) = self.get_gandi_client("domain.zone.record.update");
        request = request.argument(zone_id);
        request = request.argument(zone_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct NewRecordId {
            id: u32,
        };
        request = request.argument(&NewRecordId { id: *new_record_id });

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
            value: String,
        }

        let record = Record {
            name: record_name.to_string(),
            type_: "A".to_string(),
            value: ip_addr.to_string(),
        };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request); // ignore response
    }

    fn update_zone_version(&self, zone_id: &u32, zone_version: &u16) -> bool {

        let (client, mut request) = self.get_gandi_client("domain.zone.version.set");
        request = request.argument(zone_id);
        request = request.argument(zone_version);
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        let regex = Regex::new(r"<boolean>([0-1]*)</boolean>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        let result = caps.at(1).unwrap();

        debug!("Activate version result: {}", result);

        match result {
            "1" => true,
            "0" | _ => false,
        }

    }
}
<commit_msg>(gandi) api refactoring<commit_after>use config::Config;
use error::Result;
use ip::IpAddr;
use regex::Regex;
use std::str::FromStr;
use xmlrpc::Client as XMLRPCClient;
use xmlrpc::Request as XMLRPCRequest;
use xmlrpc::Response as XMLRPCResponse;

pub struct DNSProviderFactory;

impl<'a> DNSProviderFactory {
    pub fn build(config: &'a Config) -> Box<DNSProvider + 'a>  {
        Box::new(GandiDNSProvider::new(&config.apikey))
    }
}

pub trait DNSProvider {
    fn init(&mut self, domain: &str) -> Result<()>;
    fn handle_ipv6_addr(&self) -> bool;
    fn is_record_already_declared(&self, record_name: &str) -> Result<Option<IpAddr>>;
    fn update_record(&self, record_name: &str, ip_addr: &IpAddr) -> Result<()>;
    fn create_record(&self, record_name: &str, ip_addr: &IpAddr) -> Result<()>;
}

pub struct GandiDNSProvider<'a> {
    zone_id: u32,
    gandi_rpc: GandiRPC<'a>,
}

impl<'a> GandiDNSProvider<'a> {
    pub fn new(gandi_apikey: &'a str) -> GandiDNSProvider<'a> {

        let gandi_rpc = GandiRPC {
            xmlrpc_server: GandiRpcEndpoint::PROD.url(),
            apikey: gandi_apikey,
        };

        GandiDNSProvider {
            zone_id: 0,
            gandi_rpc: gandi_rpc,
        }
    }
}

impl<'a> DNSProvider for GandiDNSProvider<'a> {
    fn init(&mut self, domain: &str) -> Result<()> {

        let response = &self.gandi_rpc.domain_info(domain);

        // TODO: fix this ugly code
        // Handle errors
        let zone_id_pos = response.body.find("zone_id").unwrap();
        let (_, body_end) = response.body.split_at(zone_id_pos);
        let first_int_markup = body_end.find("<int>").unwrap();
        let (_, body_end) = body_end.split_at(first_int_markup + "<int>".len());
        let first_end_int_markup = body_end.find("</int>").unwrap();
        let (zone_id, _) = body_end.split_at(first_end_int_markup);

        self.zone_id = try!(zone_id.parse::<u32>());

        debug!("Zone id: {}", self.zone_id);
        Ok(())
    }

    fn handle_ipv6_addr(&self) -> bool {
        // IPv6 addresses are not handled yet
        false
    }

    fn is_record_already_declared(&self, record_name: &str) -> Result<Option<IpAddr>> {

        let response = &self.gandi_rpc.domain_zone_record_list(record_name, &self.zone_id, &0);

        // Extract already configured IP address
        // We are looking for something like that: <value><string>55.32.210.10</string></value>
        let regex = Regex::new(r"<value><string>([0-9.]*)</string></value>").unwrap();

        let caps = regex.captures(&*response.body);

        let result = caps.map_or(None, |caps| caps.at(1))
            .map(|val| IpAddr::from_str(val).unwrap());

        // TODO: handle correctly regex error
        Ok(result)
    }

    fn update_record(&self, record_name: &str, ip_addr: &IpAddr) -> Result<()> {

        // Create a new zone and get returned version

        let new_zone_version = &self.gandi_rpc.domain_zone_version_new(&self.zone_id);

        debug!("New zone version: {}", new_zone_version);

        // Extract new record id

        let new_record_id = &self.gandi_rpc
                                 .get_record_id(record_name, &self.zone_id, &new_zone_version);

        debug!("New record id: {}", new_record_id);

        // Update zone with the new record

        &self.gandi_rpc.domain_zone_record_update(record_name,
                                                ip_addr,
                                                &self.zone_id,
                                                new_zone_version,
                                                new_record_id);

        // Activate the new zone
        debug!("Activate version '{}' of the zone '{}'",
               new_zone_version,
               &self.zone_id);

        self.gandi_rpc.domain_zone_version_set(&self.zone_id, &new_zone_version);
        // TODO: check previous result
        Ok(())
    }

    fn create_record(&self, record_name: &str, ip_addr: &IpAddr) -> Result<()> {
        unimplemented!();
    }
}

#[derive(Debug)]
pub enum GandiRpcEndpoint {
    PROD,
    STAGING,
}

impl GandiRpcEndpoint {
    pub fn url(&self) -> &'static str {
        match self {
            &GandiRpcEndpoint::PROD => "https://rpc.gandi.net/xmlrpc/",
            &GandiRpcEndpoint::STAGING => unimplemented!(),
        }
    }
}

struct GandiRPC<'a> {
    xmlrpc_server: &'a str,
    apikey: &'a str,
}

impl<'a> GandiRPC<'a> {
    fn get_gandi_client(&self, rpc_action: &str) -> (XMLRPCClient, XMLRPCRequest) {
        let client = XMLRPCClient::new(self.xmlrpc_server);
        let mut request = XMLRPCRequest::new(rpc_action);
        request = request.argument(&self.apikey.to_string());
        (client, request)
    }

    fn domain_info(&self, domain: &'a str) -> XMLRPCResponse {
        let (client, mut request) = self.get_gandi_client("domain.info");
        request = request.argument(&domain.to_string());
        request = request.finalize();

        client.remote_call(&request).unwrap()
    }

    fn domain_zone_record_list(&self,
                       record_name: &str,
                       zone_id: &u32,
                       zone_version: &u16)
                       -> XMLRPCResponse {

        let (client, mut request) = self.get_gandi_client("domain.zone.record.list");
        request = request.argument(zone_id);
        request = request.argument(zone_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
        }

        let record = Record {
            name: record_name.to_string(),
            type_: "A".to_string(),
        };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request).unwrap()
    }

    fn domain_zone_version_new(&self, zone_id: &u32) -> u16 {
        let (client, mut request) = self.get_gandi_client("domain.zone.version.new");
        request = request.argument(zone_id);
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        caps.at(1).unwrap().parse::<u16>().ok().unwrap()
    }

    fn get_record_id(&self, record_name: &str, zone_id: &u32, zone_version: &u16) -> u32 {
        let response = &self.domain_zone_record_list(record_name, zone_id, zone_version);

        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        caps.at(1).unwrap().parse::<u32>().ok().unwrap()
    }

    fn domain_zone_record_update(&self,
                               record_name: &str,
                               ip_addr: &IpAddr,
                               zone_id: &u32,
                               zone_version: &u16,
                               new_record_id: &u32) {
        let (client, mut request) = self.get_gandi_client("domain.zone.record.update");
        request = request.argument(zone_id);
        request = request.argument(zone_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct NewRecordId {
            id: u32,
        };
        request = request.argument(&NewRecordId { id: *new_record_id });

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
            value: String,
        }

        let record = Record {
            name: record_name.to_string(),
            type_: "A".to_string(),
            value: ip_addr.to_string(),
        };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request); // ignore response
    }

    fn domain_zone_version_set(&self, zone_id: &u32, zone_version: &u16) -> bool {

        let (client, mut request) = self.get_gandi_client("domain.zone.version.set");
        request = request.argument(zone_id);
        request = request.argument(zone_version);
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        let regex = Regex::new(r"<boolean>([0-1]*)</boolean>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        let result = caps.at(1).unwrap();

        debug!("Activate version result: {}", result);

        match result {
            "1" => true,
            "0" | _ => false,
        }

    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::process::{Command, Output};
use errors::*;

pub trait Config {
  fn get(&self, name: &str) -> Result<String>;
  fn set(&self, name: &str, value: &str) -> Result<()>;
}

pub fn root() -> Result<PathBuf> {
  let output =
    try!(Command::new("git").args(&["rev-parse", "--show-toplevel"]).output());
  let stdout = String::from_utf8_lossy(&output.stdout);

  Ok(stdout.trim_right().into())
}

pub struct GitConfig {
  pub namespace: String,
}

impl GitConfig {
  pub fn auto_include(&self) {
    // Make sure .git-together exists
    if let Ok(mut path) = root() {
      path.push(&format!(".{}", self.namespace));
      if !path.exists() {
        return;
      }
    } else {
      return;
    }

    // Make sure we're not already including .git-together
    if let Ok(output) = self.output(&["--local", "--get-all", "include.path"]) {
      let stdout = String::from_utf8_lossy(&output.stdout);
      if stdout.split('\n').any(|x| x == "../git-together") {
        return;
      }
    }

    self.output(&["--add", "include.path", &format!("../.{}", self.namespace)])
      .ok();
  }

  fn output(&self, args: &[&str]) -> Result<Output> {
    let output = try!(Command::new("git")
      .arg("config")
      .args(args)
      .output());

    if output.status.success() {
      Ok(output)
    } else {
      Err(ErrorKind::GitConfig(output).into())
    }
  }
}

impl Config for GitConfig {
  fn get(&self, name: &str) -> Result<String> {
    let name = format!("{}.{}", self.namespace, name);
    let output = try!(self.output(&[&name]));
    let stdout = String::from_utf8_lossy(&output.stdout);

    Ok(stdout.trim_right().into())
  }

  fn set(&self, name: &str, value: &str) -> Result<()> {
    let name = format!("{}.{}", self.namespace, name);

    self.output(&[&name, value]).and(Ok(()))
  }
}
<commit_msg>be more explicit on ignoring unused results<commit_after>use std::path::PathBuf;
use std::process::{Command, Output};
use errors::*;

pub trait Config {
  fn get(&self, name: &str) -> Result<String>;
  fn set(&self, name: &str, value: &str) -> Result<()>;
}

pub fn root() -> Result<PathBuf> {
  let output =
    try!(Command::new("git").args(&["rev-parse", "--show-toplevel"]).output());
  let stdout = String::from_utf8_lossy(&output.stdout);

  Ok(stdout.trim_right().into())
}

pub struct GitConfig {
  pub namespace: String,
}

impl GitConfig {
  pub fn auto_include(&self) {
    // Make sure .git-together exists
    if let Ok(mut path) = root() {
      path.push(&format!(".{}", self.namespace));
      if !path.exists() {
        return;
      }
    } else {
      return;
    }

    // Make sure we're not already including .git-together
    if let Ok(output) = self.output(&["--local", "--get-all", "include.path"]) {
      let stdout = String::from_utf8_lossy(&output.stdout);
      if stdout.split('\n').any(|x| x == "../git-together") {
        return;
      }
    }

    let _ = self.output(&["--add", "include.path", &format!("../.{}", self.namespace)]);
  }

  fn output(&self, args: &[&str]) -> Result<Output> {
    let output = try!(Command::new("git")
      .arg("config")
      .args(args)
      .output());

    if output.status.success() {
      Ok(output)
    } else {
      Err(ErrorKind::GitConfig(output).into())
    }
  }
}

impl Config for GitConfig {
  fn get(&self, name: &str) -> Result<String> {
    let name = format!("{}.{}", self.namespace, name);
    let output = try!(self.output(&[&name]));
    let stdout = String::from_utf8_lossy(&output.stdout);

    Ok(stdout.trim_right().into())
  }

  fn set(&self, name: &str, value: &str) -> Result<()> {
    let name = format!("{}.{}", self.namespace, name);

    self.output(&[&name, value]).and(Ok(()))
  }
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::process::Command;

pub fn repo_hash<P: AsRef<Path>>(path: P) -> Option<String> {
    let git_path = path.as_ref().to_str();
    let mut args =
        match git_path {
            Some(path) => vec!["-C", path],
            None => vec![],
        };
    args.extend(&["rev-parse", "--short", "HEAD"]);
    let hash = String::from_utf8(Command::new("git")
        .args(&args)
        .output().ok()?
        .stdout).ok()?;
    let hash = hash.trim_end_matches('\n');

    if dirty(path) {
        Some(format!("{}+", hash))
    } else {
        Some(hash.into())
    }
}

fn dirty<P: AsRef<Path>>(path: P) -> bool {
    let path = path.as_ref().to_str();
    let mut args =
        match path {
            Some(path) => vec!["-C", path],
            None => vec![],
        };
    args.extend(&["ls-files", "-m"]);
    match Command::new("git").args(&args).output() {
        Ok(modified_files) => !modified_files.stdout.is_empty(),
        Err(_) => false,
    }
}
<commit_msg>Fix formatting<commit_after>use std::path::Path;
use std::process::Command;

pub fn repo_hash<P: AsRef<Path>>(path: P) -> Option<String> {
    let git_path = path.as_ref().to_str();
    let mut args = match git_path {
        Some(path) => vec!["-C", path],
        None => vec![],
    };
    args.extend(&["rev-parse", "--short", "HEAD"]);
    let hash = String::from_utf8(Command::new("git").args(&args).output().ok()?.stdout).ok()?;
    let hash = hash.trim_end_matches('\n');

    if dirty(path) {
        Some(format!("{}+", hash))
    } else {
        Some(hash.into())
    }
}

fn dirty<P: AsRef<Path>>(path: P) -> bool {
    let path = path.as_ref().to_str();
    let mut args = match path {
        Some(path) => vec!["-C", path],
        None => vec![],
    };
    args.extend(&["ls-files", "-m"]);
    match Command::new("git").args(&args).output() {
        Ok(modified_files) => !modified_files.stdout.is_empty(),
        Err(_) => false,
    }
}
<|endoftext|>


<commit_before>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use byteorder::{LE, ReadBytesExt};

use Error;

use std::{fmt, io};

/// Represents a Glb loader error.
#[derive(Debug)]
pub enum GlbError {
    /// Io error occured.
    IoError(::std::io::Error),
    /// Unsupported version.
    Version(u32),
    /// Magic says that file is not glTF.
    Magic([u8; 4]),
    /// Length specified in GLB header exceeeds that of slice.
    Length {
        /// length specified in GLB header.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Stream ended before we could read the chunk.
    ChunkLength {
        /// chunkType error happened at.
        ty: ChunkType,
        /// chunkLength.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Chunk of this chunkType was not expected.
    ChunkType(ChunkType),
    /// Unknown chunk type.
    UnknownChunkType([u8; 4]),
}

/// The contents of a .glb file.
#[derive(Clone, Debug)]
pub struct Glb<'a> {
    /// The header section of the `.glb` file.
    pub header: Header,
    /// The JSON section of the `.glb` file.
    pub json: &'a [u8],
    /// The optional BIN section of the `.glb` file.
    pub bin: Option<&'a [u8]>,
}

/// The header section of a .glb file.
#[derive(Copy, Clone, Debug)]
pub struct Header {
    /// Must be `b"glTF"`.
    pub magic: [u8; 4],
    /// Must be `2`.
    pub version: u32,
    /// Must match the length of the parent .glb file.
    pub length: u32,
}

/// GLB chunk type.
#[derive(Copy, Clone, Debug)]
pub enum ChunkType {
    /// JSON chunk.
    Json,
    /// BIN\0 chunk.
    Bin,
}

/// Chunk header with no data read yet.
#[derive(Copy, Clone, Debug)]
struct ChunkHeader {
    /// The length of the chunk data in byte excluding the header.
    length: u32,
    /// Chunk type.
    ty: ChunkType,
}

impl Header {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, GlbError> {
        use self::GlbError::IoError;
        let mut magic = [0; 4];
        reader.read_exact(&mut magic).map_err(IoError)?;
        // We only validate magic as we don't care for version and length of
        // contents, the caller does.  Let them decide what to do next with
        // regard to version and length.
        if &magic == b"glTF" {
            Ok(Self {
                magic,
                version: reader.read_u32::<LE>().map_err(IoError)?,
                length: reader.read_u32::<LE>().map_err(IoError)?,
            })
        } else {
            Err(GlbError::Magic(magic))
        }
    }
}

impl ChunkHeader {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, GlbError> {
        use self::GlbError::IoError;
        let length = reader.read_u32::<LE>().map_err(IoError)?;
        let mut ty = [0; 4];
        reader.read_exact(&mut ty).map_err(IoError)?;
        let ty = match &ty {
            b"JSON" => Ok(ChunkType::Json),
            b"BIN\0" => Ok(ChunkType::Bin),
            _ => Err(GlbError::UnknownChunkType(ty)),
        }?;
        Ok(Self { length, ty })
    }
}

impl<'a> Glb<'a> {
    /// Splits loaded GLB into its three chunks.
    ///
    /// * Mandatory GLB header.
    /// * Mandatory JSON chunk.
    /// * Optional BIN chunk.
    pub fn from_slice(mut data: &'a [u8]) -> Result<Self, Error> {
        let header = Header::from_reader(&mut data)
            .and_then(|header| if header.length as usize <= data.len() {
                Ok(header)
            } else {
                Err(GlbError::Length {
                    length: header.length,
                    length_read: data.len(),
                })
            })
            .map_err(Error::Glb)?;
        match header.version {
            2 => Self::from_v2(data)
                .map(|(json, bin)| Glb { header, json, bin })
                .map_err(Error::Glb),
            x => Err(Error::Glb(GlbError::Version(x)))
        }
    }

    /// Does the loading job for you.  Provided buf will be cleared before new
    /// data will be written.  When error happens, if only header was read, buf
    /// will not be mutated, otherwise, buf will be empty.
    pub fn from_reader<R: io::Read>(mut reader: R,
                                    buf: &'a mut Vec<u8>) -> Result<Self, Error> {
        let header = Header::from_reader(&mut reader).map_err(Error::Glb)?;
        match header.version {
            2 => {
                buf.clear();
                buf.reserve(header.length as usize);
                // SAFETY: We are doing unsafe operation on a user-supplied
                // container!  Make sure not to expose user to uninitialized
                // data if an error happens during reading.
                //
                // It is guaranteed by reserve's implementation that the reserve
                // call will make buf's capacity _at least_ header.length.
                //
                // We do not read contents of the Vec unless it is fully
                // initialized.
                unsafe { buf.set_len(header.length as usize) };
                if let Err(e) = reader.read(buf)
                    .map_err(GlbError::IoError)
                    .and_then(|len| if len == header.length as usize {
                        Ok(())
                    } else {
                        Err(GlbError::Length {
                            length: header.length,
                            length_read: len,
                        })
                    })
                {
                    // SAFETY: It is safe to not run destructors because u8 has
                    // none.
                    unsafe { buf.set_len(0) };
                    Err(Error::Glb(e))
                } else {
                    Self::from_v2(buf)
                       .map(|(json, bin)| Glb { header, json, bin })
                       .map_err(Error::Glb)
                }
            }
            x => Err(Error::Glb(GlbError::Version(x)))
        }
    }

    /// Loads GLB for glTF 2.
    fn from_v2(mut data: &'a [u8]) -> Result<(&'a [u8], Option<&'a [u8]>), GlbError> {
        let (json, mut data) = ChunkHeader::from_reader(&mut data)
            .and_then(|json_h| if let ChunkType::Json = json_h.ty {
                Ok(json_h)
            } else {
                Err(GlbError::ChunkType(json_h.ty))
            })
            .and_then(|json_h| if json_h.length as usize <= data.len() {
                Ok(json_h)
            } else {
                Err(GlbError::ChunkLength {
                    ty: json_h.ty,
                    length: json_h.length,
                    length_read: data.len(),
                })
            })
            // PANIC: We have verified that json_h.length is no greater than
            // that of data.len().
            .map(|json_h| data.split_at(json_h.length as usize))?;

        let bin = if data.len() > 0 {
            ChunkHeader::from_reader(&mut data)
                .and_then(|bin_h| if let ChunkType::Bin = bin_h.ty {
                    Ok(bin_h)
                } else {
                    Err(GlbError::ChunkType(bin_h.ty))
                })
                .and_then(|bin_h| if bin_h.length as usize <= data.len() {
                    Ok(bin_h)
                } else {
                    Err(GlbError::ChunkLength {
                        ty: bin_h.ty,
                        length: bin_h.length,
                        length_read: data.len(),
                    })
                })
                // PANIC: we have verified that bin_h.length is no greater than
                // that of data.len().
                .map(|bin_h| data.split_at(bin_h.length as usize))
                .map(|(x, _)| Some(x))?
        } else {
            None
        };
        Ok((json, bin))
    }
}

impl fmt::Display for GlbError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl ::std::error::Error for GlbError {
    fn description(&self) -> &str {
         match *self {
             GlbError::IoError(ref e) => e.description(),
             GlbError::Version(_) => "unsupported version",
             GlbError::Magic(_) => "not glTF magic",
             GlbError::Length { .. } => "could not completely read the object",
             GlbError::ChunkLength { ty, .. } => match ty {
                 ChunkType::Json => "JSON chunk length exceeds that of slice",
                 ChunkType::Bin => "BIN\\0 chunk length exceeds that of slice",
                 _ => "chunk length exceeds that of slice",
             },
             GlbError::ChunkType(ty) => match ty {
                 ChunkType::Json => "was not expecting JSON chunk",
                 ChunkType::Bin => "was not expecting BIN\\0 chunk",
                 _ => "was not expecting a chunk",
             },
             GlbError::UnknownChunkType(ty) => "unknown chunk type",
        }
    }
}
<commit_msg>Remove dead code<commit_after>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use byteorder::{LE, ReadBytesExt};

use Error;

use std::{fmt, io};

/// Represents a Glb loader error.
#[derive(Debug)]
pub enum GlbError {
    /// Io error occured.
    IoError(::std::io::Error),
    /// Unsupported version.
    Version(u32),
    /// Magic says that file is not glTF.
    Magic([u8; 4]),
    /// Length specified in GLB header exceeeds that of slice.
    Length {
        /// length specified in GLB header.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Stream ended before we could read the chunk.
    ChunkLength {
        /// chunkType error happened at.
        ty: ChunkType,
        /// chunkLength.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Chunk of this chunkType was not expected.
    ChunkType(ChunkType),
    /// Unknown chunk type.
    UnknownChunkType([u8; 4]),
}

/// The contents of a .glb file.
#[derive(Clone, Debug)]
pub struct Glb<'a> {
    /// The header section of the `.glb` file.
    pub header: Header,
    /// The JSON section of the `.glb` file.
    pub json: &'a [u8],
    /// The optional BIN section of the `.glb` file.
    pub bin: Option<&'a [u8]>,
}

/// The header section of a .glb file.
#[derive(Copy, Clone, Debug)]
pub struct Header {
    /// Must be `b"glTF"`.
    pub magic: [u8; 4],
    /// Must be `2`.
    pub version: u32,
    /// Must match the length of the parent .glb file.
    pub length: u32,
}

/// GLB chunk type.
#[derive(Copy, Clone, Debug)]
pub enum ChunkType {
    /// JSON chunk.
    Json,
    /// BIN\0 chunk.
    Bin,
}

/// Chunk header with no data read yet.
#[derive(Copy, Clone, Debug)]
struct ChunkHeader {
    /// The length of the chunk data in byte excluding the header.
    length: u32,
    /// Chunk type.
    ty: ChunkType,
}

impl Header {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, GlbError> {
        use self::GlbError::IoError;
        let mut magic = [0; 4];
        reader.read_exact(&mut magic).map_err(IoError)?;
        // We only validate magic as we don't care for version and length of
        // contents, the caller does.  Let them decide what to do next with
        // regard to version and length.
        if &magic == b"glTF" {
            Ok(Self {
                magic,
                version: reader.read_u32::<LE>().map_err(IoError)?,
                length: reader.read_u32::<LE>().map_err(IoError)?,
            })
        } else {
            Err(GlbError::Magic(magic))
        }
    }
}

impl ChunkHeader {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, GlbError> {
        use self::GlbError::IoError;
        let length = reader.read_u32::<LE>().map_err(IoError)?;
        let mut ty = [0; 4];
        reader.read_exact(&mut ty).map_err(IoError)?;
        let ty = match &ty {
            b"JSON" => Ok(ChunkType::Json),
            b"BIN\0" => Ok(ChunkType::Bin),
            _ => Err(GlbError::UnknownChunkType(ty)),
        }?;
        Ok(Self { length, ty })
    }
}

impl<'a> Glb<'a> {
    /// Splits loaded GLB into its three chunks.
    ///
    /// * Mandatory GLB header.
    /// * Mandatory JSON chunk.
    /// * Optional BIN chunk.
    pub fn from_slice(mut data: &'a [u8]) -> Result<Self, Error> {
        let header = Header::from_reader(&mut data)
            .and_then(|header| if header.length as usize <= data.len() {
                Ok(header)
            } else {
                Err(GlbError::Length {
                    length: header.length,
                    length_read: data.len(),
                })
            })
            .map_err(Error::Glb)?;
        match header.version {
            2 => Self::from_v2(data)
                .map(|(json, bin)| Glb { header, json, bin })
                .map_err(Error::Glb),
            x => Err(Error::Glb(GlbError::Version(x)))
        }
    }

    /// Does the loading job for you.  Provided buf will be cleared before new
    /// data will be written.  When error happens, if only header was read, buf
    /// will not be mutated, otherwise, buf will be empty.
    pub fn from_reader<R: io::Read>(mut reader: R,
                                    buf: &'a mut Vec<u8>) -> Result<Self, Error> {
        let header = Header::from_reader(&mut reader).map_err(Error::Glb)?;
        match header.version {
            2 => {
                buf.clear();
                buf.reserve(header.length as usize);
                // SAFETY: We are doing unsafe operation on a user-supplied
                // container!  Make sure not to expose user to uninitialized
                // data if an error happens during reading.
                //
                // It is guaranteed by reserve's implementation that the reserve
                // call will make buf's capacity _at least_ header.length.
                //
                // We do not read contents of the Vec unless it is fully
                // initialized.
                unsafe { buf.set_len(header.length as usize) };
                if let Err(e) = reader.read(buf)
                    .map_err(GlbError::IoError)
                    .and_then(|len| if len == header.length as usize {
                        Ok(())
                    } else {
                        Err(GlbError::Length {
                            length: header.length,
                            length_read: len,
                        })
                    })
                {
                    // SAFETY: It is safe to not run destructors because u8 has
                    // none.
                    unsafe { buf.set_len(0) };
                    Err(Error::Glb(e))
                } else {
                    Self::from_v2(buf)
                       .map(|(json, bin)| Glb { header, json, bin })
                       .map_err(Error::Glb)
                }
            }
            x => Err(Error::Glb(GlbError::Version(x)))
        }
    }

    /// Loads GLB for glTF 2.
    fn from_v2(mut data: &'a [u8]) -> Result<(&'a [u8], Option<&'a [u8]>), GlbError> {
        let (json, mut data) = ChunkHeader::from_reader(&mut data)
            .and_then(|json_h| if let ChunkType::Json = json_h.ty {
                Ok(json_h)
            } else {
                Err(GlbError::ChunkType(json_h.ty))
            })
            .and_then(|json_h| if json_h.length as usize <= data.len() {
                Ok(json_h)
            } else {
                Err(GlbError::ChunkLength {
                    ty: json_h.ty,
                    length: json_h.length,
                    length_read: data.len(),
                })
            })
            // PANIC: We have verified that json_h.length is no greater than
            // that of data.len().
            .map(|json_h| data.split_at(json_h.length as usize))?;

        let bin = if data.len() > 0 {
            ChunkHeader::from_reader(&mut data)
                .and_then(|bin_h| if let ChunkType::Bin = bin_h.ty {
                    Ok(bin_h)
                } else {
                    Err(GlbError::ChunkType(bin_h.ty))
                })
                .and_then(|bin_h| if bin_h.length as usize <= data.len() {
                    Ok(bin_h)
                } else {
                    Err(GlbError::ChunkLength {
                        ty: bin_h.ty,
                        length: bin_h.length,
                        length_read: data.len(),
                    })
                })
                // PANIC: we have verified that bin_h.length is no greater than
                // that of data.len().
                .map(|bin_h| data.split_at(bin_h.length as usize))
                .map(|(x, _)| Some(x))?
        } else {
            None
        };
        Ok((json, bin))
    }
}

impl fmt::Display for GlbError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl ::std::error::Error for GlbError {
    fn description(&self) -> &str {
         match *self {
             GlbError::IoError(ref e) => e.description(),
             GlbError::Version(_) => "unsupported version",
             GlbError::Magic(_) => "not glTF magic",
             GlbError::Length { .. } => "could not completely read the object",
             GlbError::ChunkLength { ty, .. } => match ty {
                 ChunkType::Json => "JSON chunk length exceeds that of slice",
                 ChunkType::Bin => "BIN\\0 chunk length exceeds that of slice",
             },
             GlbError::ChunkType(ty) => match ty {
                 ChunkType::Json => "was not expecting JSON chunk",
                 ChunkType::Bin => "was not expecting BIN\\0 chunk",
             },
             GlbError::UnknownChunkType(_) => "unknown chunk type",
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

use std::io::{self, Read, Seek, SeekFrom};
use std::mem::transmute;

use static_assertions::assert_eq_size;

// TODO static assertion

// Minimal ELF support, sufficient for a very simple 64-bit static Linux
// executable.

// Sources:
// * /usr/include/elf.h
// * https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
// * https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html

type Elf64_Half = u16;
type Elf64_Word = u32;
type Elf64_Xword = u64;
type Elf64_Addr = u64;
type Elf64_Off = u64;

const ELFOSABI_LINUX: u8 = 3;
const ET_EXEC: u16 = 2;
const EM_X86_64: u16 = 62;
const PT_LOAD: u32 = 1;

const PF_X: u32 = 1 << 0;
const PF_W: u32 = 1 << 1;
const PF_R: u32 = 1 << 2;

const EHDR_SIZE: usize = 64;
const PHDR_SIZE: usize = 56;
const SHDR_SIZE: usize = 64;

assert_eq_size!(ehdr_size_assert; Elf64_Ehdr, [u8; EHDR_SIZE]);
assert_eq_size!(phdr_size_assert; Elf64_Phdr, [u8; PHDR_SIZE]);
assert_eq_size!(shdr_size_assert; Elf64_Shdr, [u8; SHDR_SIZE]);

// ELF header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Ehdr {
    pub e_ident: [u8; 16],
    pub e_type: Elf64_Half,
    pub e_machine: Elf64_Half,
    pub e_version: Elf64_Word,
    pub e_entry: Elf64_Addr,
    pub e_phoff: Elf64_Off,
    pub e_shoff: Elf64_Off,
    pub e_flags: Elf64_Word,
    pub e_ehsize: Elf64_Half,
    pub e_phentsize: Elf64_Half,
    pub e_phnum: Elf64_Half,
    pub e_shentsize: Elf64_Half,
    pub e_shnum: Elf64_Half,
    pub e_shstrndx: Elf64_Half,
}

// Program header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Phdr {
    pub p_type: Elf64_Word,
    pub p_flags: Elf64_Word,
    pub p_offset: Elf64_Off,
    pub p_vaddr: Elf64_Addr,
    pub p_paddr: Elf64_Addr,
    pub p_filesz: Elf64_Xword,
    pub p_memsz: Elf64_Xword,
    pub p_align: Elf64_Xword,
}

// Symbol header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Elf64_Shdr {
    pub sh_name: Elf64_Word,
    pub sh_type: Elf64_Word,
    pub sh_flags: Elf64_Xword,
    pub sh_addr: Elf64_Addr,
    pub sh_offset: Elf64_Off,
    pub sh_size: Elf64_Xword,
    pub sh_link: Elf64_Word,
    pub sh_info: Elf64_Word,
    pub sh_addralign: Elf64_Xword,
    pub sh_entsize: Elf64_Xword,
}

pub fn create_elf64_hdr(size: u64, bss_size: u64) -> Vec<u8> {
    let ehdr = Elf64_Ehdr {
        e_ident: [0x7f, b'E', b'L', b'F', 2, 1, 1, ELFOSABI_LINUX, 0, 0, 0, 0, 0, 0, 0, 0 ],
        e_type: ET_EXEC,
        e_machine: EM_X86_64,
        e_version: 1,
        e_entry: 0x401000,
        // Put program header immediately after ELF header
        e_phoff: EHDR_SIZE as u64,
        // Don't include a section header table
        e_shoff: 0,
        e_flags: 0,
        e_ehsize: EHDR_SIZE as u16,
        e_phentsize: PHDR_SIZE as u16,
        e_phnum: 2,
        e_shentsize: SHDR_SIZE as u16,
        e_shnum: 0,
        e_shstrndx: 0,
    };

    let phdr_text = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_X,
        p_offset: 0,
        p_vaddr: 0x401000,
        p_paddr: 0x401000,
        p_filesz: size,
        p_memsz: size,
        p_align: 0x1000,
    };

    let bss_offset = (size + 0x1000 - 1) & !(0x1000 - 1);

    println!("{:x} - {:x}", bss_offset, bss_size);

    let phdr_bss = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_W,
        p_offset: bss_offset,
        p_vaddr: 0x401000 + bss_offset,
        p_paddr: 0x401000 + bss_offset,
        p_filesz: 0,
        p_memsz: bss_size,
        p_align: 0x1000,
    };

    let mut vec = Vec::new();
    unsafe {
        vec.extend_from_slice(&transmute::<_, [u8; EHDR_SIZE]>(ehdr));
        vec.extend_from_slice(&transmute::<_, [u8; PHDR_SIZE]>(phdr_text));
        vec.extend_from_slice(&transmute::<_, [u8; PHDR_SIZE]>(phdr_bss));
    }
    vec
}

fn elf64_read_strtab(f: &mut (impl Read + Seek), ehdr: &Elf64_Ehdr) -> io::Result<Vec<u8>> {
    // Read section header for the string table
    let mut shdr_buf = [0; SHDR_SIZE];
    f.seek(SeekFrom::Start(ehdr.e_shoff + ehdr.e_shstrndx as u64 * SHDR_SIZE as u64))?;
    f.read(&mut shdr_buf)?;
    let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

    // Read string table section
    let mut strtab = Vec::with_capacity(shdr.sh_size as usize);
    strtab.resize(shdr.sh_size as usize, 0);
    f.seek(SeekFrom::Start(shdr.sh_offset))?;
    f.read(&mut strtab)?;

    Ok(strtab)
}

pub fn elf64_get_section(f: &mut (impl Read + Seek), name: &[u8]) -> io::Result<Option<Elf64_Shdr>> {
    let mut ehdr_buf = [0; EHDR_SIZE];
    f.seek(SeekFrom::Start(0))?;
    f.read(&mut ehdr_buf)?;
    let ehdr: Elf64_Ehdr = unsafe { transmute(ehdr_buf) };

    let strtab = elf64_read_strtab(f, &ehdr)?;

    f.seek(SeekFrom::Start(ehdr.e_shoff))?;
    for _ in 0..ehdr.e_shnum {
        let mut shdr_buf = [0; SHDR_SIZE];
        f.read(&mut shdr_buf)?;
        let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

        let mut cur_name = &strtab[shdr.sh_name as usize..];
        if let Some(idx) = cur_name.iter().position(|c| *c == b'\0') {
            cur_name = &cur_name[..idx];
        }
        if cur_name == name {
            return Ok(Some(shdr));
        }
    }

    Ok(None)
}
<commit_msg>Correct offset; now elf header works<commit_after>#![allow(non_camel_case_types)]

use std::io::{self, Read, Seek, SeekFrom};
use std::mem::transmute;

use static_assertions::assert_eq_size;

// TODO static assertion

// Minimal ELF support, sufficient for a very simple 64-bit static Linux
// executable.

// Sources:
// * /usr/include/elf.h
// * https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
// * https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html

type Elf64_Half = u16;
type Elf64_Word = u32;
type Elf64_Xword = u64;
type Elf64_Addr = u64;
type Elf64_Off = u64;

const ELFOSABI_LINUX: u8 = 3;
const ET_EXEC: u16 = 2;
const EM_X86_64: u16 = 62;
const PT_LOAD: u32 = 1;

const PF_X: u32 = 1 << 0;
const PF_W: u32 = 1 << 1;
const PF_R: u32 = 1 << 2;

const EHDR_SIZE: usize = 64;
const PHDR_SIZE: usize = 56;
const SHDR_SIZE: usize = 64;

assert_eq_size!(ehdr_size_assert; Elf64_Ehdr, [u8; EHDR_SIZE]);
assert_eq_size!(phdr_size_assert; Elf64_Phdr, [u8; PHDR_SIZE]);
assert_eq_size!(shdr_size_assert; Elf64_Shdr, [u8; SHDR_SIZE]);

// ELF header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Ehdr {
    pub e_ident: [u8; 16],
    pub e_type: Elf64_Half,
    pub e_machine: Elf64_Half,
    pub e_version: Elf64_Word,
    pub e_entry: Elf64_Addr,
    pub e_phoff: Elf64_Off,
    pub e_shoff: Elf64_Off,
    pub e_flags: Elf64_Word,
    pub e_ehsize: Elf64_Half,
    pub e_phentsize: Elf64_Half,
    pub e_phnum: Elf64_Half,
    pub e_shentsize: Elf64_Half,
    pub e_shnum: Elf64_Half,
    pub e_shstrndx: Elf64_Half,
}

// Program header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Phdr {
    pub p_type: Elf64_Word,
    pub p_flags: Elf64_Word,
    pub p_offset: Elf64_Off,
    pub p_vaddr: Elf64_Addr,
    pub p_paddr: Elf64_Addr,
    pub p_filesz: Elf64_Xword,
    pub p_memsz: Elf64_Xword,
    pub p_align: Elf64_Xword,
}

// Symbol header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Elf64_Shdr {
    pub sh_name: Elf64_Word,
    pub sh_type: Elf64_Word,
    pub sh_flags: Elf64_Xword,
    pub sh_addr: Elf64_Addr,
    pub sh_offset: Elf64_Off,
    pub sh_size: Elf64_Xword,
    pub sh_link: Elf64_Word,
    pub sh_info: Elf64_Word,
    pub sh_addralign: Elf64_Xword,
    pub sh_entsize: Elf64_Xword,
}

pub fn create_elf64_hdr(size: u64, bss_size: u64) -> Vec<u8> {
    let hdr_size = (EHDR_SIZE + 2 * PHDR_SIZE) as u64;
    let hdr_size_padded = (hdr_size + 0x1000 - 1) & !(0x1000 - 1);

    let ehdr = Elf64_Ehdr {
        e_ident: [0x7f, b'E', b'L', b'F', 2, 1, 1, ELFOSABI_LINUX, 0, 0, 0, 0, 0, 0, 0, 0 ],
        e_type: ET_EXEC,
        e_machine: EM_X86_64,
        e_version: 1,
        e_entry: 0x401000,
        // Put program header immediately after ELF header
        e_phoff: EHDR_SIZE as u64,
        // Don't include a section header table
        e_shoff: 0,
        e_flags: 0,
        e_ehsize: EHDR_SIZE as u16,
        e_phentsize: PHDR_SIZE as u16,
        e_phnum: 2,
        e_shentsize: SHDR_SIZE as u16,
        e_shnum: 0,
        e_shstrndx: 0,
    };

    let phdr_text = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_X,
        p_offset: hdr_size_padded,
        p_vaddr: 0x401000,
        p_paddr: 0x401000,
        p_filesz: size,
        p_memsz: size,
        p_align: 0x1000,
    };

    let bss_offset = (size + 0x1000 - 1) & !(0x1000 - 1);

    let phdr_bss = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_W,
        p_offset: hdr_size_padded + bss_offset,
        p_vaddr: 0x401000 + bss_offset,
        p_paddr: 0x401000 + bss_offset,
        p_filesz: 0,
        p_memsz: bss_size,
        p_align: 0x1000,
    };

    let mut vec = Vec::new();
    unsafe {
        vec.extend_from_slice(&transmute::<_, [u8; EHDR_SIZE]>(ehdr));
        vec.extend_from_slice(&transmute::<_, [u8; PHDR_SIZE]>(phdr_text));
        vec.extend_from_slice(&transmute::<_, [u8; PHDR_SIZE]>(phdr_bss));
    }
    for _ in 0..(hdr_size_padded - hdr_size) {
        vec.push(0);
    }
    vec
}

fn elf64_read_strtab(f: &mut (impl Read + Seek), ehdr: &Elf64_Ehdr) -> io::Result<Vec<u8>> {
    // Read section header for the string table
    let mut shdr_buf = [0; SHDR_SIZE];
    f.seek(SeekFrom::Start(ehdr.e_shoff + ehdr.e_shstrndx as u64 * SHDR_SIZE as u64))?;
    f.read(&mut shdr_buf)?;
    let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

    // Read string table section
    let mut strtab = Vec::with_capacity(shdr.sh_size as usize);
    strtab.resize(shdr.sh_size as usize, 0);
    f.seek(SeekFrom::Start(shdr.sh_offset))?;
    f.read(&mut strtab)?;

    Ok(strtab)
}

pub fn elf64_get_section(f: &mut (impl Read + Seek), name: &[u8]) -> io::Result<Option<Elf64_Shdr>> {
    let mut ehdr_buf = [0; EHDR_SIZE];
    f.seek(SeekFrom::Start(0))?;
    f.read(&mut ehdr_buf)?;
    let ehdr: Elf64_Ehdr = unsafe { transmute(ehdr_buf) };

    let strtab = elf64_read_strtab(f, &ehdr)?;

    f.seek(SeekFrom::Start(ehdr.e_shoff))?;
    for _ in 0..ehdr.e_shnum {
        let mut shdr_buf = [0; SHDR_SIZE];
        f.read(&mut shdr_buf)?;
        let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

        let mut cur_name = &strtab[shdr.sh_name as usize..];
        if let Some(idx) = cur_name.iter().position(|c| *c == b'\0') {
            cur_name = &cur_name[..idx];
        }
        if cur_name == name {
            return Ok(Some(shdr));
        }
    }

    Ok(None)
}
<|endoftext|>


<commit_before>use std::default::Default;
use libc::{c_int, c_char, uint8_t, uint32_t, int32_t};

pub static MAX_CPUID_LEVEL: uint = 32u;
pub static MAX_EXT_CPUID_LEVEL: uint = 32u;
pub static MAX_INTELFN4_LEVEL: uint = 4u;
pub static MAX_INTELFN11_LEVEL: uint = 4u;
pub static VENDOR_STR_MAX: uint = 16u;
pub static BRAND_STR_MAX: uint = 64u;
pub static CPU_FLAGS_MAX: uint = 128u;
pub static CPU_HINTS_MAX: uint = 16u;

#[repr(C)]
pub struct cpu_raw_data_t {
    pub basic_cpuid: [[uint32_t, ..4u], ..MAX_CPUID_LEVEL],
    pub ext_cpuid: [[uint32_t, ..4u], ..MAX_EXT_CPUID_LEVEL],
    pub intel_fn4: [[uint32_t, ..4u], ..MAX_INTELFN4_LEVEL],
    pub intel_fn11: [[uint32_t, ..4u], ..MAX_INTELFN11_LEVEL],
}

impl Default for cpu_raw_data_t {
    fn default() -> cpu_raw_data_t {
        cpu_raw_data_t {
            basic_cpuid: [[0, ..4u], ..MAX_CPUID_LEVEL],
            ext_cpuid: [[0, ..4u], ..MAX_EXT_CPUID_LEVEL],
            intel_fn4: [[0, ..4u], ..MAX_INTELFN4_LEVEL],
            intel_fn11: [[0, ..4u], ..MAX_INTELFN11_LEVEL],
        }
    }
}

#[repr(C)]
pub struct cpu_id_t {
    pub vendor_str: [c_char, ..VENDOR_STR_MAX],
    pub brand_str: [c_char, ..BRAND_STR_MAX],
    pub vendor: int32_t,
    pub flags: [uint8_t, ..CPU_FLAGS_MAX],
    pub family: int32_t,
    pub model: int32_t,
    pub stepping: int32_t,
    pub ext_family: int32_t,
    pub ext_model: int32_t,
    pub num_cores: int32_t,
    pub num_logical_cpus: int32_t,
    pub total_logical_cpus: int32_t,
    pub l1_data_cache: int32_t,
    pub l1_instruction_cache: int32_t,
    pub l2_cache: int32_t,
    pub l3_cache: int32_t,
    pub l1_assoc: int32_t,
    pub l2_assoc: int32_t,
    pub l3_assoc: int32_t,
    pub l1_cacheline: int32_t,
    pub l2_cacheline: int32_t,
    pub l3_cacheline: int32_t,
    pub cpu_codename: [c_char, ..64],
    pub sse_size: int32_t,
    pub detection_hints: [uint8_t, ..CPU_HINTS_MAX],
}

impl Default for cpu_id_t {
    fn default() -> cpu_id_t {
        cpu_id_t {
            vendor_str: [0, ..VENDOR_STR_MAX],
            brand_str: [0, ..BRAND_STR_MAX],
            vendor: 0,
            flags: [0u8, ..CPU_FLAGS_MAX],
            family: 0,
            model: 0,
            stepping: 0,
            ext_family: 0,
            ext_model: 0,
            num_cores: 0,
            num_logical_cpus: 0,
            total_logical_cpus: 0,
            l1_data_cache: 0,
            l1_instruction_cache: 0,
            l2_cache: 0,
            l3_cache: 0,
            l1_assoc: 0,
            l2_assoc: 0,
            l3_assoc: 0,
            l1_cacheline: 0,
            l2_cacheline: 0,
            l3_cacheline: 0,
            cpu_codename: [0, ..64],
            sse_size: 0,
            detection_hints: [0u8, ..CPU_HINTS_MAX],
        }
    }
}

#[link(name = "cpuid")]
extern {
    pub fn cpuid_present() -> c_int;
    pub fn cpuid_lib_version() -> *const c_char;
    pub fn cpuid_error() -> *const c_char;
    pub fn cpuid_get_raw_data(raw: *mut cpu_raw_data_t) -> c_int;
    pub fn cpu_identify(raw: *mut cpu_raw_data_t, data: *mut cpu_id_t) -> c_int;
    pub fn cpu_clock() -> c_int;
}
<commit_msg>static -> const<commit_after>use std::default::Default;
use libc::{c_int, c_char, uint8_t, uint32_t, int32_t};

pub const MAX_CPUID_LEVEL: uint = 32u;
pub const MAX_EXT_CPUID_LEVEL: uint = 32u;
pub const MAX_INTELFN4_LEVEL: uint = 4u;
pub const MAX_INTELFN11_LEVEL: uint = 4u;
pub const VENDOR_STR_MAX: uint = 16u;
pub const BRAND_STR_MAX: uint = 64u;
pub const CPU_FLAGS_MAX: uint = 128u;
pub const CPU_HINTS_MAX: uint = 16u;

#[repr(C)]
pub struct cpu_raw_data_t {
    pub basic_cpuid: [[uint32_t, ..4u], ..MAX_CPUID_LEVEL],
    pub ext_cpuid: [[uint32_t, ..4u], ..MAX_EXT_CPUID_LEVEL],
    pub intel_fn4: [[uint32_t, ..4u], ..MAX_INTELFN4_LEVEL],
    pub intel_fn11: [[uint32_t, ..4u], ..MAX_INTELFN11_LEVEL],
}

impl Default for cpu_raw_data_t {
    fn default() -> cpu_raw_data_t {
        cpu_raw_data_t {
            basic_cpuid: [[0, ..4u], ..MAX_CPUID_LEVEL],
            ext_cpuid: [[0, ..4u], ..MAX_EXT_CPUID_LEVEL],
            intel_fn4: [[0, ..4u], ..MAX_INTELFN4_LEVEL],
            intel_fn11: [[0, ..4u], ..MAX_INTELFN11_LEVEL],
        }
    }
}

#[repr(C)]
pub struct cpu_id_t {
    pub vendor_str: [c_char, ..VENDOR_STR_MAX],
    pub brand_str: [c_char, ..BRAND_STR_MAX],
    pub vendor: int32_t,
    pub flags: [uint8_t, ..CPU_FLAGS_MAX],
    pub family: int32_t,
    pub model: int32_t,
    pub stepping: int32_t,
    pub ext_family: int32_t,
    pub ext_model: int32_t,
    pub num_cores: int32_t,
    pub num_logical_cpus: int32_t,
    pub total_logical_cpus: int32_t,
    pub l1_data_cache: int32_t,
    pub l1_instruction_cache: int32_t,
    pub l2_cache: int32_t,
    pub l3_cache: int32_t,
    pub l1_assoc: int32_t,
    pub l2_assoc: int32_t,
    pub l3_assoc: int32_t,
    pub l1_cacheline: int32_t,
    pub l2_cacheline: int32_t,
    pub l3_cacheline: int32_t,
    pub cpu_codename: [c_char, ..64],
    pub sse_size: int32_t,
    pub detection_hints: [uint8_t, ..CPU_HINTS_MAX],
}

impl Default for cpu_id_t {
    fn default() -> cpu_id_t {
        cpu_id_t {
            vendor_str: [0, ..VENDOR_STR_MAX],
            brand_str: [0, ..BRAND_STR_MAX],
            vendor: 0,
            flags: [0u8, ..CPU_FLAGS_MAX],
            family: 0,
            model: 0,
            stepping: 0,
            ext_family: 0,
            ext_model: 0,
            num_cores: 0,
            num_logical_cpus: 0,
            total_logical_cpus: 0,
            l1_data_cache: 0,
            l1_instruction_cache: 0,
            l2_cache: 0,
            l3_cache: 0,
            l1_assoc: 0,
            l2_assoc: 0,
            l3_assoc: 0,
            l1_cacheline: 0,
            l2_cacheline: 0,
            l3_cacheline: 0,
            cpu_codename: [0, ..64],
            sse_size: 0,
            detection_hints: [0u8, ..CPU_HINTS_MAX],
        }
    }
}

#[link(name = "cpuid")]
extern {
    pub fn cpuid_present() -> c_int;
    pub fn cpuid_lib_version() -> *const c_char;
    pub fn cpuid_error() -> *const c_char;
    pub fn cpuid_get_raw_data(raw: *mut cpu_raw_data_t) -> c_int;
    pub fn cpu_identify(raw: *mut cpu_raw_data_t, data: *mut cpu_id_t) -> c_int;
    pub fn cpu_clock() -> c_int;
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
const END_TAG_LEN: u32 = 8;

#[macro_use]
macro_rules! ptr {
    ($it:expr) => { &$it as *const _ }
}

pub mod elf;
pub mod elf64;

#[repr(C)]
pub struct Info { pub length: u32
                , _pad: u32
                , tag_start: Tag
                }

impl Info {

    pub unsafe fn from(addr: usize) -> &'static Self {
        let info = &*(addr as *const Info);
        assert!(info.has_end());
        info
    }

    /// Finds the tag with the given tag type.
    ///
    /// This is actually safe since the tag types are constrained by The
    /// `TagType` enum
    pub fn get_tag(&self, tag_type: TagType) -> Option<&'static Tag> {
        self.tags()
            .find(|t| t.ty == tag_type)
    }

    #[inline]
    pub fn mem_map(&self) -> Option<&'static MemMapTag> {
        self.get_tag(TagType::MemoryMap)
            .map(|tag| unsafe { &*((tag as *const Tag) as *const MemMapTag) })
    }

    #[inline]
    pub fn elf64_sections(&self) -> Option<&'static elf64::SectionsTag> {
        self.get_tag(TagType::ELFSections)
            .map(|tag| unsafe {
                &*((tag as *const Tag) as *const elf64::SectionsTag)
            })
    }

    #[inline]
    fn tags(&self) -> Tags { Tags(ptr!(self.tag_start)) }

    fn has_end(&self) -> bool {
        let end_tag_addr
            = (self as *const _) as usize +
              (self.length - END_TAG_LEN) as usize;
        let end_tag = unsafe {&*(end_tag_addr as *const Tag)};
        end_tag.ty == TagType::End && end_tag.length == 8
    }
}

/// A Multiboot tag.
///
/// From the specification:
///
/// Boot information consists of a fixed part and a series of tags.
/// Its start is 8-bytes aligned. Fixed part is as following:
///
///<rawtext>
///
///             +-------------------+
///     u32     | total_size        |
///     u32     | reserved          |
///             +-------------------+
///</rawtext>
///
/// `total_size` contains the total size of boot information including this
/// field and terminating tag in bytes.
/// `reserved` is always set to zero and must be ignored by OS image.
///
///  Every tag begins with following fields:
///<rawtext>
///
///             +-------------------+
///     u32     | type              |
///     u32     | size              |
///             +-------------------+
///</rawtext>
/// `type` contains an identifier of contents of the rest of the tag. `size`
/// contains the size of tag including header fields but not including padding.
/// Tags follow one another padded when necessary in order for each tag to
/// start at 8-bytes aligned address. Tags are terminated by a tag of type `0`
/// and size `8`.
#[repr(C)]
#[derive(Debug)]
pub struct Tag { ty: TagType
               , length: u32
               }

/// Types of Multiboot tags
///
/// Refer to Chapter 3 of the Multiboot 2 spec
#[repr(u32)]
#[derive(Debug, Eq, PartialEq)]
pub enum TagType { /// Tag that indicates the end of multiboot tags
                   End              = 0
                 , /// Command line passed to the bootloader
                   CommandLine      = 1
                 , BootloaderName   = 2
                 , Modules          = 3
                 , BasicMemInfo     = 4
                 , BIOSBootDev      = 5
                 , MemoryMap        = 6
                 , VBEInfo          = 7
                 , FramebufferInfo  = 8
                 , ELFSections      = 9
                 , APMTable         = 10
                 }

struct Tags(*const Tag);

impl Tags {
    #[inline] fn advance(&mut self, size: u32) {
        let next_addr = self.0 as usize + size as usize;
        self.0 = (((next_addr-1) & !0x7) + 0x8) as *const _;
    }
}

impl Iterator for Tags {
    type Item = &'static Tag;

    fn next(&mut self) -> Option<Self::Item> {
        match unsafe { &*self.0 } {
            &Tag{ ty: TagType::End, length: END_TAG_LEN } => None
          , tag => { self.advance(tag.length); Some(tag) }
        }
    }
}

#[repr(C)]
pub struct MemMapTag { tag: Tag
                     , entry_size: u32
                     , entry_version: u32
                     , first_entry: MemArea
                     }
impl MemMapTag {
    pub fn entries(&self) -> Entries {
        Entries { curr: (&self.first_entry) as *const MemArea
                , last: ((self as *const MemMapTag as u32) +
                        self.tag.length - self.entry_size)
                        as *const MemArea
                , size: self.entry_size
                }
    }
}

#[repr(u32)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum MemAreaType { Available = 1
                     , ACPI      = 3
                     , Preserve  = 4
                     }

#[repr(C)]
pub struct MemArea { pub base: u64
                   , pub length: u64
                   , ty: MemAreaType
                   , _pad: u32
                   }

pub struct Entries { curr: *const MemArea
                   , last: *const MemArea
                   , size: u32
                   }

impl Iterator for Entries {
    type Item = &'static MemArea;
    fn next(&mut self) -> Option<&'static MemArea> {
        if self.curr > self.last {
            None
        } else {
            let current = unsafe { &*self.curr };
            self.curr = (self.curr as u32 + self.size) as *const MemArea;
            if current.ty == MemAreaType::Available {
                Some(current)
            } else {
                self.next()
            }
        }
    }
}
<commit_msg>The `ptr!()` macro is Evil And Should Not Be Used<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
const END_TAG_LEN: u32 = 8;
pub mod elf;
pub mod elf64;

#[repr(C)]
pub struct Info { pub length: u32
                , _pad: u32
                , tag_start: Tag
                }

impl Info {

    pub unsafe fn from(addr: usize) -> &'static Self {
        let info = &*(addr as *const Info);
        assert!(info.has_end());
        info
    }

    /// Finds the tag with the given tag type.
    ///
    /// This is actually safe since the tag types are constrained by The
    /// `TagType` enum
    pub fn get_tag(&self, tag_type: TagType) -> Option<&'static Tag> {
        self.tags()
            .find(|t| t.ty == tag_type)
    }

    #[inline]
    pub fn mem_map(&self) -> Option<&'static MemMapTag> {
        self.get_tag(TagType::MemoryMap)
            .map(|tag| unsafe { &*((tag as *const Tag) as *const MemMapTag) })
    }

    #[inline]
    pub fn elf64_sections(&self) -> Option<&'static elf64::SectionsTag> {
        self.get_tag(TagType::ELFSections)
            .map(|tag| unsafe {
                &*((tag as *const Tag) as *const elf64::SectionsTag)
            })
    }

    #[inline]
    fn tags(&self) -> Tags { Tags(&self.tag_start as *const Tag) }

    fn has_end(&self) -> bool {
        let end_tag_addr
            = (self as *const _) as usize +
              (self.length - END_TAG_LEN) as usize;
        let end_tag = unsafe {&*(end_tag_addr as *const Tag)};
        end_tag.ty == TagType::End && end_tag.length == 8
    }
}

/// A Multiboot tag.
///
/// From the specification:
///
/// Boot information consists of a fixed part and a series of tags.
/// Its start is 8-bytes aligned. Fixed part is as following:
///
///<rawtext>
///
///             +-------------------+
///     u32     | total_size        |
///     u32     | reserved          |
///             +-------------------+
///</rawtext>
///
/// `total_size` contains the total size of boot information including this
/// field and terminating tag in bytes.
/// `reserved` is always set to zero and must be ignored by OS image.
///
///  Every tag begins with following fields:
///<rawtext>
///
///             +-------------------+
///     u32     | type              |
///     u32     | size              |
///             +-------------------+
///</rawtext>
/// `type` contains an identifier of contents of the rest of the tag. `size`
/// contains the size of tag including header fields but not including padding.
/// Tags follow one another padded when necessary in order for each tag to
/// start at 8-bytes aligned address. Tags are terminated by a tag of type `0`
/// and size `8`.
#[repr(C)]
#[derive(Debug)]
pub struct Tag { ty: TagType
               , length: u32
               }

/// Types of Multiboot tags
///
/// Refer to Chapter 3 of the Multiboot 2 spec
#[repr(u32)]
#[derive(Debug, Eq, PartialEq)]
pub enum TagType { /// Tag that indicates the end of multiboot tags
                   End              = 0
                 , /// Command line passed to the bootloader
                   CommandLine      = 1
                 , BootloaderName   = 2
                 , Modules          = 3
                 , BasicMemInfo     = 4
                 , BIOSBootDev      = 5
                 , MemoryMap        = 6
                 , VBEInfo          = 7
                 , FramebufferInfo  = 8
                 , ELFSections      = 9
                 , APMTable         = 10
                 }

struct Tags(*const Tag);

impl Tags {
    #[inline] fn advance(&mut self, size: u32) {
        let next_addr = self.0 as usize + size as usize;
        self.0 = (((next_addr-1) & !0x7) + 0x8) as *const _;
    }
}

impl Iterator for Tags {
    type Item = &'static Tag;

    fn next(&mut self) -> Option<Self::Item> {
        match unsafe { &*self.0 } {
            &Tag{ ty: TagType::End, length: END_TAG_LEN } => None
          , tag => { self.advance(tag.length); Some(tag) }
        }
    }
}

#[repr(C)]
pub struct MemMapTag { tag: Tag
                     , entry_size: u32
                     , entry_version: u32
                     , first_entry: MemArea
                     }
impl MemMapTag {
    pub fn entries(&self) -> Entries {
        Entries { curr: (&self.first_entry) as *const MemArea
                , last: ((self as *const MemMapTag as u32) +
                        self.tag.length - self.entry_size)
                        as *const MemArea
                , size: self.entry_size
                }
    }
}

#[repr(u32)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum MemAreaType { Available = 1
                     , ACPI      = 3
                     , Preserve  = 4
                     }

#[repr(C)]
pub struct MemArea { pub base: u64
                   , pub length: u64
                   , ty: MemAreaType
                   , _pad: u32
                   }

pub struct Entries { curr: *const MemArea
                   , last: *const MemArea
                   , size: u32
                   }

impl Iterator for Entries {
    type Item = &'static MemArea;
    fn next(&mut self) -> Option<&'static MemArea> {
        if self.curr > self.last {
            None
        } else {
            let current = unsafe { &*self.curr };
            self.curr = (self.curr as u32 + self.size) as *const MemArea;
            if current.ty == MemAreaType::Available {
                Some(current)
            } else {
                self.next()
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::iter::IntoIterator;

////////////////////////////////////////////////////////////////////////////////
// List implementation

pub struct List<T> {
    head: Link<T>,
}

type Link<T> = Option<Box<Node<T>>>;

struct Node<T> {
    elem: T,
    next: Link<T>,
}

impl<T> List<T> {
    fn new() -> Self {
        List { head: None }
    }

    // TODO: Figure out how to return self.
    fn push(&mut self, elem: T) {
        self.head = Some(Box::new(Node { elem: elem, next: self.head.take() }));
    }

    fn pop(&mut self) -> Option<T> {
        // Option<Box<Node<T>>>
        self.head.take().map(|node| { // Box<Node<T>>
            let node = *node;
            self.head = node.next;
            node.elem
        })
    }

    fn peek(&self) -> Option<&T> {
        self.head.as_ref().map(|node| { &node.elem })
    }

    fn peek_mut(&mut self) -> Option<&mut T> {
        self.head.as_mut().map(|node| { &mut node.elem })
    }

    fn iter(&self) -> Iter<T> {
        Iter { link: &self.head }
    }
}

////////////////////////////////////////////////////////////////////////////////
// By-reference Iter

pub struct Iter<'a, T: 'a> {
    link: &'a Link<T>,
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        self.link.as_ref().map(|node| {
            self.link = &node.next;
            &node.elem
        })
    }
}

////////////////////////////////////////////////////////////////////////////////
// IntoIterator

pub struct ListIntoIterator<T> {
    list: List<T>,
}

impl<T> Iterator for ListIntoIterator<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        self.list.pop()
    }
}

impl<T> IntoIterator for List<T> {
    type Item = T;
    type IntoIter = ListIntoIterator<T>;

    fn into_iter(self) -> ListIntoIterator<T> {
        ListIntoIterator { list: self }
    }
}

impl<'a, T> IntoIterator for &'a List<T> {
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Iter<'a, T> {
        self.iter()
    }
}

////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod test {
    use super::List;

    #[test]
    fn test_push_pop() {
        let mut list = List::new();
        list.push(1);
        assert_eq!(Some(&1), list.peek());
        list.push(2);
        assert_eq!(Some(&2), list.peek());
        list.push(3);
        assert_eq!(Some(&3), list.peek());
        assert_eq!(Some(3), list.pop());
        assert_eq!(Some(2), list.pop());
        assert_eq!(Some(1), list.pop());
        assert_eq!(None, list.pop());
    }

    #[test]
    fn test_into_iter() {
        let mut list = List::new();
        list.push(1);
        list.push(2);
        list.push(3);
        let mut i = 3;
        for val in list {
            assert_eq!(i, val);
            i -= 1;
        }
    }

    #[test]
    fn test_iter() {
        let mut list = List::new();
        list.push(1);
        list.push(2);
        list.push(3);
        let mut iter = list.iter();
        assert_eq!(Some(&3), iter.next());
        assert_eq!(Some(&2), iter.next());
        assert_eq!(Some(&1), iter.next());
        assert_eq!(None, iter.next());
        let mut i = 3;
        for val in &list {
            assert_eq!(i, *val);
            i -= 1;
        }
    }
}
<commit_msg>Added mutable iterator for linked-list representation.<commit_after>use std::iter::IntoIterator;

////////////////////////////////////////////////////////////////////////////////
// List implementation

pub struct List<T> {
    head: Link<T>,
}

type Link<T> = Option<Box<Node<T>>>;

struct Node<T> {
    elem: T,
    next: Link<T>,
}

impl<T> List<T> {
    fn new() -> Self {
        List { head: None }
    }

    // TODO: Figure out how to return self.
    fn push(&mut self, elem: T) {
        self.head = Some(Box::new(Node { elem: elem, next: self.head.take() }));
    }

    fn pop(&mut self) -> Option<T> {
        // Option<Box<Node<T>>>
        self.head.take().map(|node| { // Box<Node<T>>
            let node = *node;
            self.head = node.next;
            node.elem
        })
    }

    fn peek(&self) -> Option<&T> {
        self.head.as_ref().map(|node| { &node.elem })
    }

    fn peek_mut(&mut self) -> Option<&mut T> {
        self.head.as_mut().map(|node| { &mut node.elem })
    }

    fn iter(&self) -> Iter<T> {
        Iter { link: &self.head }
    }

    fn iter_mut(&mut self) -> IterMut<T> {
        IterMut { next: Some(&mut self.head) }
    }
}

////////////////////////////////////////////////////////////////////////////////
// By-reference Iter

pub struct Iter<'a, T: 'a> {
    link: &'a Link<T>,
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        self.link.as_ref().map(|node| {
            self.link = &node.next;
            &node.elem
        })
    }
}

////////////////////////////////////////////////////////////////////////////////
// Mutable by-reference Iter

// FAILED ATTEMPT
//pub struct IterMut<'a, T: 'a> {
//    link: &'a mut Link<T>,
//}
//
//impl<'a, T> Iterator for IterMut<'a, T> {
//    type Item = &'a mut T;
//
//    fn next(&mut self) -> Option<Self::Item> {
//        self.link.as_mut().take().map(|node| {
//            self.link = &mut node.next;
//            &mut node.elem
//        })
//    }
//}

// KEY INSIGHT in working implementation:
// * On iterator initialization, the iterator lifetime is 'a.
// * On #next(), the lifetime of the iterator needs to be independent of 'a for the iterator to be
//   usable past one invocation of next(). But this independent lifetime prevents it from returning
//   something with lifetime 'a UNLESS it stores something else that it owns (ie. that it can
//   modify) that contains a pointer with lifetime 'a.
//
// Much easier way to implement is Gankro's version
//   http://cglab.ca/~abeinges/blah/too-many-lists/book/second-iter-mut.html
// which stores Option<&'a Node> instead.

pub struct IterMut<'a, T: 'a> {
    next: Option<&'a mut Link<T>>,  // (Link<T> = Option<Box<Node<T>>>)
}

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        self.next.take().and_then(|link| {
            // link has type: &mut Link<T>  (Link<T> = Option<Box<Node<T>>>)
            link.as_mut().map(|node| {
                // Need to deref the box first so that rust can infer that we are mut-borrowing
                // disjoint fields of a struct. Without this line, both times, we would be
                // mut-borrowing the box directly, and boxes are opaque to the compiler. See
                // https://users.rust-lang.org/t/trouble-implementing-linked-list-mutable-iterator-variant-based-on-gankros-tutorial/2357
                // for more info.
                let node = &mut **node;
                self.next = Some(&mut node.next);
                &mut node.elem
            })
        })
    }
}

////////////////////////////////////////////////////////////////////////////////
// IntoIterator

pub struct ListIntoIterator<T> {
    list: List<T>,
}

impl<T> Iterator for ListIntoIterator<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        self.list.pop()
    }
}

impl<T> IntoIterator for List<T> {
    type Item = T;
    type IntoIter = ListIntoIterator<T>;

    fn into_iter(self) -> ListIntoIterator<T> {
        ListIntoIterator { list: self }
    }
}

impl<'a, T> IntoIterator for &'a List<T> {
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Iter<'a, T> {
        self.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut List<T> {
    type Item = &'a mut T;
    type IntoIter = IterMut<'a, T>;

    fn into_iter(self) -> IterMut<'a, T> {
        self.iter_mut()
    }
}

////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod test {
    use super::List;

    #[test]
    fn test_push_pop() {
        let mut list = List::new();
        list.push(1);
        assert_eq!(Some(&1), list.peek());
        list.push(2);
        assert_eq!(Some(&2), list.peek());
        list.push(3);
        assert_eq!(Some(&3), list.peek());
        assert_eq!(Some(3), list.pop());
        assert_eq!(Some(2), list.pop());
        assert_eq!(Some(1), list.pop());
        assert_eq!(None, list.pop());
    }

    #[test]
    fn test_into_iter() {
        let mut list = List::new();
        list.push(1);
        list.push(2);
        list.push(3);
        let mut i = 3;
        for val in list {
            assert_eq!(i, val);
            i -= 1;
        }
    }

    #[test]
    fn test_iter() {
        let mut list = List::new();
        list.push(1);
        list.push(2);
        list.push(3);
        let mut iter = list.iter();
        assert_eq!(Some(&3), iter.next());
        assert_eq!(Some(&2), iter.next());
        assert_eq!(Some(&1), iter.next());
        assert_eq!(None, iter.next());
        let mut i = 3;
        for val in &list {
            assert_eq!(i, *val);
            i -= 1;
        }
    }

    #[test]
    fn test_iter_mut() {
        let mut list = List::new();
        list.push(1);
        list.push(2);
        list.push(3);
        let mut i = 3;
        for val in list.iter_mut() {
            assert_eq!(i, *val);
            *val = 3 - i;
            i -= 1;
        }
        let mut i = 0;
        for val in &mut list {
            assert_eq!(i, *val);
            *val = 3 - i;
            i += 1;
        }
        let mut i = 3;
        for val in &list {
            assert_eq!(i, *val);
            i -= 1;
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::error::Error;
use std::result::Result as RResult;

use toml::{Table, Value};

use self::error::ParserErrorKind;
use self::error::ParserError;

pub mod error {
    use std::fmt::{Debug, Display, Formatter};
    use std::fmt;
    use std::error::Error;
    use toml;

    #[derive(Clone)]
    pub enum ParserErrorKind {
        TOMLParserErrors,
        MissingMainSection,
        MissingVersionInfo,
    }

    pub struct ParserError {
        kind: ParserErrorKind,
        cause: Option<Box<Error>>,
    }

    impl ParserError {

        pub fn new(k: ParserErrorKind, cause: Option<Box<Error>>) -> ParserError {
            ParserError {
                kind: k,
                cause: cause,
            }
        }

    }

    impl Debug for ParserError {

        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
            try!(write!(f, "{:?}", self.description()));
            Ok(())
        }

    }

    impl Display for ParserError {

        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
            try!(write!(f, "{}", self.description()));
            Ok(())
        }

    }

    impl Error for ParserError {

        fn description(&self) -> &str {
            match self.kind {
                ParserErrorKind::TOMLParserErrors   => "Several TOML-Parser-Errors",
                ParserErrorKind::MissingMainSection => "Missing main section",
                ParserErrorKind::MissingVersionInfo => "Missing version information in main section",
            }
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

/**
 * EntryHeader
 *
 * This is basically a wrapper around toml::Table which provides convenience to the user of the
 * librray.
 */
#[derive(Debug, Clone)]
pub struct EntryHeader {
    toml: Table,
}

pub type Result<V> = RResult<V, error::ParserError>;

/**
 * Wrapper type around file header (TOML) object
 */
impl EntryHeader {

    /**
     * Get a new header object with a already-filled toml table
     *
     * Default header values are inserted into the header object by default.
     */
    pub fn new() -> EntryHeader {
        EntryHeader {
            toml: BTreeMap::new(),
        }
    }

    /**
     * Get the table which lives in the background
     */
    pub fn toml(&self) -> &Table {
        &self.toml
    }

    pub fn parse(s: &str) -> Result<EntryHeader> {
        use toml::Parser;

        let mut parser = Parser::new(s);
        parser.parse()
            .ok_or(ParserError::new(ParserErrorKind::TOMLParserErrors, None))
            .and_then(|t| verify_header_consistency(t))
            .map(|t| {
                EntryHeader {
                    toml: t
                }
            })
    }

}

fn verify_header_consistency(t: Table) -> Result<Table> {
    if !has_main_section(&t) {
        Err(ParserError::new(ParserErrorKind::MissingMainSection, None))
    } else if !has_imag_version_in_main_section(&t) {
        Err(ParserError::new(ParserErrorKind::MissingVersionInfo, None))
    } else {
        Ok(t)
    }
}

fn has_main_section(t: &Table) -> bool {
    t.contains_key("imag") &&
        match t.get("imag") {
            Some(&Value::Table(_)) => true,
            Some(_)                => false,
            None                   => false,
        }
}

fn has_imag_version_in_main_section(t: &Table) -> bool {
    use semver::Version;

    match t.get("imag").unwrap() {
        &Value::Table(ref sec) => {
            sec.get("version")
                .and_then(|v| {
                    match v {
                        &Value::String(ref s) => {
                            Some(Version::parse(&s[..]).is_ok())
                        },
                        _                 => Some(false),
                    }
                })
                .unwrap_or(false)
        }
        _                  => false,
    }
}

#[cfg(test)]
mod test {
    use std::collections::BTreeMap;

    use toml::Value;

    #[test]
    fn test_imag_section() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Table(BTreeMap::new()));

        assert!(has_main_section(&map));
    }

    #[test]
    fn test_imag_invalid_section_type() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Boolean(false));

        assert!(!has_main_section(&map));
    }

    #[test]
    fn test_imag_abscent_main_section() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("not_imag".into(), Value::Boolean(false));

        assert!(!has_main_section(&map));
    }

    #[test]
    fn test_main_section_without_version() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Table(BTreeMap::new()));

        assert!(!has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_main_section_with_version() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        let mut sub = BTreeMap::new();
        sub.insert("version".into(), Value::String("0.0.0".into()));
        map.insert("imag".into(), Value::Table(sub));

        assert!(has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_main_section_with_version_in_wrong_type() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        let mut sub = BTreeMap::new();
        sub.insert("version".into(), Value::Boolean(false));
        map.insert("imag".into(), Value::Table(sub));

        assert!(!has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_verification_good() {
        use super::verify_header_consistency;

        let mut header = BTreeMap::new();
        let sub = {
            let mut sub = BTreeMap::new();
            sub.insert("version".into(), Value::String(String::from("0.0.0")));

            Value::Table(sub)
        };

        header.insert("imag".into(), sub);

        assert!(verify_header_consistency(header).is_ok());
    }

    #[test]
    fn test_verification_invalid_versionstring() {
        use super::verify_header_consistency;

        let mut header = BTreeMap::new();
        let sub = {
            let mut sub = BTreeMap::new();
            sub.insert("version".into(), Value::String(String::from("000")));

            Value::Table(sub)
        };

        header.insert("imag".into(), sub);

        assert!(!verify_header_consistency(header).is_ok());
    }

    #[test]
    fn test_verification_current_version() {
        use version;

        use super::verify_header_consistency;

        let mut header = BTreeMap::new();
        let sub = {
            let mut sub = BTreeMap::new();
            sub.insert("version".into(), Value::String(version!()));

            Value::Table(sub)
        };

        header.insert("imag".into(), sub);

        assert!(verify_header_consistency(header).is_ok());
    }
}

<commit_msg>Init the header with default values<commit_after>use std::collections::BTreeMap;
use std::error::Error;
use std::result::Result as RResult;

use toml::{Array, Table, Value};
use version;

use self::error::ParserErrorKind;
use self::error::ParserError;

pub mod error {
    use std::fmt::{Debug, Display, Formatter};
    use std::fmt;
    use std::error::Error;
    use toml;

    #[derive(Clone)]
    pub enum ParserErrorKind {
        TOMLParserErrors,
        MissingMainSection,
        MissingVersionInfo,
    }

    pub struct ParserError {
        kind: ParserErrorKind,
        cause: Option<Box<Error>>,
    }

    impl ParserError {

        pub fn new(k: ParserErrorKind, cause: Option<Box<Error>>) -> ParserError {
            ParserError {
                kind: k,
                cause: cause,
            }
        }

    }

    impl Debug for ParserError {

        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
            try!(write!(f, "{:?}", self.description()));
            Ok(())
        }

    }

    impl Display for ParserError {

        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
            try!(write!(f, "{}", self.description()));
            Ok(())
        }

    }

    impl Error for ParserError {

        fn description(&self) -> &str {
            match self.kind {
                ParserErrorKind::TOMLParserErrors   => "Several TOML-Parser-Errors",
                ParserErrorKind::MissingMainSection => "Missing main section",
                ParserErrorKind::MissingVersionInfo => "Missing version information in main section",
            }
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

/**
 * EntryHeader
 *
 * This is basically a wrapper around toml::Table which provides convenience to the user of the
 * librray.
 */
#[derive(Debug, Clone)]
pub struct EntryHeader {
    toml: Table,
}

pub type Result<V> = RResult<V, error::ParserError>;

/**
 * Wrapper type around file header (TOML) object
 */
impl EntryHeader {

    /**
     * Get a new header object with a already-filled toml table
     *
     * Default header values are inserted into the header object by default.
     */
    pub fn new() -> EntryHeader {
        EntryHeader {
            toml: build_default_header(),
        }
    }

    /**
     * Get the table which lives in the background
     */
    pub fn toml(&self) -> &Table {
        &self.toml
    }

    pub fn parse(s: &str) -> Result<EntryHeader> {
        use toml::Parser;

        let mut parser = Parser::new(s);
        parser.parse()
            .ok_or(ParserError::new(ParserErrorKind::TOMLParserErrors, None))
            .and_then(|t| verify_header_consistency(t))
            .map(|t| {
                EntryHeader {
                    toml: t
                }
            })
    }

}

fn verify_header_consistency(t: Table) -> Result<Table> {
    if !has_main_section(&t) {
        Err(ParserError::new(ParserErrorKind::MissingMainSection, None))
    } else if !has_imag_version_in_main_section(&t) {
        Err(ParserError::new(ParserErrorKind::MissingVersionInfo, None))
    } else {
        Ok(t)
    }
}

fn has_main_section(t: &Table) -> bool {
    t.contains_key("imag") &&
        match t.get("imag") {
            Some(&Value::Table(_)) => true,
            Some(_)                => false,
            None                   => false,
        }
}

fn has_imag_version_in_main_section(t: &Table) -> bool {
    use semver::Version;

    match t.get("imag").unwrap() {
        &Value::Table(ref sec) => {
            sec.get("version")
                .and_then(|v| {
                    match v {
                        &Value::String(ref s) => {
                            Some(Version::parse(&s[..]).is_ok())
                        },
                        _                 => Some(false),
                    }
                })
                .unwrap_or(false)
        }
        _                  => false,
    }
}

#[cfg(test)]
mod test {
    use std::collections::BTreeMap;

    use toml::Value;

    #[test]
    fn test_imag_section() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Table(BTreeMap::new()));

        assert!(has_main_section(&map));
    }

    #[test]
    fn test_imag_invalid_section_type() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Boolean(false));

        assert!(!has_main_section(&map));
    }

    #[test]
    fn test_imag_abscent_main_section() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("not_imag".into(), Value::Boolean(false));

        assert!(!has_main_section(&map));
    }

    #[test]
    fn test_main_section_without_version() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Table(BTreeMap::new()));

        assert!(!has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_main_section_with_version() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        let mut sub = BTreeMap::new();
        sub.insert("version".into(), Value::String("0.0.0".into()));
        map.insert("imag".into(), Value::Table(sub));

        assert!(has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_main_section_with_version_in_wrong_type() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        let mut sub = BTreeMap::new();
        sub.insert("version".into(), Value::Boolean(false));
        map.insert("imag".into(), Value::Table(sub));

        assert!(!has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_verification_good() {
        use super::verify_header_consistency;

        let mut header = BTreeMap::new();
        let sub = {
            let mut sub = BTreeMap::new();
            sub.insert("version".into(), Value::String(String::from("0.0.0")));

            Value::Table(sub)
        };

        header.insert("imag".into(), sub);

        assert!(verify_header_consistency(header).is_ok());
    }

    #[test]
    fn test_verification_invalid_versionstring() {
        use super::verify_header_consistency;

        let mut header = BTreeMap::new();
        let sub = {
            let mut sub = BTreeMap::new();
            sub.insert("version".into(), Value::String(String::from("000")));

            Value::Table(sub)
        };

        header.insert("imag".into(), sub);

        assert!(!verify_header_consistency(header).is_ok());
    }

    #[test]
    fn test_verification_current_version() {
        use version;

        use super::verify_header_consistency;

        let mut header = BTreeMap::new();
        let sub = {
            let mut sub = BTreeMap::new();
            sub.insert("version".into(), Value::String(version!()));

            Value::Table(sub)
        };

        header.insert("imag".into(), sub);

        assert!(verify_header_consistency(header).is_ok());
    }
}

fn build_default_header() -> BTreeMap<String, Value> {
    let mut m = BTreeMap::new();

    m.insert(String::from("imag"), {
        let mut imag_map = BTreeMap::<String, Value>::new();

        imag_map.insert(String::from("version"), Value::String(version!()));
        imag_map.insert(String::from("links"), Value::Array(vec![]));

        Value::Table(imag_map)
    });

    m
}

<|endoftext|>


<commit_before>#![feature(backtrace)]

mod as_dyn_error;
mod context;
mod error;

#[cfg(not(feature = "std"))]
compile_error!("no_std support is not implemented yet");

pub use crate::as_dyn_error::AsDynError;
pub use crate::context::Context;
pub use crate::error::{Chain, Error};

/// `Result<T, Error>`
pub type Result<T> = std::result::Result<T, Error>;

/// Return early with an error.
///
/// This macro is equivalent to `return Err(From::from($err))`.
#[macro_export]
macro_rules! bail {
    ($err:expr) => {
        return std::result::Result::Err(std::convert::From::from($err));
    };
}

/// Construct an ad-hoc error from a string.
///
/// This evaluates to an `Error`. It can take either just a string, or a format
/// string with arguments. It also can take any custom type which implements
/// `Debug` and `Display`.
#[macro_export]
macro_rules! anyhow {
    ($e:expr)   => { $crate::Error::new_adhoc($e) };
    ($($arg:tt)*) => { $crate::Error::new_adhoc(format!($($arg)*)) };
}
<commit_msg>Accept trailing comma in macros<commit_after>#![feature(backtrace)]

mod as_dyn_error;
mod context;
mod error;

#[cfg(not(feature = "std"))]
compile_error!("no_std support is not implemented yet");

pub use crate::as_dyn_error::AsDynError;
pub use crate::context::Context;
pub use crate::error::{Chain, Error};

/// `Result<T, Error>`
pub type Result<T> = std::result::Result<T, Error>;

/// Return early with an error.
///
/// This macro is equivalent to `return Err(From::from($err))`.
#[macro_export]
macro_rules! bail {
    ($err:expr) => {
        return std::result::Result::Err(std::convert::From::from($err));
    };
    ($err:expr,) => {
        $crate::bail!($err);
    };
}

/// Construct an ad-hoc error from a string.
///
/// This evaluates to an `Error`. It can take either just a string, or a format
/// string with arguments. It also can take any custom type which implements
/// `Debug` and `Display`.
#[macro_export]
macro_rules! anyhow {
    ($msg:expr) => {
        $crate::Error::new_adhoc($msg)
    };
    ($msg:expr,) => {
        $crate::anyhow!($msg)
    };
    ($fmt:expr, $($arg:tt)*) => {
        $crate::Error::new_adhoc(format!($fmt, $($arg)*))
    };
}
<|endoftext|>