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

use std::fmt;
use std::io::Write;
use std::mem;

use syn;

use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::ir::{
    AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path,
    ToCondition, Type,
};
use bindgen::writer::{Source, SourceWriter};

#[derive(Debug, Clone)]
pub enum Literal {
    Expr(String),
    Struct {
        name: String,
        export_name: String,
        fields: Vec<(String, Literal)>,
    },
}

impl fmt::Display for Literal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Literal::Expr(v) => write!(f, "{}", v),
            Literal::Struct {
                name: _,
                export_name,
                fields,
            } => write!(
                f,
                "({}){{ {} }}",
                export_name,
                fields
                    .iter()
                    .map(|(key, lit)| format!(".{} = {}", key, lit))
                    .collect::<Vec<String>>()
                    .join(", "),
            ),
        }
    }
}

impl Literal {
    pub fn rename_for_config(&mut self, config: &Config) {
        match self {
            Literal::Struct {
                name: _,
                ref mut export_name,
                fields,
            } => {
                config.export.rename(export_name);
                for (_, lit) in fields {
                    lit.rename_for_config(config);
                }
            }
            Literal::Expr(_) => {}
        }
    }

    pub fn load(expr: &syn::Expr) -> Result<Literal, String> {
        match expr {
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Str(ref value),
                ..
            }) => Ok(Literal::Expr(format!("u8\"{}\"", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Byte(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Char(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Int(ref value),
                ..
            }) => match value.suffix() {
                syn::IntSuffix::Usize
                | syn::IntSuffix::U8
                | syn::IntSuffix::U16
                | syn::IntSuffix::U32
                | syn::IntSuffix::U64
                | syn::IntSuffix::U128
                | syn::IntSuffix::None => Ok(Literal::Expr(format!("{}", value.value()))),
                syn::IntSuffix::Isize
                | syn::IntSuffix::I8
                | syn::IntSuffix::I16
                | syn::IntSuffix::I32
                | syn::IntSuffix::I64
                | syn::IntSuffix::I128 => unsafe {
                    Ok(Literal::Expr(format!(
                        "{}",
                        mem::transmute::<u64, i64>(value.value())
                    )))
                },
            },
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Float(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Bool(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value))),

            &syn::Expr::Struct(syn::ExprStruct {
                ref path,
                ref fields,
                ..
            }) => {
                let struct_name = path.segments[0].ident.to_string();
                let mut field_pairs: Vec<(String, Literal)> = Vec::new();
                for field in fields {
                    let ident = match field.member {
                        syn::Member::Named(ref name) => name.to_string(),
                        syn::Member::Unnamed(ref index) => format!("_{}", index.index),
                    };
                    let key = ident.to_string();
                    let value = Literal::load(&field.expr)?;
                    field_pairs.push((key, value));
                }
                Ok(Literal::Struct {
                    name: struct_name.clone(),
                    export_name: struct_name,
                    fields: field_pairs,
                })
            }
            _ => Err("Unsupported literal expression.".to_owned()),
        }
    }
}

#[derive(Debug, Clone)]
pub struct Constant {
    pub path: Path,
    pub export_name: String,
    pub ty: Type,
    pub value: Literal,
    pub cfg: Option<Cfg>,
    pub annotations: AnnotationSet,
    pub documentation: Documentation,
}

impl Constant {
    pub fn load(
        path: Path,
        item: &syn::ItemConst,
        mod_cfg: &Option<Cfg>,
    ) -> Result<Constant, String> {
        let ty = Type::load(&item.ty)?;

        if ty.is_none() {
            return Err("Cannot have a zero sized const definition.".to_owned());
        }

        let ty = ty.unwrap();

        if !ty.is_primitive_or_ptr_primitive()
            && match *item.expr {
                syn::Expr::Struct(_) => false,
                _ => true,
            }
        {
            return Err("Unhanded const definition".to_owned());
        }

        Ok(Constant::new(
            path,
            ty,
            Literal::load(&item.expr)?,
            Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            AnnotationSet::load(&item.attrs)?,
            Documentation::load(&item.attrs),
        ))
    }

    pub fn load_assoc(
        name: String,
        item: &syn::ImplItemConst,
        mod_cfg: &Option<Cfg>,
        is_transparent: bool,
        struct_path: &Path,
    ) -> Result<Constant, String> {
        let ty = Type::load(&item.ty)?;

        if ty.is_none() {
            return Err("Cannot have a zero sized const definition.".to_owned());
        }
        let ty = ty.unwrap();

        let can_handle_const_expr = match item.expr {
            syn::Expr::Struct(_) => true,
            _ => false,
        };

        if !ty.is_primitive_or_ptr_primitive() && !can_handle_const_expr {
            return Err("Unhandled const definition".to_owned());
        }

        let expr = Literal::load(match item.expr {
            syn::Expr::Struct(syn::ExprStruct { ref fields, .. }) => {
                if is_transparent && fields.len() == 1 {
                    &fields[0].expr
                } else {
                    &item.expr
                }
            }
            _ => &item.expr,
        })?;

        let full_name = Path::new(format!("{}_{}", struct_path, name));

        Ok(Constant::new(
            full_name,
            ty,
            expr,
            Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            AnnotationSet::load(&item.attrs)?,
            Documentation::load(&item.attrs),
        ))
    }

    pub fn new(
        path: Path,
        ty: Type,
        value: Literal,
        cfg: Option<Cfg>,
        annotations: AnnotationSet,
        documentation: Documentation,
    ) -> Self {
        let export_name = path.name().to_owned();
        Self {
            path,
            export_name,
            ty,
            value,
            cfg,
            annotations,
            documentation,
        }
    }
}

impl Item for Constant {
    fn path(&self) -> &Path {
        &self.path
    }

    fn export_name(&self) -> &str {
        &self.export_name
    }

    fn cfg(&self) -> &Option<Cfg> {
        &self.cfg
    }

    fn annotations(&self) -> &AnnotationSet {
        &self.annotations
    }

    fn annotations_mut(&mut self) -> &mut AnnotationSet {
        &mut self.annotations
    }

    fn container(&self) -> ItemContainer {
        ItemContainer::Constant(self.clone())
    }

    fn rename_for_config(&mut self, config: &Config) {
        config.export.rename(&mut self.export_name);
        self.value.rename_for_config(config);
        self.ty.rename_for_config(config, &GenericParams::default()); // FIXME: should probably propagate something here
    }

    fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
        self.ty.resolve_declaration_types(resolver);
    }
}

impl Source for Constant {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        let condition = (&self.cfg).to_condition(config);
        condition.write_before(config, out);
        if config.constant.allow_static_const && config.language == Language::Cxx {
            if let Type::ConstPtr(..) = self.ty {
                out.write("static ");
            } else {
                out.write("static const ");
            }
            self.ty.write(config, out);
            write!(out, " {} = {};", self.export_name(), self.value)
        } else {
            write!(out, "#define {} {}", self.export_name(), self.value)
        }
        condition.write_after(config, out);
    }
}
<commit_msg>Cleanup matching in Literal::load.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fmt;
use std::io::Write;
use std::mem;

use syn;

use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::ir::{
    AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path,
    ToCondition, Type,
};
use bindgen::writer::{Source, SourceWriter};

#[derive(Debug, Clone)]
pub enum Literal {
    Expr(String),
    Struct {
        name: String,
        export_name: String,
        fields: Vec<(String, Literal)>,
    },
}

impl fmt::Display for Literal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Literal::Expr(v) => write!(f, "{}", v),
            Literal::Struct {
                name: _,
                export_name,
                fields,
            } => write!(
                f,
                "({}){{ {} }}",
                export_name,
                fields
                    .iter()
                    .map(|(key, lit)| format!(".{} = {}", key, lit))
                    .collect::<Vec<String>>()
                    .join(", "),
            ),
        }
    }
}

impl Literal {
    pub fn rename_for_config(&mut self, config: &Config) {
        match self {
            Literal::Struct {
                name: _,
                ref mut export_name,
                fields,
            } => {
                config.export.rename(export_name);
                for (_, lit) in fields {
                    lit.rename_for_config(config);
                }
            }
            Literal::Expr(_) => {}
        }
    }

