<commit_before>//! Shader module.
//!
//! Shader functions and declarations can be grouped in so-called *modules*. Modules structure is
//! inherently tied to the filesystem’s tree.
//!
//! You’re not supposed to use modules at the Rust level, even though you can. You’re supposed to
//! actually write modules that will be used by shader programs.

use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

use render::shader::lang::parser;
use render::shader::lang::syntax::{Declaration, ExternalDeclaration, FunctionDefinition, FullySpecifiedType,
                                   FunctionParameterDeclaration, InitDeclaratorList,
                                   Module as SyntaxModule, SingleDeclaration, StorageQualifier,
                                   StructSpecifier, StructFieldSpecifier,
                                   TypeSpecifier, TypeQualifierSpec};
use sys::resource::{CacheKey, Load, LoadError, LoadResult, Store, StoreKey};

/// Shader module.
///
/// A shader module is a piece of GLSL code with optional import lists (dependencies).
///
/// You’re not supposed to directly manipulate any object of this type. You just write modules on
/// disk and let everyting happen automatically for you.
#[derive(Clone, Debug, PartialEq)]
pub struct Module(pub SyntaxModule); // FIXME: remove the pub

impl Module {
  /// Retrieve all the modules this module depends on, without duplicates.
  pub fn deps(&self, store: &mut Store, key: &ModuleKey) -> Result<Vec<ModuleKey>, DepsError> {
    let mut deps = Vec::new();
    self.deps_no_cycle(store, &key, &mut Vec::new(), &mut deps).map(|_| deps)
  }

  fn deps_no_cycle(&self, store: &mut Store, key: &ModuleKey, parents: &mut Vec<ModuleKey>, deps: &mut Vec<ModuleKey>) -> Result<(), DepsError> {
    let imports = self.0.imports.iter().map(|il| &il.module);

    parents.push(key.clone());

    for module_path in imports {
      let module_key = ModuleKey(module_path.path.join("."));

      // check whether it’s already in the deps
      if deps.contains(&module_key) {
        continue;
      }

      // check whether the module was already visited
      if parents.contains(&module_key) {
        return Err(DepsError::Cycle(module_key.clone(), module_key.clone()));
      }

      // get the dependency module
      let module = store.get(&module_key).ok_or_else(|| DepsError::LoadError(module_key.clone()))?;
      module.borrow().deps_no_cycle(store, &module_key, parents, deps)?;

      deps.push(module_key.clone());
      parents.pop();
    }

    Ok(())
  }

  /// Fold a module and its dependencies into a single module. The list of dependencies is also
  /// returned.
  pub fn gather(&self, store: &mut Store, k: &ModuleKey) -> Result<(Self, Vec<ModuleKey>), DepsError> {
    let deps = self.deps(store, k)?;
    let glsl =
      deps.iter()
          .flat_map(|kd| {
              let m = store.get(kd).unwrap();
              let g = m.borrow().0.glsl.clone();
              g
            })
          .chain(self.0.glsl.clone())
          .collect();

    let module = Module(SyntaxModule {
      imports: Vec::new(),
      glsl
    });

    Ok((module, deps))
  }

  /// Get all the uniforms defined in a module.
  pub fn uniforms(&self) -> Vec<SingleDeclaration> {
    let mut uniforms = Vec::new();

    for glsl in &self.0.glsl {
      if let ExternalDeclaration::Declaration(Declaration::InitDeclaratorList(ref i)) = *glsl {
        if let Some(ref q) = i.head.ty.qualifier {
          if q.qualifiers.contains(&TypeQualifierSpec::Storage(StorageQualifier::Uniform)) {
            uniforms.push(i.head.clone());

            // check whether we have more
            for next in &i.tail {
              uniforms.push(SingleDeclaration {
                ty: i.head.ty.clone(),
                name: Some(next.name.clone()),
                array_specifier: next.array_specifier.clone(),
                initializer: None
              })
            }
          }
        }
      }
    }

    uniforms
  }

  /// Get all the functions.
  pub fn functions(&self) -> Vec<FunctionDefinition> {
    self.0.glsl.iter().filter_map(|ed| match *ed {
      ExternalDeclaration::FunctionDefinition(ref def) => Some(def.clone()),
      _ => None
    }).collect()
  }

  /// Get all the declared structures.
  pub fn structs(&self) -> Vec<StructSpecifier> {
    self.0.glsl.iter().filter_map(|ed| {
      match *ed {
        ExternalDeclaration::Declaration(
          Declaration::InitDeclaratorList(
            InitDeclaratorList {
              head: SingleDeclaration {
                ty: FullySpecifiedType {
                  ty: TypeSpecifier::Struct(ref s),
                  ..
                },
                ..
              },
              ..
            }
          )
        ) => Some(s.clone()),
        _ => None
      }
    }).collect()
  }
}

/// Vertex shader I/O interface.
///
/// It contains the inputs and the outputs to the next stage.
#[derive(Clone, Debug, PartialEq)]
pub struct VertexShaderInterface {
  inputs: Vec<ExternalDeclaration>,
  outputs: Vec<ExternalDeclaration>
}

#[derive(Clone, Debug, PartialEq)]
pub enum VertexShaderInterfaceError {
  UnnamedInput,
  OutputHasMainQualifier,
  OutputTypeMustBeAStruct(TypeSpecifier),
  WrongOutputFirstField(StructFieldSpecifier),
  OutputFieldCannotBeStruct(usize, TypeSpecifier),
  OutputFieldCannotHaveSeveralIdentifiers(usize, StructFieldSpecifier)
}

/// Build the vertex shader interface from a function definition.
pub fn vertex_shader_interface(fun_def: &FunctionDefinition, structs: &[StructSpecifier]) -> Result<VertexShaderInterface, VertexShaderInterfaceError> {
  let proto = &fun_def.prototype;
  let inputs = vertex_shader_inputs(proto.parameters.iter())?;
  let outputs = vertex_shader_outputs(&proto.ty, structs)?;

  Ok(VertexShaderInterface { inputs, outputs })
}

fn vertex_shader_inputs<'a, I>(args: I) -> Result<Vec<ExternalDeclaration>, VertexShaderInterfaceError> where I: IntoIterator<Item = &'a FunctionParameterDeclaration> {
  let mut inputs = Vec::new();

  for arg in args {
    match *arg {
      FunctionParameterDeclaration::Unnamed(..) => return Err(VertexShaderInterfaceError::UnnamedInput),
      FunctionParameterDeclaration::Named(ref ty_qual, ref decl) => {
        let qualifier = ty_qual.clone();
        let ty = decl.ty.clone();
        let name = Some(decl.name.clone());
        let array_spec = decl.array_spec.clone();
        let idl = InitDeclaratorList {
          head: SingleDeclaration {
            ty: FullySpecifiedType {
              qualifier,
              ty
            },
            name,
            array_specifier: array_spec,
            initializer: None
          },
          tail: Vec::new()
        };
        let ed = ExternalDeclaration::Declaration(Declaration::InitDeclaratorList(idl));

        inputs.push(ed);
      }
    }
  }

  Ok(inputs)
}

fn vertex_shader_outputs(fsty: &FullySpecifiedType, structs: &[StructSpecifier]) -> Result<Vec<ExternalDeclaration>, VertexShaderInterfaceError> {
  // we refuse that the output has a main qualifier
  if fsty.qualifier.is_some() {
    return Err(VertexShaderInterfaceError::OutputHasMainQualifier);
  }

  let ty = &fsty.ty;

  // we enforce that the output must be a struct that follows a certain pattern
  match *ty {
    TypeSpecifier::TypeName(ref ty_name) => {
      let real_ty = structs.iter().find(|ref s| s.name.as_ref() == Some(ty_name));

      match real_ty {
        Some(ref s) => {
          // the first field must be named "gl_Position", has type vec4 and no qualifier
          let first_field = &s.fields[0];

          if first_field.qualifier.is_some() ||
             first_field.ty != TypeSpecifier::Vec4 ||
             first_field.identifiers != vec![("gl_Position".to_owned(), None)] {
            return Err(VertexShaderInterfaceError::WrongOutputFirstField(first_field.clone()));
          }

          // then, for all other fields, we check that they are not composite type (i.e. structs); if
          // they are not, add them to the interface; otherwise, fail
          let mut outputs = Vec::new();

          for (i, field) in (&s.fields[1..]).into_iter().enumerate() {
            if let TypeSpecifier::Struct(_) = field.ty {
              return Err(VertexShaderInterfaceError::OutputFieldCannotBeStruct(i, field.ty.clone()));
            }

            if field.identifiers.len() > 1 {
              return Err(VertexShaderInterfaceError::OutputFieldCannotHaveSeveralIdentifiers(i, field.clone()));
            }

            outputs.push(vertex_shader_output_field_to_ext_decl(&field));
          }

          Ok(outputs)
        }
        _ => Err(VertexShaderInterfaceError::OutputTypeMustBeAStruct(ty.clone()))
      }
    }
    _ => Err(VertexShaderInterfaceError::OutputTypeMustBeAStruct(ty.clone()))
  }
}

fn vertex_shader_output_field_to_ext_decl(field: &StructFieldSpecifier) -> ExternalDeclaration {
  let fsty = FullySpecifiedType {
    qualifier: field.qualifier.clone(),
    ty: field.ty.clone()
  };
  let decl = SingleDeclaration {
    ty: fsty,
    name: Some(field.identifiers[0].0.clone()),
    array_specifier: field.identifiers[0].1.clone(),
    initializer: None
  };

  ExternalDeclaration::Declaration(
    Declaration::InitDeclaratorList(
      InitDeclaratorList {
        head: decl,
        tail: Vec::new()
      }
    )
  )
}