    pub fn load(expr: &syn::Expr) -> Result<Literal, String> {
        match *expr {
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Str(ref value),
                ..
            }) => Ok(Literal::Expr(format!("u8\"{}\"", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Byte(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Char(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Int(ref value),
                ..
            }) => match value.suffix() {
                syn::IntSuffix::Usize
                | syn::IntSuffix::U8
                | syn::IntSuffix::U16
                | syn::IntSuffix::U32
                | syn::IntSuffix::U64
                | syn::IntSuffix::U128
                | syn::IntSuffix::None => Ok(Literal::Expr(format!("{}", value.value()))),
                syn::IntSuffix::Isize
                | syn::IntSuffix::I8
                | syn::IntSuffix::I16
                | syn::IntSuffix::I32
                | syn::IntSuffix::I64
                | syn::IntSuffix::I128 => unsafe {
                    Ok(Literal::Expr(format!(
                        "{}",
                        mem::transmute::<u64, i64>(value.value())
                    )))
                },
            },
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Float(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Bool(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value))),

            syn::Expr::Struct(syn::ExprStruct {
                ref path,
                ref fields,
                ..
            }) => {
                let struct_name = path.segments[0].ident.to_string();
                let mut field_pairs: Vec<(String, Literal)> = Vec::new();
                for field in fields {
                    let ident = match field.member {
                        syn::Member::Named(ref name) => name.to_string(),
                        syn::Member::Unnamed(ref index) => format!("_{}", index.index),
                    };
                    let key = ident.to_string();
                    let value = Literal::load(&field.expr)?;
                    field_pairs.push((key, value));
                }
                Ok(Literal::Struct {
                    name: struct_name.clone(),
                    export_name: struct_name,
                    fields: field_pairs,
                })
            }
            _ => Err("Unsupported literal expression.".to_owned()),
        }
    }
}

#[derive(Debug, Clone)]
pub struct Constant {
    pub path: Path,
    pub export_name: String,
    pub ty: Type,
    pub value: Literal,
    pub cfg: Option<Cfg>,
    pub annotations: AnnotationSet,
    pub documentation: Documentation,
}

impl Constant {
    pub fn load(
        path: Path,
        item: &syn::ItemConst,
        mod_cfg: &Option<Cfg>,
    ) -> Result<Constant, String> {
        let ty = Type::load(&item.ty)?;

        if ty.is_none() {
            return Err("Cannot have a zero sized const definition.".to_owned());
        }

        let ty = ty.unwrap();

        if !ty.is_primitive_or_ptr_primitive()
            && match *item.expr {
                syn::Expr::Struct(_) => false,
                _ => true,
            }
        {
            return Err("Unhanded const definition".to_owned());
        }

        Ok(Constant::new(
            path,
            ty,
            Literal::load(&item.expr)?,
            Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            AnnotationSet::load(&item.attrs)?,
            Documentation::load(&item.attrs),
        ))
    }

    pub fn load_assoc(
        name: String,
        item: &syn::ImplItemConst,
        mod_cfg: &Option<Cfg>,
        is_transparent: bool,
        struct_path: &Path,
    ) -> Result<Constant, String> {
        let ty = Type::load(&item.ty)?;

        if ty.is_none() {
            return Err("Cannot have a zero sized const definition.".to_owned());
        }
        let ty = ty.unwrap();

        let can_handle_const_expr = match item.expr {
            syn::Expr::Struct(_) => true,
            _ => false,
        };

        if !ty.is_primitive_or_ptr_primitive() && !can_handle_const_expr {
            return Err("Unhandled const definition".to_owned());
        }

        let expr = Literal::load(match item.expr {
            syn::Expr::Struct(syn::ExprStruct { ref fields, .. }) => {
                if is_transparent && fields.len() == 1 {
                    &fields[0].expr
                } else {
                    &item.expr
                }
            }
            _ => &item.expr,
        })?;

        let full_name = Path::new(format!("{}_{}", struct_path, name));

        Ok(Constant::new(
            full_name,
            ty,
            expr,
            Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            AnnotationSet::load(&item.attrs)?,
            Documentation::load(&item.attrs),
        ))
    }

    pub fn new(
        path: Path,
        ty: Type,
        value: Literal,
        cfg: Option<Cfg>,
        annotations: AnnotationSet,
        documentation: Documentation,
    ) -> Self {
        let export_name = path.name().to_owned();
        Self {
            path,
            export_name,
            ty,
            value,
            cfg,
            annotations,
            documentation,
        }
    }
}

impl Item for Constant {
    fn path(&self) -> &Path {
        &self.path
    }

    fn export_name(&self) -> &str {
        &self.export_name
    }

    fn cfg(&self) -> &Option<Cfg> {
        &self.cfg
    }

    fn annotations(&self) -> &AnnotationSet {
        &self.annotations
    }

    fn annotations_mut(&mut self) -> &mut AnnotationSet {
        &mut self.annotations
    }

    fn container(&self) -> ItemContainer {
        ItemContainer::Constant(self.clone())
    }

    fn rename_for_config(&mut self, config: &Config) {
        config.export.rename(&mut self.export_name);
        self.value.rename_for_config(config);
        self.ty.rename_for_config(config, &GenericParams::default()); // FIXME: should probably propagate something here
    }

    fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
        self.ty.resolve_declaration_types(resolver);
    }
}

impl Source for Constant {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        let condition = (&self.cfg).to_condition(config);
        condition.write_before(config, out);
        if config.constant.allow_static_const && config.language == Language::Cxx {
            if let Type::ConstPtr(..) = self.ty {
                out.write("static ");
            } else {
                out.write("static const ");
            }
            self.ty.write(config, out);
            write!(out, " {} = {};", self.export_name(), self.value)
        } else {
            write!(out, "#define {} {}", self.export_name(), self.value)
        }
        condition.write_after(config, out);
    }
}
<|endoftext|>


<commit_before>use std::sync::{Arc,Mutex};
use std::collections::HashMap;
use std::io::BufReader;
use webpki;
use rustls::{ResolvesServerCert, SignatureScheme};
use rustls::sign::{CertifiedKey, RSASigningKey};
use rustls::internal::pemfile;

use sozu_command::proxy::{CertificateAndKey, CertFingerprint, AddCertificate, RemoveCertificate};
use sozu_command::certificate::calculate_fingerprint_from_der;

use trie::TrieNode;

struct TlsData {
  pub cert:     CertifiedKey,
}

pub struct CertificateResolver {
  pub domains:  TrieNode<CertFingerprint>,
  certificates: HashMap<CertFingerprint, TlsData>,
}

impl CertificateResolver {
  pub fn new() -> CertificateResolver {
    CertificateResolver {
      domains:      TrieNode::root(),
      certificates: HashMap::new(),
    }
  }

  pub fn add_certificate(&mut self, add_certificate: AddCertificate) -> Option<CertFingerprint> {
    if let Some(certified_key) = generate_certified_key(add_certificate.certificate) {
      let fingerprint = calculate_fingerprint_from_der(&certified_key.cert[0].0);
      if add_certificate.names.is_empty() {
        //FIXME: waiting for https://github.com/briansmith/webpki/pull/65 to merge to get the DNS names
        // create a untrusted::Input
        // let input = untrusted::Input::from(&certs[0].0);
        // create an EndEntityCert
        // let ee = webpki::EndEntityCert::from(input).unwrap()
        // get names
        // let dns_names = ee.list_dns_names()
        // names.extend(dns_names.drain(..).map(|name| name.to_String()));
        error!("the rustls proxy cannot extract the names from the certificate (fingerprint={:?})", fingerprint);
        return None;
      }

      let mut names = add_certificate.names;
      //info!("cert fingerprint: {:?}", fingerprint);

      let data = TlsData {
        cert:     certified_key,
      };

      let fingerprint = CertFingerprint(fingerprint);
      self.certificates.insert(fingerprint.clone(), data);
      for name in names.drain(..) {
        self.domains.domain_insert(name.into_bytes(), fingerprint.clone());
      }

      Some(fingerprint)
    } else {
      None
    }
  }

  pub fn remove_certificate(&mut self, remove_certificate: RemoveCertificate) {
    if let Some(_data) = self.certificates.get(&remove_certificate.fingerprint) {
      //let cert = &data.cert.cert[0];
      if remove_certificate.names.is_empty() {
        //FIXME: waiting for https://github.com/briansmith/webpki/pull/65 to merge to get the DNS names
        // create a untrusted::Input
        // let input = untrusted::Input::from(&certs[0].0);
        // create an EndEntityCert
        // let ee = webpki::EndEntityCert::from(input).unwrap()
        // get names
        // let dns_names = ee.list_dns_names()
        // names.extend(dns_names.drain(..).map(|name| name.to_String()));
        unimplemented!("the rustls proxy cannot extract the names from the certificate");
      }

      let names = remove_certificate.names;

      for name in names {
        self.domains.domain_remove(&name.into_bytes());
      }
    }

    self.certificates.remove(&remove_certificate.fingerprint);
  }
}

pub struct CertificateResolverWrapper(pub Mutex<CertificateResolver>);

impl CertificateResolverWrapper {
  pub fn new() -> CertificateResolverWrapper {
    CertificateResolverWrapper(Mutex::new(CertificateResolver::new()))
  }

  pub fn add_certificate(&self, add_certificate: AddCertificate) -> Option<CertFingerprint> {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.add_certificate(add_certificate)
    } else {
      None
    }
  }

  pub fn remove_certificate(&self, remove_certificate: RemoveCertificate) {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.remove_certificate(remove_certificate)
    }

  }
}