/// Class of errors that can happen in dependencies.
#[derive(Clone, Debug, PartialEq)]
pub enum DepsError {
  /// If a module’s dependencies has any cycle, the dependencies are unusable and the cycle is
  /// returned.
  Cycle(ModuleKey, ModuleKey),
  /// There was a loading error of a module.
  LoadError(ModuleKey)
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ModuleKey(String);

impl ModuleKey {
  pub fn new(key: &str) -> Self {
    ModuleKey(key.to_owned())
  }
}

impl CacheKey for ModuleKey {
  type Target = Module;
}

impl StoreKey for ModuleKey {
  fn key_to_path(&self) -> PathBuf {
    PathBuf::from(self.0.replace(".", "/") + ".spsl")
  }
}

impl Load for Module {
  fn load<K>(key: &K, _: &mut Store) -> Result<LoadResult<Self>, LoadError> where K: StoreKey<Target = Self> {
    let path = key.key_to_path();

    let mut fh = File::open(&path).map_err(|_| LoadError::FileNotFound(path.into()))?;
    let mut src = String::new();
    let _ = fh.read_to_string(&mut src);

    match parser::parse_str(&src[..], parser::module) {
      parser::ParseResult::Ok(module) => {
        Ok(Module(module).into())
      }
      parser::ParseResult::Err(e) => Err(LoadError::ConversionFailed(format!("{:?}", e))),
      _ => Err(LoadError::ConversionFailed("incomplete input".to_owned()))
    }
  }
}

<commit_msg>Ça fait le café.<commit_after>//! Shader module.
//!
//! Shader functions and declarations can be grouped in so-called *modules*. Modules structure is
//! inherently tied to the filesystem’s tree.
//!
//! You’re not supposed to use modules at the Rust level, even though you can. You’re supposed to
//! actually write modules that will be used by shader programs.

use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

use render::shader::lang::parser;
// FIXME: qualified use, it’s ugly now
use render::shader::lang::syntax::{Declaration, ExternalDeclaration, FunctionDefinition, FullySpecifiedType,
                                   FunctionParameterDeclaration, InitDeclaratorList, Expr,
                                   Module as SyntaxModule, SingleDeclaration, StorageQualifier,
                                   StructSpecifier, StructFieldSpecifier, LayoutQualifier,
                                   TypeSpecifier, TypeQualifier, TypeQualifierSpec, LayoutQualifierSpec};
use sys::resource::{CacheKey, Load, LoadError, LoadResult, Store, StoreKey};

/// Shader module.
///
/// A shader module is a piece of GLSL code with optional import lists (dependencies).
///
/// You’re not supposed to directly manipulate any object of this type. You just write modules on
/// disk and let everyting happen automatically for you.
#[derive(Clone, Debug, PartialEq)]
pub struct Module(pub SyntaxModule); // FIXME: remove the pub

impl Module {
  /// Retrieve all the modules this module depends on, without duplicates.
  pub fn deps(&self, store: &mut Store, key: &ModuleKey) -> Result<Vec<ModuleKey>, DepsError> {
    let mut deps = Vec::new();
    self.deps_no_cycle(store, &key, &mut Vec::new(), &mut deps).map(|_| deps)
  }

  fn deps_no_cycle(&self, store: &mut Store, key: &ModuleKey, parents: &mut Vec<ModuleKey>, deps: &mut Vec<ModuleKey>) -> Result<(), DepsError> {
    let imports = self.0.imports.iter().map(|il| &il.module);

    parents.push(key.clone());

    for module_path in imports {
      let module_key = ModuleKey(module_path.path.join("."));

      // check whether it’s already in the deps
      if deps.contains(&module_key) {
        continue;
      }

      // check whether the module was already visited
      if parents.contains(&module_key) {
        return Err(DepsError::Cycle(module_key.clone(), module_key.clone()));
      }

      // get the dependency module
      let module = store.get(&module_key).ok_or_else(|| DepsError::LoadError(module_key.clone()))?;
      module.borrow().deps_no_cycle(store, &module_key, parents, deps)?;

      deps.push(module_key.clone());
      parents.pop();
    }

    Ok(())
  }

  /// Fold a module and its dependencies into a single module. The list of dependencies is also
  /// returned.
  pub fn gather(&self, store: &mut Store, k: &ModuleKey) -> Result<(Self, Vec<ModuleKey>), DepsError> {
    let deps = self.deps(store, k)?;
    let glsl =
      deps.iter()
          .flat_map(|kd| {
              let m = store.get(kd).unwrap();
              let g = m.borrow().0.glsl.clone();
              g
            })
          .chain(self.0.glsl.clone())
          .collect();

    let module = Module(SyntaxModule {
      imports: Vec::new(),
      glsl
    });

    Ok((module, deps))
  }

  /// Get all the uniforms defined in a module.
  pub fn uniforms(&self) -> Vec<SingleDeclaration> {
    let mut uniforms = Vec::new();

    for glsl in &self.0.glsl {
      if let ExternalDeclaration::Declaration(Declaration::InitDeclaratorList(ref i)) = *glsl {
        if let Some(ref q) = i.head.ty.qualifier {
          if q.qualifiers.contains(&TypeQualifierSpec::Storage(StorageQualifier::Uniform)) {
            uniforms.push(i.head.clone());

            // check whether we have more
            for next in &i.tail {
              uniforms.push(SingleDeclaration {
                ty: i.head.ty.clone(),
                name: Some(next.name.clone()),
                array_specifier: next.array_specifier.clone(),
                initializer: None
              })
            }
          }
        }
      }
    }

    uniforms
  }

  /// Get all the functions.
  pub fn functions(&self) -> Vec<FunctionDefinition> {
    self.0.glsl.iter().filter_map(|ed| match *ed {
      ExternalDeclaration::FunctionDefinition(ref def) => Some(def.clone()),
      _ => None
    }).collect()
  }

  /// Get all the declared structures.
  pub fn structs(&self) -> Vec<StructSpecifier> {
    self.0.glsl.iter().filter_map(|ed| {
      match *ed {
        ExternalDeclaration::Declaration(
          Declaration::InitDeclaratorList(
            InitDeclaratorList {
              head: SingleDeclaration {
                ty: FullySpecifiedType {
                  ty: TypeSpecifier::Struct(ref s),
                  ..
                },
                ..
              },
              ..
            }
          )
        ) => Some(s.clone()),
        _ => None
      }
    }).collect()
  }
}

/// Vertex shader I/O interface.
///
/// It contains the inputs and the outputs to the next stage.
#[derive(Clone, Debug, PartialEq)]
pub struct VertexShaderInterface {
  inputs: Vec<ExternalDeclaration>,
  outputs: Vec<ExternalDeclaration>
}

#[derive(Clone, Debug, PartialEq)]
pub enum VertexShaderInterfaceError {
  UnnamedInput,
  OutputHasMainQualifier,
  OutputTypeMustBeAStruct(TypeSpecifier),
  WrongOutputFirstField(StructFieldSpecifier),
  OutputFieldCannotBeStruct(usize, TypeSpecifier),
  OutputFieldCannotHaveSeveralIdentifiers(usize, StructFieldSpecifier)
}

/// Build the vertex shader interface from a function definition.
pub fn vertex_shader_interface(fun_def: &FunctionDefinition, structs: &[StructSpecifier]) -> Result<VertexShaderInterface, VertexShaderInterfaceError> {
  let proto = &fun_def.prototype;
  let inputs = vertex_shader_inputs(proto.parameters.iter())?;
  let outputs = vertex_shader_outputs(&proto.ty, structs)?;

  Ok(VertexShaderInterface { inputs, outputs })
}

fn vertex_shader_inputs<'a, I>(args: I) -> Result<Vec<ExternalDeclaration>, VertexShaderInterfaceError> where I: IntoIterator<Item = &'a FunctionParameterDeclaration> {
  let mut inputs = Vec::new();

  for (i, arg) in args.into_iter().enumerate() {
    match *arg {
      FunctionParameterDeclaration::Unnamed(..) => return Err(VertexShaderInterfaceError::UnnamedInput),
      FunctionParameterDeclaration::Named(ref ty_qual, ref decl) => {
        let layout_qualifier = LayoutQualifier {
          ids: vec![LayoutQualifierSpec::Identifier("location".to_owned(), Some(Box::new(Expr::IntConst(i as i32))))]
        };
        let base_qualifier = TypeQualifier {
          qualifiers: vec![
            TypeQualifierSpec::Layout(layout_qualifier),
            TypeQualifierSpec::Storage(StorageQualifier::Uniform)
          ]
        };
        let qualifier = match *ty_qual {
          Some(ref qual) => TypeQualifier { qualifiers: base_qualifier.qualifiers.into_iter().chain(qual.clone().qualifiers).collect() },
          None => base_qualifier
        };
        let ty = decl.ty.clone();
        let name = Some(decl.name.clone());
        let array_spec = decl.array_spec.clone();
        let idl = InitDeclaratorList {
          head: SingleDeclaration {
            ty: FullySpecifiedType {
              qualifier: Some(qualifier),
              ty
            },
            name,
            array_specifier: array_spec,
            initializer: None
          },
          tail: Vec::new()
        };
        let ed = ExternalDeclaration::Declaration(Declaration::InitDeclaratorList(idl));

        inputs.push(ed);
      }
    }
  }

  Ok(inputs)
}

fn vertex_shader_outputs(fsty: &FullySpecifiedType, structs: &[StructSpecifier]) -> Result<Vec<ExternalDeclaration>, VertexShaderInterfaceError> {
  // we refuse that the output has a main qualifier
  if fsty.qualifier.is_some() {
    return Err(VertexShaderInterfaceError::OutputHasMainQualifier);
  }

  let ty = &fsty.ty;

  // we enforce that the output must be a struct that follows a certain pattern
  match *ty {
    TypeSpecifier::TypeName(ref ty_name) => {
      let real_ty = structs.iter().find(|ref s| s.name.as_ref() == Some(ty_name));

      match real_ty {
        Some(ref s) => {
          // the first field must be named "gl_Position", has type vec4 and no qualifier
          let first_field = &s.fields[0];

          if first_field.qualifier.is_some() ||
             first_field.ty != TypeSpecifier::Vec4 ||
             first_field.identifiers != vec![("gl_Position".to_owned(), None)] {
            return Err(VertexShaderInterfaceError::WrongOutputFirstField(first_field.clone()));
          }

          // then, for all other fields, we check that they are not composite type (i.e. structs); if
          // they are not, add them to the interface; otherwise, fail
          let mut outputs = Vec::new();

          for (i, field) in (&s.fields[1..]).into_iter().enumerate() {
            if let TypeSpecifier::Struct(_) = field.ty {
              return Err(VertexShaderInterfaceError::OutputFieldCannotBeStruct(i, field.ty.clone()));
            }

            if field.identifiers.len() > 1 {
              return Err(VertexShaderInterfaceError::OutputFieldCannotHaveSeveralIdentifiers(i, field.clone()));
            }

            outputs.push(vertex_shader_output_field_to_ext_decl(&field));
          }

          Ok(outputs)
        }
        _ => Err(VertexShaderInterfaceError::OutputTypeMustBeAStruct(ty.clone()))
      }
    }
    _ => Err(VertexShaderInterfaceError::OutputTypeMustBeAStruct(ty.clone()))
  }
}

fn vertex_shader_output_field_to_ext_decl(field: &StructFieldSpecifier) -> ExternalDeclaration {
  let fsty = FullySpecifiedType {
    qualifier: field.qualifier.clone(),
    ty: field.ty.clone()
  };
  let decl = SingleDeclaration {
    ty: fsty,
    name: Some(field.identifiers[0].0.clone()),
    array_specifier: field.identifiers[0].1.clone(),
    initializer: None
  };

  ExternalDeclaration::Declaration(
    Declaration::InitDeclaratorList(
      InitDeclaratorList {
        head: decl,
        tail: Vec::new()
      }
    )
  )
}

/// Class of errors that can happen in dependencies.
#[derive(Clone, Debug, PartialEq)]
pub enum DepsError {
  /// If a module’s dependencies has any cycle, the dependencies are unusable and the cycle is
  /// returned.
  Cycle(ModuleKey, ModuleKey),
  /// There was a loading error of a module.
  LoadError(ModuleKey)
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ModuleKey(String);

impl ModuleKey {
  pub fn new(key: &str) -> Self {
    ModuleKey(key.to_owned())
  }
}

impl CacheKey for ModuleKey {
  type Target = Module;
}

impl StoreKey for ModuleKey {
  fn key_to_path(&self) -> PathBuf {
    PathBuf::from(self.0.replace(".", "/") + ".spsl")
  }
}

impl Load for Module {
  fn load<K>(key: &K, _: &mut Store) -> Result<LoadResult<Self>, LoadError> where K: StoreKey<Target = Self> {
    let path = key.key_to_path();

    let mut fh = File::open(&path).map_err(|_| LoadError::FileNotFound(path.into()))?;
    let mut src = String::new();
    let _ = fh.read_to_string(&mut src);

    match parser::parse_str(&src[..], parser::module) {
      parser::ParseResult::Ok(module) => {
        Ok(Module(module).into())
      }
      parser::ParseResult::Err(e) => Err(LoadError::ConversionFailed(format!("{:?}", e))),
      _ => Err(LoadError::ConversionFailed("incomplete input".to_owned()))
    }
  }
}

<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error;
use std::fmt;
use std::io;
use std::sync::Mutex;
use std::time::{Duration, Instant};
use std::sync::atomic::{AtomicBool, Ordering};
use std::net::{ToSocketAddrs, SocketAddr, UdpSocket};

use cadence::prelude::*;
use cadence::{MetricSink, MetricResult, ErrorKind};

#[macro_use]
pub mod macros;

static mut CLIENT: Option<*const Metric> = None;
// IS_INITIALIZED indicates the state of CLIENT,
// `false` for uninitialized, `true` for initialized.
static IS_INITIALIZED: AtomicBool = AtomicBool::new(false);

pub trait Metric: Counted + Gauged + Metered + Timed {}

impl<T: Counted + Gauged + Metered + Timed> Metric for T {}

/// The type returned by `set_metric_client` if `set_metric_client` has already been called.
#[derive(Debug)]
pub struct SetMetricError;

impl fmt::Display for SetMetricError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt,
               "attempted to set a metric client after the metric system was already initialized")
    }
}