impl ResolvesServerCert for CertificateResolverWrapper {
  fn resolve(
        &self,
        server_name: Option<webpki::DNSNameRef>,
        sigschemes: &[SignatureScheme]
    ) -> Option<CertifiedKey> {
    if server_name.is_none() {
      error!("cannot look up certificate: no SNI from session");
      return None;
    }
    let name: &str = server_name.unwrap().into();

    trace!("trying to resolve name: {:?} for signature scheme: {:?}", name, sigschemes);
    if let Ok(ref mut resolver) = self.0.try_lock() {
      //resolver.domains.print();
      if let Some(kv) = resolver.domains.domain_lookup(name.as_bytes(), true) {
         trace!("looking for certificate for {:?} with fingerprint {:?}", name, kv.1);
         return resolver.certificates.get(&kv.1).as_ref().map(|data| data.cert.clone());
      }
    }

    error!("could not look up a certificate for server name '{}'", name);
    None
  }
}

pub fn generate_certified_key(certificate_and_key: CertificateAndKey) -> Option<CertifiedKey> {
  let mut chain = Vec::new();

  let mut cert_reader = BufReader::new(certificate_and_key.certificate.as_bytes());
  let parsed_certs = pemfile::certs(&mut cert_reader);

  if let Ok(certs) = parsed_certs {
    for cert in certs {
      chain.push(cert);
    }
  } else {
    return None;
  }

  for ref cert in certificate_and_key.certificate_chain.iter() {
    let mut chain_cert_reader = BufReader::new(cert.as_bytes());
    if let Ok(parsed_chain_certs) = pemfile::certs(&mut chain_cert_reader) {
      for cert in parsed_chain_certs {
        chain.push(cert);
      }
    }
  }

  let mut key_reader = BufReader::new(certificate_and_key.key.as_bytes());
  let parsed_key = pemfile::rsa_private_keys(&mut key_reader);

  if let Ok(keys) = parsed_key {
    if !keys.is_empty() {
      if let Ok(signing_key) = RSASigningKey::new(&keys[0]) {
        let certified = CertifiedKey::new(chain, Arc::new(Box::new(signing_key)));
        return Some(certified);
      }
    } else {
      let mut key_reader = BufReader::new(certificate_and_key.key.as_bytes());
      let parsed_key = pemfile::pkcs8_private_keys(&mut key_reader);
      if let Ok(keys) = parsed_key {
        if !keys.is_empty() {
          if let Ok(signing_key) = RSASigningKey::new(&keys[0]) {
            let certified = CertifiedKey::new(chain, Arc::new(Box::new(signing_key)));
            return Some(certified);
          }
        }
      }
    }
  } else {
    error!("could not parse private key: {:?}", parsed_key);
  }

  None
}
<commit_msg>allow ECDSA keys in rustls<commit_after>use std::sync::{Arc,Mutex};
use std::collections::HashMap;
use std::io::BufReader;
use webpki;
use rustls::{ResolvesServerCert, SignatureScheme};
use rustls::sign::{CertifiedKey, RSASigningKey};
use rustls::internal::pemfile;

use sozu_command::proxy::{CertificateAndKey, CertFingerprint, AddCertificate, RemoveCertificate};
use sozu_command::certificate::calculate_fingerprint_from_der;

use trie::TrieNode;

struct TlsData {
  pub cert:     CertifiedKey,
}

pub struct CertificateResolver {
  pub domains:  TrieNode<CertFingerprint>,
  certificates: HashMap<CertFingerprint, TlsData>,
}

impl CertificateResolver {
  pub fn new() -> CertificateResolver {
    CertificateResolver {
      domains:      TrieNode::root(),
      certificates: HashMap::new(),
    }
  }

  pub fn add_certificate(&mut self, add_certificate: AddCertificate) -> Option<CertFingerprint> {
    if let Some(certified_key) = generate_certified_key(add_certificate.certificate) {
      let fingerprint = calculate_fingerprint_from_der(&certified_key.cert[0].0);
      if add_certificate.names.is_empty() {
        //FIXME: waiting for https://github.com/briansmith/webpki/pull/65 to merge to get the DNS names
        // create a untrusted::Input
        // let input = untrusted::Input::from(&certs[0].0);
        // create an EndEntityCert
        // let ee = webpki::EndEntityCert::from(input).unwrap()
        // get names
        // let dns_names = ee.list_dns_names()
        // names.extend(dns_names.drain(..).map(|name| name.to_String()));
        error!("the rustls proxy cannot extract the names from the certificate (fingerprint={:?})", fingerprint);
        return None;
      }

      let mut names = add_certificate.names;
      //info!("cert fingerprint: {:?}", fingerprint);

      let data = TlsData {
        cert:     certified_key,
      };

      let fingerprint = CertFingerprint(fingerprint);
      self.certificates.insert(fingerprint.clone(), data);
      for name in names.drain(..) {
        self.domains.domain_insert(name.into_bytes(), fingerprint.clone());
      }

      Some(fingerprint)
    } else {
      None
    }
  }

  pub fn remove_certificate(&mut self, remove_certificate: RemoveCertificate) {
    if let Some(_data) = self.certificates.get(&remove_certificate.fingerprint) {
      //let cert = &data.cert.cert[0];
      if remove_certificate.names.is_empty() {
        //FIXME: waiting for https://github.com/briansmith/webpki/pull/65 to merge to get the DNS names
        // create a untrusted::Input
        // let input = untrusted::Input::from(&certs[0].0);
        // create an EndEntityCert
        // let ee = webpki::EndEntityCert::from(input).unwrap()
        // get names
        // let dns_names = ee.list_dns_names()
        // names.extend(dns_names.drain(..).map(|name| name.to_String()));
        unimplemented!("the rustls proxy cannot extract the names from the certificate");
      }

      let names = remove_certificate.names;

      for name in names {
        self.domains.domain_remove(&name.into_bytes());
      }
    }

    self.certificates.remove(&remove_certificate.fingerprint);
  }
}

pub struct CertificateResolverWrapper(pub Mutex<CertificateResolver>);

impl CertificateResolverWrapper {
  pub fn new() -> CertificateResolverWrapper {
    CertificateResolverWrapper(Mutex::new(CertificateResolver::new()))
  }

  pub fn add_certificate(&self, add_certificate: AddCertificate) -> Option<CertFingerprint> {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.add_certificate(add_certificate)
    } else {
      None
    }
  }

  pub fn remove_certificate(&self, remove_certificate: RemoveCertificate) {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.remove_certificate(remove_certificate)
    }

  }
}

impl ResolvesServerCert for CertificateResolverWrapper {
  fn resolve(
        &self,
        server_name: Option<webpki::DNSNameRef>,
        sigschemes: &[SignatureScheme]
    ) -> Option<CertifiedKey> {
    if server_name.is_none() {
      error!("cannot look up certificate: no SNI from session");
      return None;
    }
    let name: &str = server_name.unwrap().into();

    trace!("trying to resolve name: {:?} for signature scheme: {:?}", name, sigschemes);
    if let Ok(ref mut resolver) = self.0.try_lock() {
      //resolver.domains.print();
      if let Some(kv) = resolver.domains.domain_lookup(name.as_bytes(), true) {
         trace!("looking for certificate for {:?} with fingerprint {:?}", name, kv.1);
         return resolver.certificates.get(&kv.1).as_ref().map(|data| data.cert.clone());
      }
    }

    error!("could not look up a certificate for server name '{}'", name);
    None
  }
}

pub fn generate_certified_key(certificate_and_key: CertificateAndKey) -> Option<CertifiedKey> {
  let mut chain = Vec::new();

  let mut cert_reader = BufReader::new(certificate_and_key.certificate.as_bytes());
  let parsed_certs = pemfile::certs(&mut cert_reader);

  if let Ok(certs) = parsed_certs {
    for cert in certs {
      chain.push(cert);
    }
  } else {
    return None;
  }

  for ref cert in certificate_and_key.certificate_chain.iter() {
    let mut chain_cert_reader = BufReader::new(cert.as_bytes());
    if let Ok(parsed_chain_certs) = pemfile::certs(&mut chain_cert_reader) {
      for cert in parsed_chain_certs {
        chain.push(cert);
      }
    }
  }

  let mut key_reader = BufReader::new(certificate_and_key.key.as_bytes());
  let parsed_key = pemfile::rsa_private_keys(&mut key_reader);

  if let Ok(keys) = parsed_key {
    if !keys.is_empty() {
      if let Ok(signing_key) = RSASigningKey::new(&keys[0]) {
        let certified = CertifiedKey::new(chain, Arc::new(Box::new(signing_key)));
        return Some(certified);
      } else {
          if let Ok(k) = rustls::sign::any_ecdsa_type(&keys[0]) {
              let certified = CertifiedKey::new(chain, Arc::new(k));
              return Some(certified);
          } else {
              error!("could not decode signing key (tried RSA and ECDSA)");
          }
      }
    } else {
      let mut key_reader = BufReader::new(certificate_and_key.key.as_bytes());
      let parsed_key = pemfile::pkcs8_private_keys(&mut key_reader);
      if let Ok(keys) = parsed_key {
        if !keys.is_empty() {
          if let Ok(signing_key) = RSASigningKey::new(&keys[0]) {
            let certified = CertifiedKey::new(chain, Arc::new(Box::new(signing_key)));
            return Some(certified);
          }
        }
      }
    }
  } else {
    error!("could not parse private key: {:?}", parsed_key);
  }

  None
}
<|endoftext|>


<commit_before>use ordermap::OrderMap;
use std::hash::Hash;

use parser::Spanning;
use ast::{InputValue, ToInputValue};

/// Serializable value returned from query and field execution.
///
/// Used by the execution engine and resolvers to build up the response
/// structure. Similar to the `Json` type found in the serialize crate.
///
/// It is also similar to the `InputValue` type, but can not contain enum
/// values or variables. Also, lists and objects do not contain any location
/// information since they are generated by resolving fields and values rather
/// than parsing a source query.
#[derive(Debug, PartialEq)]
#[allow(missing_docs)]
pub enum Value {
    Null,
    Int(i32),
    Float(f64),
    String(String),
    Boolean(bool),
    List(Vec<Value>),
    Object(OrderMap<String, Value>),
}

impl Value {
    // CONSTRUCTORS

    /// Construct a null value.
    pub fn null() -> Value {
        Value::Null
    }

    /// Construct an integer value.
    pub fn int(i: i32) -> Value {
        Value::Int(i)
    }

    /// Construct a floating point value.
    pub fn float(f: f64) -> Value {
        Value::Float(f)
    }

    /// Construct a string value.
    pub fn string<T: AsRef<str>>(s: T) -> Value {
        Value::String(s.as_ref().to_owned())
    }

    /// Construct a boolean value.
    pub fn boolean(b: bool) -> Value {
        Value::Boolean(b)
    }

    /// Construct a list value.
    pub fn list(l: Vec<Value>) -> Value {
        Value::List(l)
    }

    /// Construct an object value.
    pub fn object<K>(o: OrderMap<K, Value>) -> Value
    where
        K: Into<String> + Eq + Hash,
    {
        Value::Object(o.into_iter().map(|(k, v)| (k.into(), v)).collect())
    }

    // DISCRIMINATORS

    /// Does this value represent null?
    pub fn is_null(&self) -> bool {
        match *self {
            Value::Null => true,
            _ => false,
        }
    }

    /// View the underlying float value, if present.
    pub fn as_float_value(&self) -> Option<&f64> {
        match *self {
            Value::Float(ref f) => Some(f),
            _ => None,
        }
    }

    /// View the underlying object value, if present.
    pub fn as_object_value(&self) -> Option<&OrderMap<String, Value>> {
        match *self {
            Value::Object(ref o) => Some(o),
            _ => None,
        }
    }

    /// Mutable view into the underlying object value, if present.
    pub fn as_mut_object_value(&mut self) -> Option<&mut OrderMap<String, Value>> {
        match *self {
            Value::Object(ref mut o) => Some(o),
            _ => None,
        }
    }

    /// View the underlying list value, if present.
    pub fn as_list_value(&self) -> Option<&Vec<Value>> {
        match *self {
            Value::List(ref l) => Some(l),
            _ => None,
        }
    }

    /// View the underlying string value, if present.
    pub fn as_string_value(&self) -> Option<&str> {
        match *self {
            Value::String(ref s) => Some(s),
            _ => None,
        }
    }
}

impl ToInputValue for Value {
    fn to_input_value(&self) -> InputValue {
        match *self {
            Value::Null => InputValue::Null,
            Value::Int(i) => InputValue::Int(i),
            Value::Float(f) => InputValue::Float(f),
            Value::String(ref s) => InputValue::String(s.clone()),
            Value::Boolean(b) => InputValue::Boolean(b),
            Value::List(ref l) => InputValue::List(
                l.iter()
                    .map(|x| Spanning::unlocated(x.to_input_value()))
                    .collect(),
            ),
            Value::Object(ref o) => InputValue::Object(
                o.iter()
                    .map(|(k, v)| {
                        (
                            Spanning::unlocated(k.clone()),
                            Spanning::unlocated(v.to_input_value()),
                        )
                    })
                    .collect(),
            ),
        }
    }
}

impl<'a> From<&'a str> for Value {
    fn from(s: &'a str) -> Value {
        Value::string(s)
    }
}

impl From<String> for Value {
    fn from(s: String) -> Value {
        Value::string(s)
    }
}

impl From<bool> for Value {
    fn from(b: bool) -> Value {
        Value::boolean(b)
    }
}

impl From<i32> for Value {
    fn from(i: i32) -> Value {
        Value::int(i)
    }
}

impl From<f64> for Value {
    fn from(f: f64) -> Value {
        Value::float(f)
    }
}

impl<T> From<Option<T>> for Value
where
    Value: From<T>,
{
    fn from(v: Option<T>) -> Value {
        match v {
            Some(v) => Value::from(v),
            None => Value::null(),
        }
    }
}

/// Construct JSON-like values by using JSON syntax
///
/// This macro can be used to create `Value` instances using a JSON syntax.
/// Value objects are used mostly when creating custom errors from fields.
///
/// Here are some examples; the resulting JSON will look just like what you
/// passed in.
/// ```rust
/// #[macro_use] extern crate juniper;
///
/// graphql_value!(1234);
/// graphql_value!("test");
/// graphql_value!([ 1234, "test", true ]);
/// graphql_value!({ "key": "value", "foo": 1234 });
/// ```
#[macro_export]
macro_rules! graphql_value {
    ([ $($arg:tt),* $(,)* ]) => {
        $crate::Value::list(vec![
            $( graphql_value!($arg), )*
        ])
    };
    ({ $($key:tt : $val:tt ),* $(,)* }) => {
        $crate::Value::object(vec![
            $( ($key, graphql_value!($val)), )*
        ].into_iter().collect())
    };
    (None) => ($crate::Value::null());
    ($e:expr) => ($crate::Value::from($e))
}

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

    #[test]
    fn value_macro_string() {
        assert_eq!(graphql_value!("test"), Value::string("test"));
    }

    #[test]
    fn value_macro_int() {
        assert_eq!(graphql_value!(123), Value::int(123));
    }

    #[test]
    fn value_macro_float() {
        assert_eq!(graphql_value!(123.5), Value::float(123.5));
    }

    #[test]
    fn value_macro_boolean() {
        assert_eq!(graphql_value!(false), Value::boolean(false));
    }

    #[test]
    fn value_macro_option() {
        assert_eq!(graphql_value!(Some("test")), Value::string("test"));
        assert_eq!(graphql_value!(None), Value::null());
    }

    #[test]
    fn value_macro_list() {
        assert_eq!(
            graphql_value!([123, "Test", false]),
            Value::list(vec![
                Value::int(123),
                Value::string("Test"),
                Value::boolean(false),
            ])
        );
        assert_eq!(
            graphql_value!([123, [456], 789]),
            Value::list(vec![
                Value::int(123),
                Value::list(vec![Value::int(456)]),
                Value::int(789),
            ])
        );
    }

    #[test]
    fn value_macro_object() {
        assert_eq!(
            graphql_value!({ "key": 123, "next": true }),
            Value::object(
                vec![("key", Value::int(123)), ("next", Value::boolean(true))]
                    .into_iter()
                    .collect()
            )
        );
    }
}
<commit_msg>Make tests compile on latest nightly<commit_after>use ordermap::OrderMap;
use std::hash::Hash;

use parser::Spanning;
use ast::{InputValue, ToInputValue};

/// Serializable value returned from query and field execution.
///
/// Used by the execution engine and resolvers to build up the response
/// structure. Similar to the `Json` type found in the serialize crate.
///
/// It is also similar to the `InputValue` type, but can not contain enum
/// values or variables. Also, lists and objects do not contain any location
/// information since they are generated by resolving fields and values rather
/// than parsing a source query.
#[derive(Debug, PartialEq)]
#[allow(missing_docs)]
pub enum Value {
    Null,
    Int(i32),
    Float(f64),
    String(String),
    Boolean(bool),
    List(Vec<Value>),
    Object(OrderMap<String, Value>),
}

impl Value {
    // CONSTRUCTORS

    /// Construct a null value.
    pub fn null() -> Value {
        Value::Null
    }

    /// Construct an integer value.
    pub fn int(i: i32) -> Value {
        Value::Int(i)
    }

    /// Construct a floating point value.
    pub fn float(f: f64) -> Value {
        Value::Float(f)
    }

    /// Construct a string value.
    pub fn string<T: AsRef<str>>(s: T) -> Value {
        Value::String(s.as_ref().to_owned())
    }