impl error::Error for SetMetricError {
    fn description(&self) -> &str {
        "set_metric_client() called multiple times"
    }
}

pub fn set_metric_client(client: Box<Metric + Send + Sync>) -> Result<(), SetMetricError> {
    unsafe {
        if IS_INITIALIZED.compare_and_swap(false, true, Ordering::SeqCst) != false {
            return Err(SetMetricError);
        }

        CLIENT = Some(Box::into_raw(client));
        Ok(())
    }
}

#[doc(hidden)]
pub fn client() -> Option<&'static Metric> {
    if IS_INITIALIZED.load(Ordering::SeqCst) != true {
        return None;
    }

    unsafe { CLIENT.map(|c| &*c) }
}

static BUFFER_SIZE: usize = 1024;

pub struct BufferedUdpMetricSink {
    sink_addr: SocketAddr,
    socket: UdpSocket,

    buffer: Mutex<Vec<u8>>,
    last_flush_time: Mutex<Instant>,
    flush_period: Duration,
}

impl BufferedUdpMetricSink {
    pub fn from<A>(sink_addr: A,
                   socket: UdpSocket,
                   flush_period: Duration)
                   -> MetricResult<BufferedUdpMetricSink>
        where A: ToSocketAddrs
    {
        let mut addr_iter = try!(sink_addr.to_socket_addrs());
        let addr = try!(addr_iter.next()
            .ok_or((ErrorKind::InvalidInput, "No socket addresses yielded")));

        // Moves this UDP stream into nonblocking mode.
        try!(socket.set_nonblocking(true));

        Ok(BufferedUdpMetricSink {
            sink_addr: addr,
            socket: socket,

            buffer: Mutex::new(Vec::with_capacity(BUFFER_SIZE)),
            flush_period: flush_period,
            last_flush_time: Mutex::new(Instant::now()),
        })
    }

    fn append_to_buffer(&self, metric: &str) -> io::Result<usize> {
        let mut buffer = self.buffer.lock().unwrap();
        let mut last_flush_time = self.last_flush_time.lock().unwrap();

        // +1 for '\n'
        if (buffer.len() + metric.len() + 1) > buffer.capacity() ||
           (last_flush_time.elapsed() >= self.flush_period) {
            self.flush(&mut buffer);
            *last_flush_time = Instant::now();
        }

        buffer.extend_from_slice(metric.as_bytes());
        buffer.push('\n' as u8);
        Ok(metric.len())
    }

    fn flush(&self, buffer: &mut Vec<u8>) {
        if let Err(e) = self.socket.send_to(buffer.as_slice(), &self.sink_addr) {
            warn!("send metric failed {:?}", e);
        }

        buffer.clear();
    }
}

impl MetricSink for BufferedUdpMetricSink {
    fn emit(&self, metric: &str) -> io::Result<usize> {
        self.append_to_buffer(metric)
    }
}
<commit_msg>metric: make clippy happy. (#775)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error;
use std::fmt;
use std::io;
use std::sync::Mutex;
use std::time::{Duration, Instant};
use std::sync::atomic::{AtomicBool, Ordering};
use std::net::{ToSocketAddrs, SocketAddr, UdpSocket};

use cadence::prelude::*;
use cadence::{MetricSink, MetricResult, ErrorKind};

#[macro_use]
pub mod macros;

static mut CLIENT: Option<*const Metric> = None;
// IS_INITIALIZED indicates the state of CLIENT,
// `false` for uninitialized, `true` for initialized.
static IS_INITIALIZED: AtomicBool = AtomicBool::new(false);

pub trait Metric: Counted + Gauged + Metered + Timed {}

impl<T: Counted + Gauged + Metered + Timed> Metric for T {}

/// The type returned by `set_metric_client` if `set_metric_client` has already been called.
#[derive(Debug)]
pub struct SetMetricError;

impl fmt::Display for SetMetricError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt,
               "attempted to set a metric client after the metric system was already initialized")
    }
}

impl error::Error for SetMetricError {
    fn description(&self) -> &str {
        "set_metric_client() called multiple times"
    }
}

pub fn set_metric_client(client: Box<Metric + Send + Sync>) -> Result<(), SetMetricError> {
    unsafe {
        if IS_INITIALIZED.compare_and_swap(false, true, Ordering::SeqCst) != false {
            return Err(SetMetricError);
        }

        CLIENT = Some(Box::into_raw(client));
        Ok(())
    }
}

#[doc(hidden)]
pub fn client() -> Option<&'static Metric> {
    if IS_INITIALIZED.load(Ordering::SeqCst) != true {
        return None;
    }

    unsafe { CLIENT.map(|c| &*c) }
}

static BUFFER_SIZE: usize = 1024;

pub struct BufferedUdpMetricSink {
    sink_addr: SocketAddr,
    socket: UdpSocket,

    buffer: Mutex<Vec<u8>>,
    last_flush_time: Mutex<Instant>,
    flush_period: Duration,
}

impl BufferedUdpMetricSink {
    pub fn from<A>(sink_addr: A,
                   socket: UdpSocket,
                   flush_period: Duration)
                   -> MetricResult<BufferedUdpMetricSink>
        where A: ToSocketAddrs
    {
        let mut addr_iter = try!(sink_addr.to_socket_addrs());
        let addr = try!(addr_iter.next()
            .ok_or((ErrorKind::InvalidInput, "No socket addresses yielded")));

        // Moves this UDP stream into nonblocking mode.
        try!(socket.set_nonblocking(true));

        Ok(BufferedUdpMetricSink {
            sink_addr: addr,
            socket: socket,

            buffer: Mutex::new(Vec::with_capacity(BUFFER_SIZE)),
            flush_period: flush_period,
            last_flush_time: Mutex::new(Instant::now()),
        })
    }

    fn append_to_buffer(&self, metric: &str) -> io::Result<usize> {
        let mut buffer = self.buffer.lock().unwrap();
        let mut last_flush_time = self.last_flush_time.lock().unwrap();

        // +1 for '\n'
        if (buffer.len() + metric.len() + 1) > buffer.capacity() ||
           (last_flush_time.elapsed() >= self.flush_period) {
            self.flush(&mut buffer);
            *last_flush_time = Instant::now();
        }

        buffer.extend_from_slice(metric.as_bytes());
        buffer.push(b'\n');
        Ok(metric.len())
    }

    fn flush(&self, buffer: &mut Vec<u8>) {
        if let Err(e) = self.socket.send_to(buffer.as_slice(), &self.sink_addr) {
            warn!("send metric failed {:?}", e);
        }

        buffer.clear();
    }
}

impl MetricSink for BufferedUdpMetricSink {
    fn emit(&self, metric: &str) -> io::Result<usize> {
        self.append_to_buffer(metric)
    }
}
<|endoftext|>


<commit_before>use evaluator::Evaluator;
use event::Event;
use top_level_event::TopLevelEvent;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use std::collections::HashMap;

pub struct VariableMapper<I> {
    tokenizer: I,
    variables: HashMap<String, String>,
}

impl<I> VariableMapper<I> {
    pub fn new(tokenizer: I) -> VariableMapper<I> {
        VariableMapper {
            tokenizer: tokenizer,
            variables: HashMap::new(),
        }
    }