    /// Construct a boolean value.
    pub fn boolean(b: bool) -> Value {
        Value::Boolean(b)
    }

    /// Construct a list value.
    pub fn list(l: Vec<Value>) -> Value {
        Value::List(l)
    }

    /// Construct an object value.
    pub fn object<K>(o: OrderMap<K, Value>) -> Value
    where
        K: Into<String> + Eq + Hash,
    {
        Value::Object(o.into_iter().map(|(k, v)| (k.into(), v)).collect())
    }

    // DISCRIMINATORS

    /// Does this value represent null?
    pub fn is_null(&self) -> bool {
        match *self {
            Value::Null => true,
            _ => false,
        }
    }

    /// View the underlying float value, if present.
    pub fn as_float_value(&self) -> Option<&f64> {
        match *self {
            Value::Float(ref f) => Some(f),
            _ => None,
        }
    }

    /// View the underlying object value, if present.
    pub fn as_object_value(&self) -> Option<&OrderMap<String, Value>> {
        match *self {
            Value::Object(ref o) => Some(o),
            _ => None,
        }
    }

    /// Mutable view into the underlying object value, if present.
    pub fn as_mut_object_value(&mut self) -> Option<&mut OrderMap<String, Value>> {
        match *self {
            Value::Object(ref mut o) => Some(o),
            _ => None,
        }
    }

    /// View the underlying list value, if present.
    pub fn as_list_value(&self) -> Option<&Vec<Value>> {
        match *self {
            Value::List(ref l) => Some(l),
            _ => None,
        }
    }

    /// View the underlying string value, if present.
    pub fn as_string_value(&self) -> Option<&str> {
        match *self {
            Value::String(ref s) => Some(s),
            _ => None,
        }
    }
}

impl ToInputValue for Value {
    fn to_input_value(&self) -> InputValue {
        match *self {
            Value::Null => InputValue::Null,
            Value::Int(i) => InputValue::Int(i),
            Value::Float(f) => InputValue::Float(f),
            Value::String(ref s) => InputValue::String(s.clone()),
            Value::Boolean(b) => InputValue::Boolean(b),
            Value::List(ref l) => InputValue::List(
                l.iter()
                    .map(|x| Spanning::unlocated(x.to_input_value()))
                    .collect(),
            ),
            Value::Object(ref o) => InputValue::Object(
                o.iter()
                    .map(|(k, v)| {
                        (
                            Spanning::unlocated(k.clone()),
                            Spanning::unlocated(v.to_input_value()),
                        )
                    })
                    .collect(),
            ),
        }
    }
}

impl<'a> From<&'a str> for Value {
    fn from(s: &'a str) -> Value {
        Value::string(s)
    }
}

impl From<String> for Value {
    fn from(s: String) -> Value {
        Value::string(s)
    }
}

impl From<bool> for Value {
    fn from(b: bool) -> Value {
        Value::boolean(b)
    }
}

impl From<i32> for Value {
    fn from(i: i32) -> Value {
        Value::int(i)
    }
}

impl From<f64> for Value {
    fn from(f: f64) -> Value {
        Value::float(f)
    }
}

impl<T> From<Option<T>> for Value
where
    Value: From<T>,
{
    fn from(v: Option<T>) -> Value {
        match v {
            Some(v) => Value::from(v),
            None => Value::null(),
        }
    }
}

/// Construct JSON-like values by using JSON syntax
///
/// This macro can be used to create `Value` instances using a JSON syntax.
/// Value objects are used mostly when creating custom errors from fields.
///
/// Here are some examples; the resulting JSON will look just like what you
/// passed in.
/// ```rust
/// #[macro_use] extern crate juniper;
///
/// # fn main() {
/// graphql_value!(1234);
/// graphql_value!("test");
/// graphql_value!([ 1234, "test", true ]);
/// graphql_value!({ "key": "value", "foo": 1234 });
/// # }
/// ```
#[macro_export]
macro_rules! graphql_value {
    ([ $($arg:tt),* $(,)* ]) => {
        $crate::Value::list(vec![
            $( graphql_value!($arg), )*
        ])
    };
    ({ $($key:tt : $val:tt ),* $(,)* }) => {
        $crate::Value::object(vec![
            $( ($key, graphql_value!($val)), )*
        ].into_iter().collect())
    };
    (None) => ($crate::Value::null());
    ($e:expr) => ($crate::Value::from($e))
}

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

    #[test]
    fn value_macro_string() {
        assert_eq!(graphql_value!("test"), Value::string("test"));
    }

    #[test]
    fn value_macro_int() {
        assert_eq!(graphql_value!(123), Value::int(123));
    }

    #[test]
    fn value_macro_float() {
        assert_eq!(graphql_value!(123.5), Value::float(123.5));
    }

    #[test]
    fn value_macro_boolean() {
        assert_eq!(graphql_value!(false), Value::boolean(false));
    }

    #[test]
    fn value_macro_option() {
        assert_eq!(graphql_value!(Some("test")), Value::string("test"));
        assert_eq!(graphql_value!(None), Value::null());
    }

    #[test]
    fn value_macro_list() {
        assert_eq!(
            graphql_value!([123, "Test", false]),
            Value::list(vec![
                Value::int(123),
                Value::string("Test"),
                Value::boolean(false),
            ])
        );
        assert_eq!(
            graphql_value!([123, [456], 789]),
            Value::list(vec![
                Value::int(123),
                Value::list(vec![Value::int(456)]),
                Value::int(789),
            ])
        );
    }

    #[test]
    fn value_macro_object() {
        assert_eq!(
            graphql_value!({ "key": 123, "next": true }),
            Value::object(
                vec![("key", Value::int(123)), ("next", Value::boolean(true))]
                    .into_iter()
                    .collect()
            )
        );
    }
}
<|endoftext|>


<commit_before>//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.

#![allow(dead_code)] // runtime init functions not used during testing

use crate::ffi::OsString;
use crate::fmt;
use crate::vec;

/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) {
    imp::init(argc, argv)
}

/// Returns the command line arguments
pub fn args() -> Args {
    imp::args()
}

pub struct Args {
    iter: vec::IntoIter<OsString>,
}

impl !Send for Args {}
impl !Sync for Args {}

impl fmt::Debug for Args {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.iter.as_slice().fmt(f)
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        self.iter.next()
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize {
        self.iter.len()
    }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> {
        self.iter.next_back()
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "android",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris",
    target_os = "illumos",
    target_os = "emscripten",
    target_os = "haiku",
    target_os = "l4re",
    target_os = "fuchsia",
    target_os = "redox",
    target_os = "vxworks"
))]
mod imp {
    use super::Args;
    use crate::ffi::{CStr, OsString};
    use crate::os::unix::prelude::*;
    use crate::ptr;
    use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};

    static ARGC: AtomicIsize = AtomicIsize::new(0);
    static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());

    unsafe fn really_init(argc: isize, argv: *const *const u8) {
        ARGC.store(argc, Ordering::Relaxed);
        ARGV.store(argv as *mut _, Ordering::Relaxed);
    }

    #[inline(always)]
    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
        // On Linux-GNU, we rely on `ARGV_INIT_ARRAY` below to initialize
        // `ARGC` and `ARGV`. But in Miri that does not actually happen so we
        // still initialize here.
        #[cfg(any(miri, not(all(target_os = "linux", target_env = "gnu"))))]
        really_init(_argc, _argv);
    }

    /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
    /// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
    #[cfg(all(target_os = "linux", target_env = "gnu"))]
    #[used]
    #[link_section = ".init_array.00099"]
    static ARGV_INIT_ARRAY: extern "C" fn(
        crate::os::raw::c_int,
        *const *const u8,
        *const *const u8,
    ) = {
        extern "C" fn init_wrapper(
            argc: crate::os::raw::c_int,
            argv: *const *const u8,
            _envp: *const *const u8,
        ) {
            unsafe {
                really_init(argc as isize, argv);
            }
        }
        init_wrapper
    };

    pub fn args() -> Args {
        Args { iter: clone().into_iter() }
    }

    fn clone() -> Vec<OsString> {
        unsafe {
            // Load ARGC and ARGV without a lock. If the store to either ARGV or
            // ARGC isn't visible yet, we'll return an empty argument list.
            let argv = ARGV.load(Ordering::Relaxed);
            let argc = if argv.is_null() {
                0
            } else {
                ARGC.load(Ordering::Relaxed)
            };
            (0..argc)
                .map(|i| {
                    let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
                    OsStringExt::from_vec(cstr.to_bytes().to_vec())
                })
                .collect()
        }
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod imp {
    use super::Args;
    use crate::ffi::CStr;

    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}

    #[cfg(target_os = "macos")]
    pub fn args() -> Args {
        use crate::os::unix::prelude::*;
        extern "C" {
            // These functions are in crt_externs.h.
            fn _NSGetArgc() -> *mut libc::c_int;
            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
        }

        let vec = unsafe {
            let (argc, argv) =
                (*_NSGetArgc() as isize, *_NSGetArgv() as *const *const libc::c_char);
            (0..argc as isize)
                .map(|i| {
                    let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
                    OsStringExt::from_vec(bytes)
                })
                .collect::<Vec<_>>()
        };
        Args { iter: vec.into_iter() }
    }

    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
    // and use underscores in their names - they're most probably
    // are considered private and therefore should be avoided
    // Here is another way to get arguments using Objective C
    // runtime
    //
    // In general it looks like:
    // res = Vec::new()
    // let args = [[NSProcessInfo processInfo] arguments]
    // for i in (0..[args count])
    //      res.push([args objectAtIndex:i])
    // res
    #[cfg(target_os = "ios")]
    pub fn args() -> Args {
        use crate::ffi::OsString;
        use crate::mem;
        use crate::str;

        extern "C" {
            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
        }

        #[cfg(target_arch = "aarch64")]
        extern "C" {
            fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
            #[allow(clashing_extern_declarations)]
            #[link_name = "objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
        }

        #[cfg(not(target_arch = "aarch64"))]
        extern "C" {
            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
            #[allow(clashing_extern_declarations)]
            #[link_name = "objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
        }

        type Sel = *const libc::c_void;
        type NsId = *const libc::c_void;

        let mut res = Vec::new();

        unsafe {
            let process_info_sel = sel_registerName("processInfo\0".as_ptr());
            let arguments_sel = sel_registerName("arguments\0".as_ptr());
            let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
            let count_sel = sel_registerName("count\0".as_ptr());
            let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());

            let klass = objc_getClass("NSProcessInfo\0".as_ptr());
            let info = objc_msgSend(klass, process_info_sel);
            let args = objc_msgSend(info, arguments_sel);

            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
            for i in 0..cnt {
                let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
                let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel));
                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
            }
        }

        Args { iter: res.into_iter() }
    }
}
<commit_msg>x.py fmt<commit_after>//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.

#![allow(dead_code)] // runtime init functions not used during testing

use crate::ffi::OsString;
use crate::fmt;
use crate::vec;

/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) {
    imp::init(argc, argv)
}

/// Returns the command line arguments
pub fn args() -> Args {
    imp::args()
}

pub struct Args {
    iter: vec::IntoIter<OsString>,
}

impl !Send for Args {}
impl !Sync for Args {}

impl fmt::Debug for Args {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.iter.as_slice().fmt(f)
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        self.iter.next()
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize {
        self.iter.len()
    }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> {
        self.iter.next_back()
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "android",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris",
    target_os = "illumos",
    target_os = "emscripten",
    target_os = "haiku",
    target_os = "l4re",
    target_os = "fuchsia",
    target_os = "redox",
    target_os = "vxworks"
))]
mod imp {
    use super::Args;
    use crate::ffi::{CStr, OsString};
    use crate::os::unix::prelude::*;
    use crate::ptr;
    use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};

    static ARGC: AtomicIsize = AtomicIsize::new(0);
    static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());

    unsafe fn really_init(argc: isize, argv: *const *const u8) {
        ARGC.store(argc, Ordering::Relaxed);
        ARGV.store(argv as *mut _, Ordering::Relaxed);
    }

    #[inline(always)]
    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
        // On Linux-GNU, we rely on `ARGV_INIT_ARRAY` below to initialize
        // `ARGC` and `ARGV`. But in Miri that does not actually happen so we
        // still initialize here.
        #[cfg(any(miri, not(all(target_os = "linux", target_env = "gnu"))))]
        really_init(_argc, _argv);
    }

    /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
    /// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
    #[cfg(all(target_os = "linux", target_env = "gnu"))]
    #[used]
    #[link_section = ".init_array.00099"]
    static ARGV_INIT_ARRAY: extern "C" fn(
        crate::os::raw::c_int,
        *const *const u8,
        *const *const u8,
    ) = {
        extern "C" fn init_wrapper(
            argc: crate::os::raw::c_int,
            argv: *const *const u8,
            _envp: *const *const u8,
        ) {
            unsafe {
                really_init(argc as isize, argv);
            }
        }
        init_wrapper
    };

    pub fn args() -> Args {
        Args { iter: clone().into_iter() }
    }

    fn clone() -> Vec<OsString> {
        unsafe {
            // Load ARGC and ARGV without a lock. If the store to either ARGV or
            // ARGC isn't visible yet, we'll return an empty argument list.
            let argv = ARGV.load(Ordering::Relaxed);
            let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
            (0..argc)
                .map(|i| {
                    let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
                    OsStringExt::from_vec(cstr.to_bytes().to_vec())
                })
                .collect()
        }
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod imp {
    use super::Args;
    use crate::ffi::CStr;

    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}

    #[cfg(target_os = "macos")]
    pub fn args() -> Args {
        use crate::os::unix::prelude::*;
        extern "C" {
            // These functions are in crt_externs.h.
            fn _NSGetArgc() -> *mut libc::c_int;
            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
        }

        let vec = unsafe {
            let (argc, argv) =
                (*_NSGetArgc() as isize, *_NSGetArgv() as *const *const libc::c_char);
            (0..argc as isize)
                .map(|i| {
                    let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
                    OsStringExt::from_vec(bytes)
                })
                .collect::<Vec<_>>()
        };
        Args { iter: vec.into_iter() }
    }

    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
    // and use underscores in their names - they're most probably
    // are considered private and therefore should be avoided
    // Here is another way to get arguments using Objective C
    // runtime
    //
    // In general it looks like:
    // res = Vec::new()
    // let args = [[NSProcessInfo processInfo] arguments]
    // for i in (0..[args count])
    //      res.push([args objectAtIndex:i])
    // res
    #[cfg(target_os = "ios")]
    pub fn args() -> Args {
        use crate::ffi::OsString;
        use crate::mem;
        use crate::str;

        extern "C" {
            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
        }

        #[cfg(target_arch = "aarch64")]
        extern "C" {
            fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
            #[allow(clashing_extern_declarations)]
            #[link_name = "objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
        }

        #[cfg(not(target_arch = "aarch64"))]
        extern "C" {
            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
            #[allow(clashing_extern_declarations)]
            #[link_name = "objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
        }

        type Sel = *const libc::c_void;
        type NsId = *const libc::c_void;

        let mut res = Vec::new();

        unsafe {
            let process_info_sel = sel_registerName("processInfo\0".as_ptr());
            let arguments_sel = sel_registerName("arguments\0".as_ptr());
            let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
            let count_sel = sel_registerName("count\0".as_ptr());
            let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());

            let klass = objc_getClass("NSProcessInfo\0".as_ptr());
            let info = objc_msgSend(klass, process_info_sel);
            let args = objc_msgSend(info, arguments_sel);

            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
            for i in 0..cnt {
                let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
                let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel));
                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
            }
        }

        Args { iter: res.into_iter() }
    }
}
<|endoftext|>