    fn replace_children_in_scope<'b>(&self, children: Vec<Event<'b>>, starting_variables: &HashMap<String, String>) -> Vec<Event<'b>> {
        let mut local_variables = starting_variables.clone();

        children.into_iter().filter_map(|c|
            match c {
                Event::Variable(SassVariable { name, value }) => {
                    let val = Evaluator::new_from_string(&value, &local_variables).evaluate().to_string();
                    local_variables.insert((*name).to_string(), val);
                    None
                },
                Event::Property(name, value) => {
                    Some(Event::Property(name, Evaluator::new_from_string(&value, &local_variables).evaluate().to_string().into()))
                },
                Event::ChildRule(rule) => {
                    Some(Event::ChildRule(SassRule {
                        children: self.replace_children_in_scope(rule.children, &local_variables), ..rule
                    }))
                },
                other => Some(other)
            }
        ).collect::<Vec<_>>()
    }
}

impl<'a, I> Iterator for VariableMapper<I>
    where I: Iterator<Item = TopLevelEvent<'a>>
{
    type Item = TopLevelEvent<'a>;

    fn next(&mut self) -> Option<TopLevelEvent<'a>> {
        match self.tokenizer.next() {
            Some(TopLevelEvent::Variable(SassVariable { name, value })) => {
                let val = Evaluator::new_from_string(&value, &self.variables).evaluate().to_string();
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(TopLevelEvent::Rule(sass_rule)) => {
                Some(TopLevelEvent::Rule(SassRule {
                    children: self.replace_children_in_scope(sass_rule.children, &self.variables), ..sass_rule
                }))
            },
            other => other,
        }
    }
}
<commit_msg>rearranging<commit_after>use evaluator::Evaluator;
use event::Event;
use top_level_event::TopLevelEvent;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use std::collections::HashMap;

pub struct VariableMapper<I> {
    tokenizer: I,
    variables: HashMap<String, String>,
}

impl<I> VariableMapper<I> {
    pub fn new(tokenizer: I) -> VariableMapper<I> {
        VariableMapper {
            tokenizer: tokenizer,
            variables: HashMap::new(),
        }
    }

    fn replace_children_in_scope<'b>(&self, children: Vec<Event<'b>>, mut local_variables: HashMap<String, String>) -> Vec<Event<'b>> {
        children.into_iter().filter_map(|c|
            match c {
                Event::Variable(SassVariable { name, value }) => {
                    let val = Evaluator::new_from_string(
                        &value, &local_variables
                    ).evaluate().to_string();
                    local_variables.insert((*name).to_string(), val);
                    None
                },
                Event::Property(name, value) => {
                    Some(Event::Property(
                        name,
                        Evaluator::new_from_string(
                            &value, &local_variables
                        ).evaluate().to_string().into()
                    ))
                },
                Event::ChildRule(rule) => {
                    Some(Event::ChildRule(SassRule {
                        children: self.replace_children_in_scope(
                            rule.children, local_variables.clone()
                        ), ..rule
                    }))
                },
                other => Some(other)
            }
        ).collect::<Vec<_>>()
    }
}

impl<'a, I> Iterator for VariableMapper<I>
    where I: Iterator<Item = TopLevelEvent<'a>>
{
    type Item = TopLevelEvent<'a>;

    fn next(&mut self) -> Option<TopLevelEvent<'a>> {
        match self.tokenizer.next() {
            Some(TopLevelEvent::Variable(SassVariable { name, value })) => {
                let val = Evaluator::new_from_string(
                    &value, &self.variables
                ).evaluate().to_string();
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(TopLevelEvent::Rule(sass_rule)) => {
                Some(TopLevelEvent::Rule(SassRule {
                    children: self.replace_children_in_scope(
                        sass_rule.children, self.variables.clone()
                    ), ..sass_rule
                }))
            },
            other => other,
        }
    }
}
<|endoftext|>


<commit_before>use svm::cell::SVMCell;

use self::ExprNode::*;
use self::NumNode::*;
use super::ForkTable;
/// The symbol table for bound names is represented as a
/// `ForkTable` mapping `&str` (names) to `(uint,uint)` tuples,
/// representing the location in the `$e` stack storing the value
/// bound to that name.
pub type SymTable<'a>   = ForkTable<'a, &'a str, (usize,usize)>;
/// A `CompileResult` is either `Ok(SVMCell)` or `Err(&str)`.
pub type CompileResult  = Result<SVMCell, &'static str>;

static INDENT: &'static str = "\t";

/// Trait for AST nodes.
pub trait ASTNode {
    /// Compile this node to a list of SVM expressions
    fn compile(self, state: SymTable)   -> CompileResult;

    /// Pretty-print this node
    fn prettyprint(&self)               -> String { self.print_level(0usize) }

    /// Pretty-print this node at the desired indent level
    fn print_level(&self, level: usize) -> String;
}

/// Expression
///
/// All Seax Scheme expressions are one of the following
///
///  + Nested S-Expressions
///  + Identifiers
///  + Lists
///  + Numbers
///     - signed int
///     - unsigned int
///     - floating-point
///  + Characters
///  + Strings
///
///  TODO: implement the entire Scheme 'numeric tower'
///  TODO: macros should happen
///  TODO: figure out quasiquote somehow.
#[derive(Clone, PartialEq,Debug)]
pub enum ExprNode {
    Root(RootNode),
    SExpr(SExprNode),
    Name(NameNode),
    ListConst(ListNode),
    NumConst(NumNode),
    BoolConst(BoolNode),
    StringConst(StringNode),
    CharConst(CharNode),
}

impl ASTNode for ExprNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        match self {
            //  TODO: should some of these nodes cause a state fork?
            Root(node)          => node.compile(state),
            SExpr(node)         => node.compile(state),
            Name(node)          => node.compile(state),
            ListConst(node)     => node.compile(state),
            NumConst(node)      => node.compile(state),
            BoolConst(node)     => node.compile(state),
            CharConst(node)     => node.compile(state),
            StringConst(node)   => node.compile(state)
        }
    }

    fn print_level(&self, level: usize) -> String {
        match *self {
            Root(ref node)          => node.print_level(level),
            SExpr(ref node)         => node.print_level(level),
            Name(ref node)          => node.print_level(level),
            ListConst(ref node)     => node.print_level(level),
            NumConst(ref node)      => node.print_level(level),
            BoolConst(ref node)     => node.print_level(level),
            CharConst(ref node)     => node.print_level(level),
            StringConst(ref node)   => node.print_level(level)
        }
    }
}

#[derive(Clone, PartialEq,Debug)]
pub enum NumNode {
    IntConst(IntNode),
    UIntConst(UIntNode),
    FloatConst(FloatNode)
}

/// AST node for the root of a program's AST
#[derive(Clone, PartialEq,Debug)]
pub struct RootNode { pub exprs: Vec<ExprNode> }

impl ASTNode for RootNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        self.exprs
            .iter()
            .fold(
                String::new(),
                |mut s, i| {
                    s.push_str(i.print_level(level + 1).as_ref());
                    s
                })
    }

}

/// AST node for an S-expression.
///
/// This includes function application, assignment,
/// function definition, et cetera...Scheme is not a complexl anguage.
#[derive(Clone, PartialEq,Debug)]
pub struct SExprNode {
    pub operator: NameNode,
    pub operands: Vec<ExprNode>,
}

impl ASTNode for SExprNode {

    fn compile(self,state: SymTable)    -> CompileResult {
        Err("UNINPLEMENTED")
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level { tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("S-Expression:\n");
        tab.push_str(INDENT);

        // op
        result.push_str(tab.as_ref());
        result.push_str("Operator:\n");
        result.push_str(self.operator.print_level(level + 1).as_ref());
        result.push('\n');

        for operand in self.operands.iter() {
            result.push_str(tab.as_ref());
            result.push_str("Operand: \n");
            result.push_str(operand.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for a list literal
#[derive(Clone, PartialEq,Debug)]
pub struct ListNode { pub elements: Vec<ExprNode> }

impl ASTNode for ListNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("List:\n");
        tab.push_str(INDENT);

        for elem in self.elements.iter() {
            result.push_str(tab.as_ref());
            result.push_str(elem.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for an identifier
#[derive(Clone, PartialEq,Debug)]
pub struct NameNode { pub name: String }

impl AsRef<str> for NameNode {

    /// Converts the `String` value of this node to a `&str` reference.
    ///
    /// # Examples:
    /// ```
    /// # use seax_scheme::ast::NameNode;
    /// let node = NameNode { name: "a string".to_string() };
    /// assert_eq!(node.as_ref(), "a string")
    /// ```
    fn as_ref(&self) -> &str {
        self.name.as_ref()
    }
}

impl ASTNode for NameNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT)};

        let mut result = String::new();
        result.push_str(tab.as_ref());
        result.push_str("Name: ");
        result.push_str(self.name.as_ref());
        result.push_str("\n");

        result
    }

}

/// AST node for an integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct IntNode { pub value: isize }

impl ASTNode for NumNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Number: ");

        match *self {
            NumNode::UIntConst(ref node) => {
                result.push_str(format!("{}u", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::IntConst(ref node) => {
                result.push_str(format!("{}", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::FloatConst(ref node) => {
                result.push_str(format!("{}f", node.value).as_ref());
                result.push_str("\n");
            }
        }
        result
    }
}

/// AST node for an unsigned integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct UIntNode { pub value: usize }

/// AST node for a floating-point constant
#[derive(Clone, PartialEq,Debug)]
pub struct FloatNode { pub value: f64 }

/// AST node for a boolean constant
#[derive(Clone, PartialEq,Debug)]
pub struct BoolNode { pub value: bool }

impl ASTNode for BoolNode {

    fn compile(self,state: SymTable)    -> CompileResult {
        Err("UNINPLEMENTED")
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Boolean: ");
        result.push_str(format!("{}", self.value).as_ref());
        result.push_str("\n");
        result
    }
}

/// AST node for a character constant
#[derive(Clone, PartialEq,Debug)]
pub struct CharNode { pub value: char }

impl ASTNode for CharNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("Character: \'");
        result.push(self.value);
        result.push_str("\'\n");
        result
    }
}

/// AST node for a  string constant
#[derive(Clone, PartialEq,Debug)]
pub struct StringNode { pub value: String }

impl ASTNode for StringNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("String: \"");
        result.push_str(self.value.as_ref());
        result.push_str("\"\n");
        result
    }
}

<commit_msg>Start on S-Expression codegen<commit_after>use svm::cell::SVMCell;

use self::ExprNode::*;
use self::NumNode::*;
use super::ForkTable;
/// The symbol table for bound names is represented as a
/// `ForkTable` mapping `&str` (names) to `(uint,uint)` tuples,
/// representing the location in the `$e` stack storing the value
/// bound to that name.
pub type SymTable<'a>   = ForkTable<'a, &'a str, (usize,usize)>;
/// A `CompileResult` is either `Ok(SVMCell)` or `Err(&str)`.
pub type CompileResult  = Result<SVMCell, &'static str>;

static INDENT: &'static str = "\t";

/// Trait for AST nodes.
pub trait ASTNode {
    /// Compile this node to a list of SVM expressions
    fn compile(self, state: SymTable)   -> CompileResult;

    /// Pretty-print this node
    fn prettyprint(&self)               -> String { self.print_level(0usize) }

    /// Pretty-print this node at the desired indent level
    fn print_level(&self, level: usize) -> String;
}

/// Expression
///
/// All Seax Scheme expressions are one of the following
///
///  + Nested S-Expressions
///  + Identifiers
///  + Lists
///  + Numbers
///     - signed int
///     - unsigned int
///     - floating-point
///  + Characters
///  + Strings
///
///  TODO: implement the entire Scheme 'numeric tower'
///  TODO: macros should happen
///  TODO: figure out quasiquote somehow.
#[derive(Clone, PartialEq,Debug)]
pub enum ExprNode {
    Root(RootNode),
    SExpr(SExprNode),
    Name(NameNode),
    ListConst(ListNode),
    NumConst(NumNode),
    BoolConst(BoolNode),
    StringConst(StringNode),
    CharConst(CharNode),
}

impl ASTNode for ExprNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        match self {
            //  TODO: should some of these nodes cause a state fork?
            Root(node)          => node.compile(state),
            SExpr(node)         => node.compile(state),
            Name(node)          => node.compile(state),
            ListConst(node)     => node.compile(state),
            NumConst(node)      => node.compile(state),
            BoolConst(node)     => node.compile(state),
            CharConst(node)     => node.compile(state),
            StringConst(node)   => node.compile(state)
        }
    }

    fn print_level(&self, level: usize) -> String {
        match *self {
            Root(ref node)          => node.print_level(level),
            SExpr(ref node)         => node.print_level(level),
            Name(ref node)          => node.print_level(level),
            ListConst(ref node)     => node.print_level(level),
            NumConst(ref node)      => node.print_level(level),
            BoolConst(ref node)     => node.print_level(level),
            CharConst(ref node)     => node.print_level(level),
            StringConst(ref node)   => node.print_level(level)
        }
    }
}

#[derive(Clone, PartialEq,Debug)]
pub enum NumNode {
    IntConst(IntNode),
    UIntConst(UIntNode),
    FloatConst(FloatNode)
}

/// AST node for the root of a program's AST
#[derive(Clone, PartialEq,Debug)]
pub struct RootNode { pub exprs: Vec<ExprNode> }

impl ASTNode for RootNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        self.exprs
            .iter()
            .fold(
                String::new(),
                |mut s, i| {
                    s.push_str(i.print_level(level + 1).as_ref());
                    s
                })
    }

}