<commit_before>
<commit_msg>roman-numerals: Added template to the stub file (#579)<commit_after>use std::fmt::{Display, Formatter, Result};

pub struct Roman;

impl Display for Roman {
    fn fmt(&self, _f: &mut Formatter) -> Result {
        unimplemented!("Return a roman-numeral string representation of the Roman object");
    }
}

impl From<u32> for Roman {
    fn from(num: u32) -> Self {
        unimplemented!("Construct a Roman object from the '{}' number", num);
    }
}
<|endoftext|>


<commit_before>use jack_sys as j;
use std::fmt;
use std::mem;

use super::callbacks::clear_callbacks;
use super::callbacks::{CallbackContext, NotificationHandler, ProcessHandler};
use crate::client::client_impl::Client;
use crate::client::common::{sleep_on_test, CREATE_OR_DESTROY_CLIENT_MUTEX};
use crate::Error;

/// A JACK client that is processing data asynchronously, in real-time.
///
/// To create input or output (either sound or midi), a `Port` can be used within the `process`
/// callback. See `Client::register_port` on creating ports. Also, see `Port` for documentation on
/// the API for port.
///
/// # Example
/// ```
/// // Create a client and a handler
/// let (client, _status) =
///     jack::Client::new("my_client", jack::ClientOptions::NO_START_SERVER).unwrap();
/// let process_handler = jack::ClosureProcessHandler::new(
///     move |_: &jack::Client, _: &jack::ProcessScope| jack::Control::Continue,
/// );
///
/// // An active async client is created, `client` is consumed.
/// let active_client = client.activate_async((), process_handler).unwrap();
/// ```
pub struct AsyncClient<N, P> {
    callback: Option<Box<CallbackContext<N, P>>>,
}

impl<N, P> AsyncClient<N, P>
where
    N: 'static + Send + Sync + NotificationHandler,
    P: 'static + Send + ProcessHandler,
{
    /// Tell the JACK server that the program is ready to start processing audio. JACK will call the
    /// methods specified by the `NotificationHandler` and `ProcessHandler` objects.
    ///
    /// On failure, either `Err(Error::CallbackRegistrationError)` or
    /// `Err(Error::ClientActivationError)` is returned.
    ///
    /// `notification_handler` and `process_handler` are consumed, but they are returned when
    /// `Client::deactivate` is called.
    pub fn new(client: Client, notification_handler: N, process_handler: P) -> Result<Self, Error> {
        let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
        unsafe {
            sleep_on_test();
            let mut callback_context = Box::new(CallbackContext {
                client,
                notification: notification_handler,
                process: process_handler,
            });
            CallbackContext::register_callbacks(&mut callback_context)?;
            sleep_on_test();
            let res = j::jack_activate(callback_context.client.raw());
            for _ in 0..4 {
                sleep_on_test();
            }
            match res {
                0 => Ok(AsyncClient {
                    callback: Some(callback_context),
                }),
                _ => {
                    mem::forget(callback_context);
                    Err(Error::ClientActivationError)
                }
            }
        }
    }
}

impl<N, P> AsyncClient<N, P> {
    /// Return the underlying `jack::Client`.
    #[inline(always)]
    pub fn as_client(&self) -> &Client {
        let callback = self.callback.as_ref().unwrap();
        &callback.client
    }

    /// Tell the JACK server to remove this client from the process graph.  Also, disconnect all
    /// ports belonging to it since inactive clients have no port connections.
    ///
    /// The `handler` that was used for `Client::activate` is returned on success. Its state may
    /// have changed due to JACK calling its methods.
    ///
    /// In the case of error, the `Client` is destroyed because its state is unknown, and it is
    /// therefore unsafe to continue using.
    pub fn deactivate(self) -> Result<(Client, N, P), Error> {
        let mut c = self;
        unsafe {
            c.maybe_deactivate()
                .map(|c| (c.client, c.notification, c.process))
        }
    }

    // Helper function for deactivating. Any function that calls this should
    // have ownership of self and no longer use it after this call.
    unsafe fn maybe_deactivate(&mut self) -> Result<CallbackContext<N, P>, Error> {
        let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
        if self.callback.is_none() {
            return Err(Error::ClientIsNoLongerAlive);
        }
        let client = self.callback.as_ref().unwrap().client.raw();
        // Prevent the callback from being deallocated in case deactivation
        // fails.
        let callback = Box::into_raw(self.callback.take().unwrap());

        // deactivate
        sleep_on_test();
        if j::jack_deactivate(client) != 0 {
            return Err(Error::ClientDeactivationError);
        }

        // clear the callbacks
        sleep_on_test();
        clear_callbacks(client)?;

        // done, take ownership of callback
        Ok(*Box::from_raw(callback))
    }
}

/// Closes the client.
impl<N, P> Drop for AsyncClient<N, P> {
    /// Deactivate and close the client.
    fn drop(&mut self) {
        let _ = unsafe { self.maybe_deactivate() };
    }
}

impl<N, P> fmt::Debug for AsyncClient<N, P> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "AsyncClient({:?})", self.as_client())
    }
}
<commit_msg>added must_drop annotation to AsyncClient (#141)<commit_after>use jack_sys as j;
use std::fmt;
use std::mem;

use super::callbacks::clear_callbacks;
use super::callbacks::{CallbackContext, NotificationHandler, ProcessHandler};
use crate::client::client_impl::Client;
use crate::client::common::{sleep_on_test, CREATE_OR_DESTROY_CLIENT_MUTEX};
use crate::Error;

/// A JACK client that is processing data asynchronously, in real-time.
///
/// To create input or output (either sound or midi), a `Port` can be used within the `process`
/// callback. See `Client::register_port` on creating ports. Also, see `Port` for documentation on
/// the API for port.
///
/// # Example
/// ```
/// // Create a client and a handler
/// let (client, _status) =
///     jack::Client::new("my_client", jack::ClientOptions::NO_START_SERVER).unwrap();
/// let process_handler = jack::ClosureProcessHandler::new(
///     move |_: &jack::Client, _: &jack::ProcessScope| jack::Control::Continue,
/// );
///
/// // An active async client is created, `client` is consumed.
/// let active_client = client.activate_async((), process_handler).unwrap();
/// ```
#[must_use = "the jack client is shut down when the AsyncClient is dropped"]
pub struct AsyncClient<N, P> {
    callback: Option<Box<CallbackContext<N, P>>>,
}

impl<N, P> AsyncClient<N, P>
where
    N: 'static + Send + Sync + NotificationHandler,
    P: 'static + Send + ProcessHandler,
{
    /// Tell the JACK server that the program is ready to start processing audio. JACK will call the
    /// methods specified by the `NotificationHandler` and `ProcessHandler` objects.
    ///
    /// On failure, either `Err(Error::CallbackRegistrationError)` or
    /// `Err(Error::ClientActivationError)` is returned.
    ///
    /// `notification_handler` and `process_handler` are consumed, but they are returned when
    /// `Client::deactivate` is called.
    pub fn new(client: Client, notification_handler: N, process_handler: P) -> Result<Self, Error> {
        let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
        unsafe {
            sleep_on_test();
            let mut callback_context = Box::new(CallbackContext {
                client,
                notification: notification_handler,
                process: process_handler,
            });
            CallbackContext::register_callbacks(&mut callback_context)?;
            sleep_on_test();
            let res = j::jack_activate(callback_context.client.raw());
            for _ in 0..4 {
                sleep_on_test();
            }
            match res {
                0 => Ok(AsyncClient {
                    callback: Some(callback_context),
                }),
                _ => {
                    mem::forget(callback_context);
                    Err(Error::ClientActivationError)
                }
            }
        }
    }
}

impl<N, P> AsyncClient<N, P> {
    /// Return the underlying `jack::Client`.
    #[inline(always)]
    pub fn as_client(&self) -> &Client {
        let callback = self.callback.as_ref().unwrap();
        &callback.client
    }

    /// Tell the JACK server to remove this client from the process graph.  Also, disconnect all
    /// ports belonging to it since inactive clients have no port connections.
    ///
    /// The `handler` that was used for `Client::activate` is returned on success. Its state may
    /// have changed due to JACK calling its methods.
    ///
    /// In the case of error, the `Client` is destroyed because its state is unknown, and it is
    /// therefore unsafe to continue using.
    pub fn deactivate(self) -> Result<(Client, N, P), Error> {
        let mut c = self;
        unsafe {
            c.maybe_deactivate()
                .map(|c| (c.client, c.notification, c.process))
        }
    }

    // Helper function for deactivating. Any function that calls this should
    // have ownership of self and no longer use it after this call.
    unsafe fn maybe_deactivate(&mut self) -> Result<CallbackContext<N, P>, Error> {
        let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
        if self.callback.is_none() {
            return Err(Error::ClientIsNoLongerAlive);
        }
        let client = self.callback.as_ref().unwrap().client.raw();
        // Prevent the callback from being deallocated in case deactivation
        // fails.
        let callback = Box::into_raw(self.callback.take().unwrap());

        // deactivate
        sleep_on_test();
        if j::jack_deactivate(client) != 0 {
            return Err(Error::ClientDeactivationError);
        }

        // clear the callbacks
        sleep_on_test();
        clear_callbacks(client)?;

        // done, take ownership of callback
        Ok(*Box::from_raw(callback))
    }
}

/// Closes the client.
impl<N, P> Drop for AsyncClient<N, P> {
    /// Deactivate and close the client.
    fn drop(&mut self) {
        let _ = unsafe { self.maybe_deactivate() };
    }
}

impl<N, P> fmt::Debug for AsyncClient<N, P> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "AsyncClient({:?})", self.as_client())
    }
}
<|endoftext|>


<commit_before>use std::iter::Filter;
use calx::dijkstra::Dijkstra;
use entity::Entity;
use ecs::EntityIter;
use world;
use flags;
use dir6::Dir6;
use area::Area;
use location::Location;

/// Game update control.
#[deriving(Copy, PartialEq)]
pub enum ControlState {
    AwaitingInput,
    ReadyToUpdate,
}

/// Player input action.
#[deriving(Copy, Eq, PartialEq, Clone, Show, Encodable, Decodable)]
pub enum Input {
    /// Take a step in the given direction.
    Step(Dir6),
    Melee(Dir6),
    // TODO: More
}

/// Return the player entity if one exists.
pub fn player() -> Option<Entity> {
    let mut iter = world::with(|w| w.ecs.iter());
    for e in iter {
        if e.is_player() { return Some(e); }
    }
    None
}

/// Find the first entity that has a local (not inherited) Desc component with
/// the given name.
pub fn find_prototype(name: &str) -> Option<Entity> {
    world::with(|w|
        entities().find(|&e| {
            if let Some(d) = w.descs().get_local(e) {
                if d.name == name { return true; }
            }
            false
        })
    )
}

// World update state machine //////////////////////////////////////////

/// Get the current control state.
pub fn control_state() -> ControlState {
    if world::with(|w| w.flags.player_acted) { return ControlState::ReadyToUpdate; }
    match player() {
        Some(p) if p.acts_this_frame() => ControlState::AwaitingInput,
        _ => ControlState::ReadyToUpdate,
    }
}

/// Top-level game state update function. Only valid to call if
/// control_state() returned ReadyToUpdate.
pub fn update() {
    assert!(control_state() == ControlState::ReadyToUpdate);

    ai_main();

    world::with_mut(|w| {
        w.flags.tick += 1;
        w.flags.player_acted = false;
    });
}

/// Give player input. Only valid to call if control_state() returned
/// AwaitingInput.
pub fn input(input: Input) {
    assert!(control_state() == ControlState::AwaitingInput);
    let p = player().expect("No player to receive input");
    match input {
        Input::Step(d) => {
            p.step(d);
            flags::set_camera(p.location().expect("No player location"));
        }
        Input::Melee(d) => {
            p.melee(d);
        }
    }
    world::with_mut(|w| w.flags.player_acted = true);

    // Run one world update cycle right away, so that we don't get awkward
    // single frames rendered where the player has acted and the rest of the
    // world hasn't.
    if control_state() == ControlState::ReadyToUpdate {
        update();
    }
}

// Entities ////////////////////////////////////////////////////////////

/// Return an iterator of all the world entities.
pub fn entities() -> EntityIter {
    world::with(|w| w.ecs.iter())
}

/// Return an iterator of all the world mobs.
pub fn mobs() -> Filter<Entity, EntityIter, fn(&Entity) -> bool> {
    fn is_mob(e: &Entity) -> bool { e.is_mob() }
    entities().filter(is_mob)
}

/// Run AI for all autonomous mobs.
fn ai_main() {
    for entity in entities() {
        entity.update();
    }
}

// World logic /////////////////////////////////////////////////////////

/// Return the current floor depth. Greater depths mean more powerful monsters
/// and stranger terrain.
pub fn current_depth() -> int { world::with(|w| w.area.seed.spec.depth) }

pub fn start_level(depth: int) {

    let biome = match depth {
        1 => ::Biome::Overland,
        _ => ::Biome::Dungeon,
    };

    clear_nonplayers();

    let seed = world::with(|w| w.flags.seed);

    world::with_mut(|w| {
        let new_area = Area::new(
            seed,
            ::AreaSpec::new(biome, depth));
        w.area = new_area
    });

    let eggs = world::with(|w| w.area.get_eggs());
    for &(ref egg, ref loc) in eggs.iter() {
        egg.hatch(*loc);
    }

    let start_loc = world::with(|w| w.area.player_entrance());
    // Either reuse the existing player or create a new one.
    match player() {
        Some(p) => {
            p.forget_map();
            p.place(start_loc);
        }
        None => {
            find_prototype("Player").expect("No Player prototype found!")
            .clone_at(start_loc);
        }
    };
    flags::set_camera(start_loc);
}

fn clear_nonplayers() {
    for e in entities() {
        if e.location().is_some() && !e.is_player() {
            e.delete();
        }
    }
}

/// Move the player to the next level.
pub fn next_level() {
    // This is assuming a really simple, original Rogue style descent-only, no
    // persistent maps style world.
    start_level(current_depth() + 1);
    caption!("Depth {}", current_depth() - 1);
}

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

pub fn autoexplore_map() -> Option<Dijkstra<Location>> {
    let pathing_depth = 16;

    let locs = world::with(|w| w.area.terrain.iter()
                           .map(|(&loc, _)| loc)
                           .filter(|loc| loc.fov_status().is_none())
                           .collect::<Vec<Location>>());

    if locs.len() == 0 {
        return None;
    }

    Some(Dijkstra::new(locs, |&loc| !loc.blocks_walk(), pathing_depth))
}
<commit_msg>Use proper API level<commit_after>use std::iter::Filter;
use calx::dijkstra::Dijkstra;
use entity::Entity;
use ecs::EntityIter;
use world;
use flags;
use dir6::Dir6;
use area::Area;
use location::Location;

/// Game update control.
#[deriving(Copy, PartialEq)]
pub enum ControlState {
    AwaitingInput,
    ReadyToUpdate,
}

/// Player input action.
#[deriving(Copy, Eq, PartialEq, Clone, Show, Encodable, Decodable)]
pub enum Input {
    /// Take a step in the given direction.
    Step(Dir6),
    Melee(Dir6),
    // TODO: More
}

/// Return the player entity if one exists.
pub fn player() -> Option<Entity> {
    for e in entities() {
        if e.is_player() { return Some(e); }
    }
    None
}

/// Find the first entity that has a local (not inherited) Desc component with
/// the given name.
pub fn find_prototype(name: &str) -> Option<Entity> {
    world::with(|w|
        entities().find(|&e| {
            if let Some(d) = w.descs().get_local(e) {
                if d.name == name { return true; }
            }
            false
        })
    )
}

// World update state machine //////////////////////////////////////////

/// Get the current control state.
pub fn control_state() -> ControlState {
    if world::with(|w| w.flags.player_acted) { return ControlState::ReadyToUpdate; }
    match player() {
        Some(p) if p.acts_this_frame() => ControlState::AwaitingInput,
        _ => ControlState::ReadyToUpdate,
    }
}

/// Top-level game state update function. Only valid to call if
/// control_state() returned ReadyToUpdate.
pub fn update() {
    assert!(control_state() == ControlState::ReadyToUpdate);

    ai_main();

    world::with_mut(|w| {
        w.flags.tick += 1;
        w.flags.player_acted = false;
    });
}

/// Give player input. Only valid to call if control_state() returned
/// AwaitingInput.
pub fn input(input: Input) {
    assert!(control_state() == ControlState::AwaitingInput);
    let p = player().expect("No player to receive input");
    match input {
        Input::Step(d) => {
            p.step(d);
            flags::set_camera(p.location().expect("No player location"));
        }
        Input::Melee(d) => {
            p.melee(d);
        }
    }
    world::with_mut(|w| w.flags.player_acted = true);

    // Run one world update cycle right away, so that we don't get awkward
    // single frames rendered where the player has acted and the rest of the
    // world hasn't.
    if control_state() == ControlState::ReadyToUpdate {
        update();
    }
}

// Entities ////////////////////////////////////////////////////////////

/// Return an iterator of all the world entities.
pub fn entities() -> EntityIter {
    world::with(|w| w.ecs.iter())
}

/// Return an iterator of all the world mobs.
pub fn mobs() -> Filter<Entity, EntityIter, fn(&Entity) -> bool> {
    fn is_mob(e: &Entity) -> bool { e.is_mob() }
    entities().filter(is_mob)
}

/// Run AI for all autonomous mobs.
fn ai_main() {
    for entity in entities() {
        entity.update();
    }
}

// World logic /////////////////////////////////////////////////////////

/// Return the current floor depth. Greater depths mean more powerful monsters
/// and stranger terrain.
pub fn current_depth() -> int { world::with(|w| w.area.seed.spec.depth) }

pub fn start_level(depth: int) {

    let biome = match depth {
        1 => ::Biome::Overland,
        _ => ::Biome::Dungeon,
    };

    clear_nonplayers();

    let seed = world::with(|w| w.flags.seed);

    world::with_mut(|w| {
        let new_area = Area::new(
            seed,
            ::AreaSpec::new(biome, depth));
        w.area = new_area
    });

    let eggs = world::with(|w| w.area.get_eggs());
    for &(ref egg, ref loc) in eggs.iter() {
        egg.hatch(*loc);
    }

    let start_loc = world::with(|w| w.area.player_entrance());
    // Either reuse the existing player or create a new one.
    match player() {
        Some(p) => {
            p.forget_map();
            p.place(start_loc);
        }
        None => {
            find_prototype("Player").expect("No Player prototype found!")
            .clone_at(start_loc);
        }
    };
    flags::set_camera(start_loc);
}

fn clear_nonplayers() {
    for e in entities() {
        if e.location().is_some() && !e.is_player() {
            e.delete();
        }
    }
}

/// Move the player to the next level.
pub fn next_level() {
    // This is assuming a really simple, original Rogue style descent-only, no
    // persistent maps style world.
    start_level(current_depth() + 1);
    caption!("Depth {}", current_depth() - 1);
}

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

pub fn autoexplore_map() -> Option<Dijkstra<Location>> {
    let pathing_depth = 16;

    let locs = world::with(|w| w.area.terrain.iter()
                           .map(|(&loc, _)| loc)
                           .filter(|loc| loc.fov_status().is_none())
                           .collect::<Vec<Location>>());

    if locs.len() == 0 {
        return None;
    }

    Some(Dijkstra::new(locs, |&loc| !loc.blocks_walk(), pathing_depth))
}
<|endoftext|>