/// AST node for an S-expression.
///
/// This includes function application, assignment,
/// function definition, et cetera...Scheme is not a complexl anguage.
#[derive(Clone, PartialEq,Debug)]
pub struct SExprNode {
    pub operator: NameNode,
    pub operands: Vec<ExprNode>,
}

impl ASTNode for SExprNode {

    fn compile(self,state: SymTable)    -> CompileResult {
        match self.operator.as_ref() {
            "let" => unimplemented!(),
            name if state.chain_contains_key(&name) => unimplemented!(),
            name => Err(format!("[error] Unknown identifier `{}`", name).as_ref())
        }
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level { tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("S-Expression:\n");
        tab.push_str(INDENT);

        // op
        result.push_str(tab.as_ref());
        result.push_str("Operator:\n");
        result.push_str(self.operator.print_level(level + 1).as_ref());
        result.push('\n');

        for operand in self.operands.iter() {
            result.push_str(tab.as_ref());
            result.push_str("Operand: \n");
            result.push_str(operand.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for a list literal
#[derive(Clone, PartialEq,Debug)]
pub struct ListNode { pub elements: Vec<ExprNode> }

impl ASTNode for ListNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("List:\n");
        tab.push_str(INDENT);

        for elem in self.elements.iter() {
            result.push_str(tab.as_ref());
            result.push_str(elem.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for an identifier
#[derive(Clone, PartialEq,Debug)]
pub struct NameNode { pub name: String }

impl AsRef<str> for NameNode {

    /// Converts the `String` value of this node to a `&str` reference.
    ///
    /// # Examples:
    /// ```
    /// # use seax_scheme::ast::NameNode;
    /// let node = NameNode { name: "a string".to_string() };
    /// assert_eq!(node.as_ref(), "a string")
    /// ```
    fn as_ref(&self) -> &str {
        self.name.as_ref()
    }
}

impl ASTNode for NameNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT)};

        let mut result = String::new();
        result.push_str(tab.as_ref());
        result.push_str("Name: ");
        result.push_str(self.name.as_ref());
        result.push_str("\n");

        result
    }

}

/// AST node for an integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct IntNode { pub value: isize }

impl ASTNode for NumNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Number: ");

        match *self {
            NumNode::UIntConst(ref node) => {
                result.push_str(format!("{}u", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::IntConst(ref node) => {
                result.push_str(format!("{}", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::FloatConst(ref node) => {
                result.push_str(format!("{}f", node.value).as_ref());
                result.push_str("\n");
            }
        }
        result
    }
}

/// AST node for an unsigned integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct UIntNode { pub value: usize }

/// AST node for a floating-point constant
#[derive(Clone, PartialEq,Debug)]
pub struct FloatNode { pub value: f64 }

/// AST node for a boolean constant
#[derive(Clone, PartialEq,Debug)]
pub struct BoolNode { pub value: bool }

impl ASTNode for BoolNode {

    fn compile(self,state: SymTable)    -> CompileResult {
        Err("UNINPLEMENTED")
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Boolean: ");
        result.push_str(format!("{}", self.value).as_ref());
        result.push_str("\n");
        result
    }
}

/// AST node for a character constant
#[derive(Clone, PartialEq,Debug)]
pub struct CharNode { pub value: char }

impl ASTNode for CharNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("Character: \'");
        result.push(self.value);
        result.push_str("\'\n");
        result
    }
}

/// AST node for a  string constant
#[derive(Clone, PartialEq,Debug)]
pub struct StringNode { pub value: String }

impl ASTNode for StringNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("String: \"");
        result.push_str(self.value.as_ref());
        result.push_str("\"\n");
        result
    }
}

<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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 std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Write;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
}

const TEST_REPOS: &'static [Test] = &[Test {
                                          name: "cargo",
                                          repo: "https://github.com/rust-lang/cargo",
                                          sha: "d3bad1ab29efae414e9b4c24534b2d02b3a59782",
                                          lock: None,
                                      },
                                      Test {
                                          name: "iron",
                                          repo: "https://github.com/iron/iron",
                                          sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
                                          lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
                                      }];

fn main() {
    // One of the projects being tested here is Cargo, and when being tested
    // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately
    // `nmake` will read these two environment variables below and try to
    // intepret them. We're likely being run, however, from MSYS `make` which
    // uses the same variables.
    //
    // As a result, to prevent confusion and errors, we remove these variables
    // from our environment to prevent passing MSYS make flags to nmake, causing
    // it to blow up.
    if cfg!(target_env = "msvc") {
        env::remove_var("MAKE");
        env::remove_var("MAKEFLAGS");
    }

    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        File::create(&dir.join("Cargo.lock"))
            .expect("")
            .write_all(lockfile.as_bytes())
            .expect("");
    }
    if !run_cargo_test(cargo, &dir) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git")
                         .arg("init")
                         .arg(&out_dir)
                         .status()
                         .expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                             .arg("fetch")
                             .arg(test.repo)
                             .arg("master")
                             .arg(&format!("--depth={}", depth))
                             .current_dir(&out_dir)
                             .status()
                             .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
                         .arg("reset")
                         .arg(test.sha)
                         .arg("--hard")
                         .current_dir(&out_dir)
                         .status()
                         .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status = Command::new("git")
                     .arg("clean")
                     .arg("-fdx")
                     .current_dir(&out_dir)
                     .status()
                     .unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path) -> bool {
    let status = Command::new(cargo_path)
        .arg("test")
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<commit_msg>Update cargo sha for cargotest<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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 std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Write;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
}

const TEST_REPOS: &'static [Test] = &[Test {
                                          name: "cargo",
                                          repo: "https://github.com/rust-lang/cargo",
                                          sha: "806e3c368a15f618244a3b4e918bf77f9c403fd0",
                                          lock: None,
                                      },
                                      Test {
                                          name: "iron",
                                          repo: "https://github.com/iron/iron",
                                          sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
                                          lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
                                      }];

fn main() {
    // One of the projects being tested here is Cargo, and when being tested
    // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately
    // `nmake` will read these two environment variables below and try to
    // intepret them. We're likely being run, however, from MSYS `make` which
    // uses the same variables.
    //
    // As a result, to prevent confusion and errors, we remove these variables
    // from our environment to prevent passing MSYS make flags to nmake, causing
    // it to blow up.
    if cfg!(target_env = "msvc") {
        env::remove_var("MAKE");
        env::remove_var("MAKEFLAGS");
    }

    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        File::create(&dir.join("Cargo.lock"))
            .expect("")
            .write_all(lockfile.as_bytes())
            .expect("");
    }
    if !run_cargo_test(cargo, &dir) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git")
                         .arg("init")
                         .arg(&out_dir)
                         .status()
                         .expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                             .arg("fetch")
                             .arg(test.repo)
                             .arg("master")
                             .arg(&format!("--depth={}", depth))
                             .current_dir(&out_dir)
                             .status()
                             .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
                         .arg("reset")
                         .arg(test.sha)
                         .arg("--hard")
                         .current_dir(&out_dir)
                         .status()
                         .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status = Command::new("git")
                     .arg("clean")
                     .arg("-fdx")
                     .current_dir(&out_dir)
                     .status()
                     .unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path) -> bool {
    let status = Command::new(cargo_path)
        .arg("test")
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<|endoftext|>


<commit_before>use errors::*;

use rsa::Rsa;

use bignum::OpensslBigNum as BigNum;
use bignum::{BigNumExt, BigNumTrait};

use aes::random_block;

fn find_signature(size: usize, suffix: &[u8]) -> Option<BigNum> {
    let mut prefix = vec![1u8];
    let one = BigNum::from_u32(1);
    let k = 3;
    //The loop does not seem to be necessary. Can I prove why?
    loop {
        let unused_space = size as i32 - 1 - prefix.len() as i32 - suffix.len() as i32;
        if unused_space < 0 {
            return None;
        }
        let fake_block = BigNum::from_bytes_be(&{
            let mut v = prefix.clone();
            v.extend_from_slice(suffix);
            v
        });
        let lower = fake_block.lsh(8 * unused_space as usize);
        let upper = (&fake_block + &one).lsh(8 * unused_space as usize);
        let r = (&upper - &one).root(k).0;
        let power = r.power(k);
        if power >= lower {
            return Some(r);
        }
        prefix.push(255);
    }
}

pub fn run() -> Result<(), Error> {
    //We lose leading zeros during the conversion to BigNum. We therefore omit it from prefix and
    //check that the length of the block is one less than the length of n.
    let bits = 1024;
    let rsa = Rsa::<BigNum>::generate(bits);
    let size = rsa.n().bytes() as usize;
    let hash = random_block(); //We want to forge a signature containing this hash
    let suffix = {
        let mut v = vec![0u8];
        v.extend_from_slice(&hash);
        v
    };

    //Verify the signature by checking that the encrypted block *starts with* (this is the flaw)
    //01 || ff || ff || ... || ff || suffix
    let verify_signature = |signature: &BigNum| -> bool {
        let block = BigNumTrait::to_bytes_be(&rsa.encrypt(signature));
        assert_eq!(block.len(), size - 1);
        if block[0] != 1 {
            return false;
        }
        let mut i = 1;
        while i < block.len() && block[i] == 255 {
            i += 1;
        }
        if i + suffix.len() >= block.len() {
            return false;
        }
        block[i..i + suffix.len()] == suffix[..]
    };

    let fake_signature = find_signature(size, &suffix);
    compare_eq(true, verify_signature(&fake_signature.unwrap()))
}
<commit_msg>Add proof that our solution to challenge 42 always works<commit_after>use errors::*;

use rsa::Rsa;

use bignum::OpensslBigNum as BigNum;
use bignum::{BigNumExt, BigNumTrait};

use sha1;

const BITS: usize = 1024;

struct Server {
    rsa: Rsa<BigNum>
}

fn get_hash(message: &[u8]) -> Vec<u8> {
    let mut sha1 = sha1::Sha1::new();
    sha1.update(message);
    sha1.digest().bytes().to_vec()
}

impl Server {
    fn new() -> Self {
        Server { rsa: Rsa::generate(BITS) }
    }

    fn n(&self) -> &BigNum {
        &self.rsa.n()
    }

    fn verify_signature(&self, message: &[u8], signature: &[u8]) -> bool {
        let rsa = &self.rsa;
        let n = rsa.n();
        let signature_num = &BigNum::from_bytes_be(signature);
        if signature_num >= n {
            return false;
        }

        let plaintext = rsa.encrypt(signature_num).to_bytes_be();

        // Coming from a BigNum, the plaintext does not include any leading zeroes.
        // We therefore check that the length is one less than the length of n.
        if plaintext.len() != n.bytes() - 1 {
            return false;
        }

        // Verify that plaintext *starts with* (this is the flaw)
        // 01 || ff || ff || ... || ff || 00 || hash

        if plaintext[0] != 1 {
            return false;
        }

        let mut i = 1;
        while i < plaintext.len() && plaintext[i] == 255 {
            i += 1;
        }

        if i >= plaintext.len() || plaintext[i] != 0 {
            return false;
        }
        i += 1;

        let hash = get_hash(message);
        if i + hash.len() > plaintext.len() {
            return false;
        }

        plaintext[i..i + hash.len()] == hash[..]
    }

    // Not really required for the exercise
    fn sign_message(&self, message: &[u8]) -> Vec<u8> {
        let hash = get_hash(message);
        let len = self.rsa.n().bytes() - 1;
        let mut plaintext = Vec::with_capacity(len);
        plaintext.push(1);
        for _ in 1..len - 1 - hash.len() {
            plaintext.push(255);
        }
        plaintext.push(0);
        plaintext.extend_from_slice(&hash);
        self.rsa.decrypt(&BigNum::from_bytes_be(&plaintext)).to_bytes_be()
    }
}

 /* We first prove a general observation concerning third roots of natural numbers.
  * Let k = 2^l be a positive natural number which is a power of two.
  * Let x be some positive natural number.
  *
  * Denote by crt the cube root function on positive real numbers. Assume that
  * (1) floor( crt((x + 1)k - 1) ) < crt(xk).
  * As y - 1 < floor(y) for any real number r, we have
  * crt((x + 1)k - 1) < crt(xk) + 1.
  * Taking  the third power yields
  * (x + 1)k - 1 < xk + 3*crt(xk) + 3*crt(xk)^2 + 1,
  * which simplifies to
  * (2) k < 3*crt(xk) + 3*crt(xk)^2 + 2.
  *
  * We now determine an upper bound for the right hand side of (2).
  * As crt(xk) >= 1, we have
  * 3*crt(xk) + 3*crt(xk)^2 + 2 <= 3*crt(xk)^2 + 3*crt(xk)^2 + 2*crt(xk)^2 = 8*crt(xk)^2.
  * Denote by y a natural number such that x <= 2^y. Then
  * 8*crt(xk)^2 <= 2^(2(l + y)/3 + 3).
  *
  * Combining this bound with (2) yields
  * 2^l <= 2^(2(l + y)/3 + 3), or (l - 9)/2 <= y.
  *
  * Reversing the implication, we find that if y < (l - 9)/2, then (1) cannot hold, i.e.
  * (3) floor( crt((x + 1)k - 1) ) >= crt(xk).
  *
  * Finally, note that (3) is equivalent to the existence of a natural number r with
  * xk <= r^3 <= (x + 1)k - 1, as floor( crt((x + 1)k - 1) ) is the biggest natural number
  * r with r^3 <= (x + 1)k - 1.
  *
  * Summarizing: If x <= 2^y for some natural number y < (l - 9)/2, then there is a natural
  * number r with x2^l <= r^3 <= (x + 1)2^l - 1. */

fn forge_signature(len: usize, message: &[u8]) -> Vec<u8> {
    let hash = &get_hash(message);

    /* Search for a plaintext of length `len` of the form
     * (F) 01 || ff || ff || ... || ff || 00 || hash || *
     * which has a third root in the natural numbers.
     *
     * In fact we can always achieve this without any ff bytes in the prefix.
     * Interpret
     * 01 || 00 || hash
     * as a big-endian number x. The length of x in bytes is 2 + hash.len() and we have
     * x <= 2^(8*(2 + hash.len())). Let l = len - 2 - hash.len() be the number
     * of bytes we can fill arbitrarily. Then the numbers of the form (F) above
     * (in big-endian) are precisely the natural numbers between
     * x2^l and (x + 1)2^l - 1. As 8*(2 + hash.len()) is small compared to l, we
     * know by the general observations above that floor( crt((x + 1)k - 1) )
     * is a signature which will fool the server.
     *
     * Note that we can just as easily forge a signature with several ff bytes in the prefix
     * as long as 8*(2 + hash.len() + number of ff bytes) < (l - 9)/2.
     * */

    let x = BigNum::from_bytes_be(&{
        let mut v = Vec::with_capacity(2 + hash.len());
        v.push(1);
        v.push(0);
        v.extend_from_slice(hash);
        v
    });
    let l = len - 2 - hash.len() as usize;
    let _1 = BigNum::from_u32(1);
    let r = (&(&x + &_1).lsh(8 * l) - &_1).root(3).0;
    r.to_bytes_be()
}

pub fn run() -> Result<(), Error> {
    let server = Server::new();
    {
        // Make sure that our server accepts valid signatures
        let message = &b"foo"[..];
        let signature = server.sign_message(message);
        compare_eq(true, server.verify_signature(message, &signature))?;
    }

    // Now we forge a signature for the following message
    let message = &b"hi mom"[..];
    let len = server.n().bytes() - 1;
    let forged_signature = forge_signature(len, message);

    compare_eq(true, server.verify_signature(message, &forged_signature))
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! A tabbed notebook container

use ffi;
use cast::GTK_NOTEBOOK;
use FFIWidget;
use glib::translate::{from_glib_none, ToGlibPtr};
use glib::{to_bool, to_gboolean};

/// GtkNotebook — A tabbed notebook container
struct_Widget!(NoteBook);

impl NoteBook {
    pub fn new() -> Option<NoteBook> {
        let tmp_pointer = unsafe { ffi::gtk_notebook_new() };
        check_pointer!(tmp_pointer, NoteBook)
    }

    pub fn append_page<Child: ::WidgetTrait, TabLabel: ::WidgetTrait>(&self, child: &Child,
            tab_label: Option<&TabLabel>) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_append_page(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label)) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn append_page_menu<Child: ::WidgetTrait, TabLabel: ::WidgetTrait,
            MenuLabel: ::WidgetTrait>(&self, child: &Child, tab_label: Option<&TabLabel>,
            menu_label: Option<&MenuLabel>) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_append_page_menu(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label), unwrap_widget!(menu_label)) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn prepend_page<Child: ::WidgetTrait, TabLabel: ::WidgetTrait>(&self, child: &Child,
            tab_label: Option<&TabLabel>) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_prepend_page(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label)) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn prepend_page_menu<Child: ::WidgetTrait, TabLabel: ::WidgetTrait,
            MenuLabel: ::WidgetTrait>(&self, child: &Child, tab_label: Option<&TabLabel>,
            menu_label: Option<&MenuLabel>) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_prepend_page_menu(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label), unwrap_widget!(menu_label)) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn insert_page<Child: ::WidgetTrait, TabLabel: ::WidgetTrait>(&self, child: &Child,
            tab_label: Option<&TabLabel>, position: i32) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_insert_page(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label), position) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn insert_page_menu<Child: ::WidgetTrait, TabLabel: ::WidgetTrait,
            MenuLabel: ::WidgetTrait>(&self, child: &Child, tab_label: Option<&TabLabel>,
            menu_label: Option<&MenuLabel>, position: i32) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_insert_page_menu(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label), unwrap_widget!(menu_label),
                position) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn remove_page(&self, page_num: i32) {
        unsafe {
            ffi::gtk_notebook_remove_page(GTK_NOTEBOOK(self.pointer), page_num)
        }
    }

    pub fn set_group_name(&self, group_name: &str) {
        unsafe {
            ffi::gtk_notebook_set_group_name(GTK_NOTEBOOK(self.pointer),
                                             group_name.to_glib_none().0)
        }
    }

    pub fn get_group_name(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gtk_notebook_get_group_name(GTK_NOTEBOOK(self.pointer)))
        }
    }

    pub fn get_current_page(&self) -> i32 {
        unsafe {
            ffi::gtk_notebook_get_current_page(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn get_nth_page<T: ::WidgetTrait>(&self, page_num: i32) -> Option<T> {
        let tmp_pointer = unsafe { ffi::gtk_notebook_get_nth_page(GTK_NOTEBOOK(self.pointer), page_num) };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer))
        }
    }

    pub fn get_n_page(&self) -> i32 {
        unsafe {
            ffi::gtk_notebook_get_n_pages(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn page_num<T: ::WidgetTrait>(&self, child: &T) -> i32 {
        unsafe {
            ffi::gtk_notebook_page_num(GTK_NOTEBOOK(self.pointer), child.unwrap_widget())
        }
    }

    pub fn set_current_page(&self, page_num: i32) {
        unsafe {
            ffi::gtk_notebook_set_current_page(GTK_NOTEBOOK(self.pointer), page_num)
        }
    }

    pub fn next_page(&self) {
        unsafe {
            ffi::gtk_notebook_next_page(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn prev_page(&self) {
        unsafe {
            ffi::gtk_notebook_prev_page(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn set_show_border(&self, show_border: bool) {
        unsafe {
            ffi::gtk_notebook_set_show_border(GTK_NOTEBOOK(self.pointer),
                                              to_gboolean(show_border))
        }
    }

    pub fn get_show_border(&self) -> bool {
        unsafe {
            to_bool(ffi::gtk_notebook_get_show_border(GTK_NOTEBOOK(self.pointer)))
        }
    }

    pub fn set_show_tabs(&self, show_tabs: bool) {
        unsafe {
            ffi::gtk_notebook_set_show_tabs(GTK_NOTEBOOK(self.pointer),
                                            to_gboolean(show_tabs))
        }
    }

    pub fn get_show_tabs(&self) -> bool {
        unsafe {
            to_bool(ffi::gtk_notebook_get_show_tabs(GTK_NOTEBOOK(self.pointer)))
        }
    }

    pub fn set_tab_pos(&self, pos: ::PositionType) {
        unsafe {
            ffi::gtk_notebook_set_tab_pos(GTK_NOTEBOOK(self.pointer), pos)
        }
    }

    pub fn get_tab_pos(&self) -> ::PositionType {
        unsafe {
            ffi::gtk_notebook_get_tab_pos(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn set_scrollable(&self, scrollable: bool) {
        unsafe {
            ffi::gtk_notebook_set_scrollable(GTK_NOTEBOOK(self.pointer),
                                             to_gboolean(scrollable))
        }
    }

    pub fn is_scrollable(&self) -> bool {
        unsafe {
            to_bool(ffi::gtk_notebook_get_scrollable(GTK_NOTEBOOK(self.pointer)))
        }
    }

    pub fn get_tab_hborder(&self) -> u16 {
        unsafe {
            ffi::gtk_notebook_get_tab_hborder(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn get_tab_vborder(&self) -> u16 {
        unsafe {
            ffi::gtk_notebook_get_tab_vborder(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn popup_enable(&self) {
        unsafe {
            ffi::gtk_notebook_popup_enable(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn popup_disable(&self) {
        unsafe {
            ffi::gtk_notebook_popup_disable(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn get_tab_label<Child: ::WidgetTrait, TabLabel: ::WidgetTrait>(&self, child: &Child) ->
            Option<TabLabel> {
        let tmp_pointer = unsafe {
            ffi::gtk_notebook_get_tab_label(GTK_NOTEBOOK(self.pointer),
                                            child.unwrap_widget())
        };
        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer))
        }
    }

    pub fn set_tab_label<Child: ::WidgetTrait, TabLabel: ::WidgetTrait>(&self, child: &Child,
            tab_label: Option<&TabLabel>) {
        unsafe {
            ffi::gtk_notebook_set_tab_label(GTK_NOTEBOOK(self.pointer),
                                            child.unwrap_widget(),
                                            unwrap_widget!(tab_label))
        }
    }

    pub fn set_tab_label_text<T: ::WidgetTrait>(&self, child: &T, tab_text: &str) {
        unsafe {
            ffi::gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(self.pointer),
                                                 child.unwrap_widget(),
                                                 tab_text.to_glib_none().0)
        }
    }

    pub fn get_tab_label_text<T: ::WidgetTrait>(&self, child: &T) -> Option<String> {
        unsafe {
            from_glib_none(
                ffi::gtk_notebook_get_tab_label_text(GTK_NOTEBOOK(self.pointer),
                                                     child.unwrap_widget()))
        }
    }

    pub fn get_menu_label<Child: ::WidgetTrait, MenuLabel: ::WidgetTrait>(&self, child: &Child) ->
            Option<MenuLabel> {
        let tmp_pointer = unsafe {
            ffi::gtk_notebook_get_menu_label(GTK_NOTEBOOK(self.pointer),
                                             child.unwrap_widget())
        };
        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer))
        }
    }

    pub fn set_menu_label<Child: ::WidgetTrait, MenuLabel: ::WidgetTrait>(&self, child: &Child,
        menu_label: Option<&MenuLabel>) {
        unsafe {
            ffi::gtk_notebook_set_menu_label(GTK_NOTEBOOK(self.pointer),
                                             child.unwrap_widget(),
                                             unwrap_widget!(menu_label))
        }
    }

    pub fn set_menu_label_text<T: ::WidgetTrait>(&self, child: &T, tab_text: &str) {
        unsafe {
            ffi::gtk_notebook_set_menu_label_text(GTK_NOTEBOOK(self.pointer),
                                                  child.unwrap_widget(),
                                                  tab_text.to_glib_none().0)
        }
    }

    pub fn get_menu_label_text<T: ::WidgetTrait>(&self, child: &T) -> Option<String> {
        unsafe {
            from_glib_none(
                ffi::gtk_notebook_get_menu_label_text(GTK_NOTEBOOK(self.pointer),
                                                              child.unwrap_widget()))
        }
    }

    pub fn reorder_child<T: ::WidgetTrait>(&self, child: &T, position: i32) {
        unsafe {
            ffi::gtk_notebook_reorder_child(GTK_NOTEBOOK(self.pointer),
                                            child.unwrap_widget(),
                                            position)
        }
    }

    pub fn is_tab_reorderable<T: ::WidgetTrait>(&self, child: &T) -> bool {
        unsafe {
            to_bool(ffi::gtk_notebook_get_tab_reorderable(GTK_NOTEBOOK(self.pointer),
                                                               child.unwrap_widget()))
        }
    }

    pub fn set_tab_reorderable<T: ::WidgetTrait>(&self, child: &T, reorderable: bool) {
        unsafe {
            ffi::gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(self.pointer),
                                                 child.unwrap_widget(),
                                                 to_gboolean(reorderable))
        }
    }

    pub fn is_tab_detachable<T: ::WidgetTrait>(&self, child: &T) -> bool {
        unsafe {
            to_bool(ffi::gtk_notebook_get_tab_detachable(GTK_NOTEBOOK(self.pointer),
                                                              child.unwrap_widget()))
        }
    }

    pub fn set_tab_detachable<T: ::WidgetTrait>(&self, child: &T, detachable: bool) {
        unsafe {
            ffi::gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(self.pointer),
                                                child.unwrap_widget(),
                                                to_gboolean(detachable))
        }
    }

    pub fn get_action_widget<T: ::WidgetTrait>(&self, pack_type: ::PackType) -> Option<T> {
        let tmp_pointer = unsafe { ffi::gtk_notebook_get_action_widget(GTK_NOTEBOOK(self.pointer),
                                                                       pack_type) };
        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer))
        }
    }

    pub fn set_action_widget<T: ::WidgetTrait>(&self, child: &T, pack_type: ::PackType) {
        unsafe {
            ffi::gtk_notebook_set_action_widget(GTK_NOTEBOOK(self.pointer),
                                                child.unwrap_widget(),
                                                pack_type)
        }
    }
}

impl_drop!(NoteBook);
impl_TraitWidget!(NoteBook);

impl ::ContainerTrait for NoteBook {}
<commit_msg>Change return type to Option<u32><commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! A tabbed notebook container

use ffi;
use cast::GTK_NOTEBOOK;
use FFIWidget;
use glib::translate::{from_glib, from_glib_none, ToGlibPtr};
use glib::{to_bool, to_gboolean};

/// GtkNotebook — A tabbed notebook container
struct_Widget!(NoteBook);

impl NoteBook {
    pub fn new() -> Option<NoteBook> {
        let tmp_pointer = unsafe { ffi::gtk_notebook_new() };
        check_pointer!(tmp_pointer, NoteBook)
    }

    pub fn append_page<Child: ::WidgetTrait, TabLabel: ::WidgetTrait>(&self, child: &Child,
            tab_label: Option<&TabLabel>) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_append_page(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label)) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn append_page_menu<Child: ::WidgetTrait, TabLabel: ::WidgetTrait,
            MenuLabel: ::WidgetTrait>(&self, child: &Child, tab_label: Option<&TabLabel>,
            menu_label: Option<&MenuLabel>) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_append_page_menu(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label), unwrap_widget!(menu_label)) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn prepend_page<Child: ::WidgetTrait, TabLabel: ::WidgetTrait>(&self, child: &Child,
            tab_label: Option<&TabLabel>) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_prepend_page(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label)) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn prepend_page_menu<Child: ::WidgetTrait, TabLabel: ::WidgetTrait,
            MenuLabel: ::WidgetTrait>(&self, child: &Child, tab_label: Option<&TabLabel>,
            menu_label: Option<&MenuLabel>) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_prepend_page_menu(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label), unwrap_widget!(menu_label)) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn insert_page<Child: ::WidgetTrait, TabLabel: ::WidgetTrait>(&self, child: &Child,
            tab_label: Option<&TabLabel>, position: i32) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_insert_page(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label), position) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn insert_page_menu<Child: ::WidgetTrait, TabLabel: ::WidgetTrait,
            MenuLabel: ::WidgetTrait>(&self, child: &Child, tab_label: Option<&TabLabel>,
            menu_label: Option<&MenuLabel>, position: i32) -> Option<u32> {
        match unsafe { ffi::gtk_notebook_insert_page_menu(GTK_NOTEBOOK(self.pointer),
                child.unwrap_widget(), unwrap_widget!(tab_label), unwrap_widget!(menu_label),
                position) } {
            x if x >= 0 => Some(x as u32),
            _ => None
        }
    }

    pub fn remove_page(&self, page_num: i32) {
        unsafe {
            ffi::gtk_notebook_remove_page(GTK_NOTEBOOK(self.pointer), page_num)
        }
    }

    pub fn set_group_name(&self, group_name: &str) {
        unsafe {
            ffi::gtk_notebook_set_group_name(GTK_NOTEBOOK(self.pointer),
                                             group_name.to_glib_none().0)
        }
    }

    pub fn get_group_name(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gtk_notebook_get_group_name(GTK_NOTEBOOK(self.pointer)))
        }
    }

    pub fn get_current_page(&self) -> Option<u32> {
        unsafe {
            from_glib(
                ffi::gtk_notebook_get_current_page(GTK_NOTEBOOK(self.pointer)))
        }
    }

    pub fn get_nth_page<T: ::WidgetTrait>(&self, page_num: i32) -> Option<T> {
        let tmp_pointer = unsafe { ffi::gtk_notebook_get_nth_page(GTK_NOTEBOOK(self.pointer), page_num) };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer))
        }
    }

    pub fn get_n_pages(&self) -> i32 {
        unsafe {
            ffi::gtk_notebook_get_n_pages(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn page_num<T: ::WidgetTrait>(&self, child: &T) -> Option<u32> {
        unsafe {
            from_glib(
                ffi::gtk_notebook_page_num(GTK_NOTEBOOK(self.pointer), child.unwrap_widget()))
        }
    }

    pub fn set_current_page(&self, page_num: i32) {
        unsafe {
            ffi::gtk_notebook_set_current_page(GTK_NOTEBOOK(self.pointer), page_num)
        }
    }

    pub fn next_page(&self) {
        unsafe {
            ffi::gtk_notebook_next_page(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn prev_page(&self) {
        unsafe {
            ffi::gtk_notebook_prev_page(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn set_show_border(&self, show_border: bool) {
        unsafe {
            ffi::gtk_notebook_set_show_border(GTK_NOTEBOOK(self.pointer),
                                              to_gboolean(show_border))
        }
    }

    pub fn get_show_border(&self) -> bool {
        unsafe {
            to_bool(ffi::gtk_notebook_get_show_border(GTK_NOTEBOOK(self.pointer)))
        }
    }

    pub fn set_show_tabs(&self, show_tabs: bool) {
        unsafe {
            ffi::gtk_notebook_set_show_tabs(GTK_NOTEBOOK(self.pointer),
                                            to_gboolean(show_tabs))
        }
    }

    pub fn get_show_tabs(&self) -> bool {
        unsafe {
            to_bool(ffi::gtk_notebook_get_show_tabs(GTK_NOTEBOOK(self.pointer)))
        }
    }

    pub fn set_tab_pos(&self, pos: ::PositionType) {
        unsafe {
            ffi::gtk_notebook_set_tab_pos(GTK_NOTEBOOK(self.pointer), pos)
        }
    }

    pub fn get_tab_pos(&self) -> ::PositionType {
        unsafe {
            ffi::gtk_notebook_get_tab_pos(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn set_scrollable(&self, scrollable: bool) {
        unsafe {
            ffi::gtk_notebook_set_scrollable(GTK_NOTEBOOK(self.pointer),
                                             to_gboolean(scrollable))
        }
    }

    pub fn is_scrollable(&self) -> bool {
        unsafe {
            to_bool(ffi::gtk_notebook_get_scrollable(GTK_NOTEBOOK(self.pointer)))
        }
    }

    pub fn get_tab_hborder(&self) -> u16 {
        unsafe {
            ffi::gtk_notebook_get_tab_hborder(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn get_tab_vborder(&self) -> u16 {
        unsafe {
            ffi::gtk_notebook_get_tab_vborder(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn popup_enable(&self) {
        unsafe {
            ffi::gtk_notebook_popup_enable(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn popup_disable(&self) {
        unsafe {
            ffi::gtk_notebook_popup_disable(GTK_NOTEBOOK(self.pointer))
        }
    }

    pub fn get_tab_label<Child: ::WidgetTrait, TabLabel: ::WidgetTrait>(&self, child: &Child) ->
            Option<TabLabel> {
        let tmp_pointer = unsafe {
            ffi::gtk_notebook_get_tab_label(GTK_NOTEBOOK(self.pointer),
                                            child.unwrap_widget())
        };
        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer))
        }
    }

    pub fn set_tab_label<Child: ::WidgetTrait, TabLabel: ::WidgetTrait>(&self, child: &Child,
            tab_label: Option<&TabLabel>) {
        unsafe {
            ffi::gtk_notebook_set_tab_label(GTK_NOTEBOOK(self.pointer),
                                            child.unwrap_widget(),
                                            unwrap_widget!(tab_label))
        }
    }

    pub fn set_tab_label_text<T: ::WidgetTrait>(&self, child: &T, tab_text: &str) {
        unsafe {
            ffi::gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(self.pointer),
                                                 child.unwrap_widget(),
                                                 tab_text.to_glib_none().0)
        }
    }

    pub fn get_tab_label_text<T: ::WidgetTrait>(&self, child: &T) -> Option<String> {
        unsafe {
            from_glib_none(
                ffi::gtk_notebook_get_tab_label_text(GTK_NOTEBOOK(self.pointer),
                                                     child.unwrap_widget()))
        }
    }

    pub fn get_menu_label<Child: ::WidgetTrait, MenuLabel: ::WidgetTrait>(&self, child: &Child) ->
            Option<MenuLabel> {
        let tmp_pointer = unsafe {
            ffi::gtk_notebook_get_menu_label(GTK_NOTEBOOK(self.pointer),
                                             child.unwrap_widget())
        };
        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer))
        }
    }

    pub fn set_menu_label<Child: ::WidgetTrait, MenuLabel: ::WidgetTrait>(&self, child: &Child,
        menu_label: Option<&MenuLabel>) {
        unsafe {
            ffi::gtk_notebook_set_menu_label(GTK_NOTEBOOK(self.pointer),
                                             child.unwrap_widget(),
                                             unwrap_widget!(menu_label))
        }
    }

    pub fn set_menu_label_text<T: ::WidgetTrait>(&self, child: &T, tab_text: &str) {
        unsafe {
            ffi::gtk_notebook_set_menu_label_text(GTK_NOTEBOOK(self.pointer),
                                                  child.unwrap_widget(),
                                                  tab_text.to_glib_none().0)
        }
    }

    pub fn get_menu_label_text<T: ::WidgetTrait>(&self, child: &T) -> Option<String> {
        unsafe {
            from_glib_none(
                ffi::gtk_notebook_get_menu_label_text(GTK_NOTEBOOK(self.pointer),
                                                              child.unwrap_widget()))
        }
    }

    pub fn reorder_child<T: ::WidgetTrait>(&self, child: &T, position: i32) {
        unsafe {
            ffi::gtk_notebook_reorder_child(GTK_NOTEBOOK(self.pointer),
                                            child.unwrap_widget(),
                                            position)
        }
    }

    pub fn is_tab_reorderable<T: ::WidgetTrait>(&self, child: &T) -> bool {
        unsafe {
            to_bool(ffi::gtk_notebook_get_tab_reorderable(GTK_NOTEBOOK(self.pointer),
                                                               child.unwrap_widget()))
        }
    }

    pub fn set_tab_reorderable<T: ::WidgetTrait>(&self, child: &T, reorderable: bool) {
        unsafe {
            ffi::gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(self.pointer),
                                                 child.unwrap_widget(),
                                                 to_gboolean(reorderable))
        }
    }

    pub fn is_tab_detachable<T: ::WidgetTrait>(&self, child: &T) -> bool {
        unsafe {
            to_bool(ffi::gtk_notebook_get_tab_detachable(GTK_NOTEBOOK(self.pointer),
                                                              child.unwrap_widget()))
        }
    }

    pub fn set_tab_detachable<T: ::WidgetTrait>(&self, child: &T, detachable: bool) {
        unsafe {
            ffi::gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(self.pointer),
                                                child.unwrap_widget(),
                                                to_gboolean(detachable))
        }
    }

    pub fn get_action_widget<T: ::WidgetTrait>(&self, pack_type: ::PackType) -> Option<T> {
        let tmp_pointer = unsafe { ffi::gtk_notebook_get_action_widget(GTK_NOTEBOOK(self.pointer),
                                                                       pack_type) };
        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer))
        }
    }

    pub fn set_action_widget<T: ::WidgetTrait>(&self, child: &T, pack_type: ::PackType) {
        unsafe {
            ffi::gtk_notebook_set_action_widget(GTK_NOTEBOOK(self.pointer),
                                                child.unwrap_widget(),
                                                pack_type)
        }
    }
}

impl_drop!(NoteBook);
impl_TraitWidget!(NoteBook);

impl ::ContainerTrait for NoteBook {}
<|endoftext|>


<commit_before>use rusoto_core::signature;

/// URL encodes an S3 object key. This is necessary for `copy_object` and `upload_part_copy`,
/// which require the `copy_source` field to be URL encoded to be used properly.
///
/// # Examples
///
/// ```
/// # use rusoto_s3::{S3, CopyObjectRequest};
/// # fn test_fn<T: S3>(s3_client: T) {
///
/// let response = s3_client.copy_object(&CopyObjectRequest {
///     bucket: "my-bucket".to_owned(),
///     key: "my-key".to_owned(),
///     copy_source: rusoto_s3::util::encode_key("other-buckét/key-to-cöpy"),
///     ..Default::default()
/// }).unwrap();
///
/// # }
pub fn encode_key<T: AsRef<str>>(key: T) -> String {
    signature::encode_uri_path(key.as_ref())
}
<commit_msg>Improve encode_key docs<commit_after>use rusoto_core::signature;

/// URL encodes an S3 object key. This is necessary for `copy_object` and `upload_part_copy`,
/// which require the `copy_source` field to be URL encoded.
///
/// # Examples
///
/// ```
/// use rusoto_s3::CopyObjectRequest;
///
/// let request = CopyObjectRequest {
///     bucket: "my-bucket".to_owned(),
///     key: "my-key".to_owned(),
///     copy_source: rusoto_s3::util::encode_key("other-buckét/key-to-cöpy"),
///     ..Default::default()
/// };
pub fn encode_key<T: AsRef<str>>(key: T) -> String {
    signature::encode_uri_path(key.as_ref())
}
<|endoftext|>