<commit_before>use nom::{IResult, Consumer, ConsumerState};
use metadata::parser::{header, block_data};

use std::collections::HashMap;

/// Data associated with a single metadata block.
#[derive(Debug)]
pub struct Block {
  /// Marks whether the current metadata block is the last.
  pub is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  pub length: u32,
  /// Block data containing on of the eight different types of metadata.
  pub data: BlockData,
}

/// General enum that hold all the different metadata block data.
#[derive(Debug, PartialEq, Eq)]
pub enum BlockData {
  /// Information regarding the entire audio stream.
  StreamInfo(StreamInfo),
  /// Block that represents a number of padded bytes.
  Padding(u32),
  /// Data used by third-party applications.
  Application(Application),
  /// Table of multiple points to seek, or skip, to within the FLAC file.
  SeekTable(Vec<SeekPoint>),
  /// Stores human-readable name/value pairs.
  VorbisComment(VorbisComment),
  /// Stores cue information
  CueSheet(CueSheet),
  /// Stores pictures associated with the FLAC file.
  Picture(Picture),
  /// A type of block data that isn't know or doesn't match the type above.
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream.
#[derive(Debug, PartialEq, Eq)]
pub struct StreamInfo {
  /// Minimum block size, in samples, used in the stream.
  pub min_block_size: u16,
  /// Maximum block size, in samples, used in the stream.
  pub max_block_size: u16,
  /// Minimum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub min_frame_size: u32,
  /// Maximum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub max_frame_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels. FLAC supports one to eight channel.
  pub channels: u8,
  /// Bits per sample. FLAC supports four to thirty-two bits per sample.
  pub bits_per_sample: u8,
  /// Total samples in the stream. A value of zero means the number is
  /// unknown.
  pub total_samples: u64,
  /// MD5 signature of the unencoded audio data.
  pub md5_sum: [u8; 16],
}

impl StreamInfo {
  pub fn new() -> StreamInfo {
    StreamInfo {
      min_block_size: 0,
      max_block_size: 0,
      min_frame_size: 0,
      max_frame_size: 0,
      sample_rate: 0,
      channels: 0,
      bits_per_sample: 0,
      total_samples: 0,
      md5_sum: [0; 16],
    }
  }
}

/// Data used by third-party applications.
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  /// Registered application ID.
  pub id: String,
  /// Data used by the third-party application.
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file.
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  /// Sample number of the first sample in the target frame.
  pub sample_number: u64,
  /// Byte offset of the target frame's header.
  pub stream_offset: u64,
  /// Number of samples in the target frame.
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs.
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  /// Vendor name.
  pub vendor_string: String,
  /// Comments associated with a name, or category, followed by it's
  /// contents.
  pub comments: HashMap<String, String>,
}

/// Stores cue information.
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  /// Media catalog number.
  pub media_catalog_number: String,
  /// Number of lead-in samples.
  pub lead_in: u64,
  /// Whether or not this `CueSheet` corresponds to a Compact Disc.
  pub is_cd: bool,
  /// One or more tracks.
  pub tracks: Vec<CueSheetTrack>,
}

/// Track information inside a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  /// Track offset, in samples, relative to the beginning of the FLAC audio
  /// stream.
  pub offset: u64,
  /// Track number.
  pub number: u8,
  /// Twelve digit alphanumeric code.
  pub isrc: String,
  /// Whether the cue sheet track is audio.
  pub is_audio: bool,
  /// Whether the cue sheet track is pre-emphasis.
  pub is_pre_emphasis: bool,
  /// For all tracks except the lead-out track.
  pub indices: Vec<CueSheetTrackIndex>,
}

/// An index point within a track, inside of a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  /// Offset, in samples, relative to the track offset of the index point.
  pub offset: u64,
  /// Index point number.
  pub number: u8,
}

/// Stores pictures associated with the FLAC file.
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  /// Picture type, based on the ID3v2 APIC frame.
  pub picture_type: PictureType,
  /// Multipurpose Internet Mail Extensions (MIME) type.
  pub mime_type: String,
  /// A string describing the picture.
  pub description: String,
  /// Width of the picture in pixels.
  pub width: u32,
  /// Height of the picture in pixels.
  pub height: u32,
  /// Color depth of the picture in bits-per-pixel.
  pub depth: u32,
  /// Number of colors used.
  pub colors: u32,
  /// Binary picture data.
  pub data: Vec<u8>,
}

/// The picture type according to the ID3v2 attached picture frame.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  /// Other picture type not categorized in this enum.
  Other,
  /// 32x32 pixels 'file icon'.
  FileIconStandard,
  /// Other, or non-standard, file icon.
  FileIcon,
  /// Cover (front).
  FrontCover,
  /// Cover (back).
  BackCover,
  /// Leaflet page.
  LeafletPage,
  /// Media, like label side of a CD.
  Media,
  /// Lead artist, lead performer, or soloist.
  LeadArtist,
  /// Artist or performer.
  Artist,
  /// Conductor.
  Conductor,
  /// Band or orchestra.
  Band,
  /// Composer.
  Composer,
  /// Lyricist or text writer.
  Lyricist,
  /// Recording location.
  RecordingLocation,
  /// During recording.
  DuringRecording,
  /// During performance.
  DuringPerformace,
  /// Movie, or video, screen capture.
  VideoScreenCapture,
  /// A bright colored fish.
  Fish,
  /// Illustration.
  Illustration,
  /// Band, or artist, logotype.
  BandLogo,
  /// Publisher, or studio, logotype.
  PublisherLogo,
}

enum ParserState {
  Marker,
  Header,
  Block((bool, u8, u32)),
}

pub struct MetaDataConsumer {
  state: ParserState,
  pub data: Vec<Block>
}

impl MetaDataConsumer {
  pub fn new() -> MetaDataConsumer {
    MetaDataConsumer {
      state: ParserState::Marker,
      data: Vec::new(),
    }
  }
}

impl Consumer for MetaDataConsumer {
  fn consume(&mut self, input: &[u8]) -> ConsumerState {
    match self.state {
      ParserState::FLAC     => {
        match tag!(input, "fLaC") {
          IResult::Done(_, _) => {
            self.state = ParserState::Header;
            ConsumerState::Await(4, 4)
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, 4),
        }
      }
      ParserState::Header   => {
        match header(input) {
          IResult::Done(_, data) => {
            let (is_last, block_type, length) = data;

            self.state      = ParserState::MetaData;
            self.is_last    = is_last;
            self.block_type = block_type;
            self.length     = length;

            ConsumerState::Await(4, length as usize)
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, 4),
        }
      },
      ParserState::MetaData => {
        let length = self.length as usize;

        match block_data(input, self.block_type, self.length) {
          IResult::Done(_, data) => {
            self.data.push(Block {
              is_last: self.is_last,
              length: self.length,
              data: data,
            });

            if self.is_last {
              ConsumerState::ConsumerDone
            } else {
              self.state = ParserState::Header;

              ConsumerState::Await(length, 4)
            }
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, length),
        }
      }
    }
  }

  fn failed(&mut self, error_code: u32) {
    println!("Failed with error code: {}", error_code);
  }

  fn end(&mut self) {}
}
<commit_msg>Move consuming methods to MetaDataConsumer<commit_after>use nom::{IResult, Consumer, ConsumerState};
use metadata::parser::{header, block_data};

use std::collections::HashMap;

/// Data associated with a single metadata block.
#[derive(Debug)]
pub struct Block {
  /// Marks whether the current metadata block is the last.
  pub is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  pub length: u32,
  /// Block data containing on of the eight different types of metadata.
  pub data: BlockData,
}

/// General enum that hold all the different metadata block data.
#[derive(Debug, PartialEq, Eq)]
pub enum BlockData {
  /// Information regarding the entire audio stream.
  StreamInfo(StreamInfo),
  /// Block that represents a number of padded bytes.
  Padding(u32),
  /// Data used by third-party applications.
  Application(Application),
  /// Table of multiple points to seek, or skip, to within the FLAC file.
  SeekTable(Vec<SeekPoint>),
  /// Stores human-readable name/value pairs.
  VorbisComment(VorbisComment),
  /// Stores cue information
  CueSheet(CueSheet),
  /// Stores pictures associated with the FLAC file.
  Picture(Picture),
  /// A type of block data that isn't know or doesn't match the type above.
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream.
#[derive(Debug, PartialEq, Eq)]
pub struct StreamInfo {
  /// Minimum block size, in samples, used in the stream.
  pub min_block_size: u16,
  /// Maximum block size, in samples, used in the stream.
  pub max_block_size: u16,
  /// Minimum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub min_frame_size: u32,
  /// Maximum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub max_frame_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels. FLAC supports one to eight channel.
  pub channels: u8,
  /// Bits per sample. FLAC supports four to thirty-two bits per sample.
  pub bits_per_sample: u8,
  /// Total samples in the stream. A value of zero means the number is
  /// unknown.
  pub total_samples: u64,
  /// MD5 signature of the unencoded audio data.
  pub md5_sum: [u8; 16],
}

impl StreamInfo {
  pub fn new() -> StreamInfo {
    StreamInfo {
      min_block_size: 0,
      max_block_size: 0,
      min_frame_size: 0,
      max_frame_size: 0,
      sample_rate: 0,
      channels: 0,
      bits_per_sample: 0,
      total_samples: 0,
      md5_sum: [0; 16],
    }
  }
}

/// Data used by third-party applications.
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  /// Registered application ID.
  pub id: String,
  /// Data used by the third-party application.
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file.
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  /// Sample number of the first sample in the target frame.
  pub sample_number: u64,
  /// Byte offset of the target frame's header.
  pub stream_offset: u64,
  /// Number of samples in the target frame.
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs.
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  /// Vendor name.
  pub vendor_string: String,
  /// Comments associated with a name, or category, followed by it's
  /// contents.
  pub comments: HashMap<String, String>,
}

/// Stores cue information.
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  /// Media catalog number.
  pub media_catalog_number: String,
  /// Number of lead-in samples.
  pub lead_in: u64,
  /// Whether or not this `CueSheet` corresponds to a Compact Disc.
  pub is_cd: bool,
  /// One or more tracks.
  pub tracks: Vec<CueSheetTrack>,
}

/// Track information inside a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  /// Track offset, in samples, relative to the beginning of the FLAC audio
  /// stream.
  pub offset: u64,
  /// Track number.
  pub number: u8,
  /// Twelve digit alphanumeric code.
  pub isrc: String,
  /// Whether the cue sheet track is audio.
  pub is_audio: bool,
  /// Whether the cue sheet track is pre-emphasis.
  pub is_pre_emphasis: bool,
  /// For all tracks except the lead-out track.
  pub indices: Vec<CueSheetTrackIndex>,
}

/// An index point within a track, inside of a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  /// Offset, in samples, relative to the track offset of the index point.
  pub offset: u64,
  /// Index point number.
  pub number: u8,
}

/// Stores pictures associated with the FLAC file.
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  /// Picture type, based on the ID3v2 APIC frame.
  pub picture_type: PictureType,
  /// Multipurpose Internet Mail Extensions (MIME) type.
  pub mime_type: String,
  /// A string describing the picture.
  pub description: String,
  /// Width of the picture in pixels.
  pub width: u32,
  /// Height of the picture in pixels.
  pub height: u32,
  /// Color depth of the picture in bits-per-pixel.
  pub depth: u32,
  /// Number of colors used.
  pub colors: u32,
  /// Binary picture data.
  pub data: Vec<u8>,
}

/// The picture type according to the ID3v2 attached picture frame.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  /// Other picture type not categorized in this enum.
  Other,
  /// 32x32 pixels 'file icon'.
  FileIconStandard,
  /// Other, or non-standard, file icon.
  FileIcon,
  /// Cover (front).
  FrontCover,
  /// Cover (back).
  BackCover,
  /// Leaflet page.
  LeafletPage,
  /// Media, like label side of a CD.
  Media,
  /// Lead artist, lead performer, or soloist.
  LeadArtist,
  /// Artist or performer.
  Artist,
  /// Conductor.
  Conductor,
  /// Band or orchestra.
  Band,
  /// Composer.
  Composer,
  /// Lyricist or text writer.
  Lyricist,
  /// Recording location.
  RecordingLocation,
  /// During recording.
  DuringRecording,
  /// During performance.
  DuringPerformace,
  /// Movie, or video, screen capture.
  VideoScreenCapture,
  /// A bright colored fish.
  Fish,
  /// Illustration.
  Illustration,
  /// Band, or artist, logotype.
  BandLogo,
  /// Publisher, or studio, logotype.
  PublisherLogo,
}

enum ParserState {
  Marker,
  Header,
  Block((bool, u8, u32)),
}

pub struct MetaDataConsumer {
  state: ParserState,
  pub data: Vec<Block>
}

impl MetaDataConsumer {
  pub fn new() -> MetaDataConsumer {
    MetaDataConsumer {
      state: ParserState::Marker,
      data: Vec::new(),
    }
  }

  fn consume_marker(&mut self, input: &[u8]) -> ConsumerState {
    match tag!(input, "fLaC") {
      IResult::Done(_, _)    => {
        self.state = ParserState::Header;

        ConsumerState::Await(4, 4)
      }
      IResult::Error(_)      => ConsumerState::ConsumerError(0),
      IResult::Incomplete(_) => ConsumerState::Await(0, 4),
    }
  }

  fn consume_header(&mut self, input: &[u8]) -> ConsumerState {
    match header(input) {
      IResult::Done(_, data) => {
        let length = data.2 as usize;

        self.state = ParserState::Block(data);

        ConsumerState::Await(4, length)
      }
      IResult::Error(_)      => ConsumerState::ConsumerError(0),
      IResult::Incomplete(_) => ConsumerState::Await(0, 4),
    }
  }

  fn consume_block(&mut self, input: &[u8], header: (bool, u8, u32))
                   -> ConsumerState {
    let (is_last, block_type, length) = header;

    match block_data(input, block_type, length) {
      IResult::Done(_, data) => {
        self.data.push(Block {
          is_last: is_last,
          length: length,
          data: data,
        });

        if is_last {
          ConsumerState::ConsumerDone
        } else {
          self.state = ParserState::Header;

          ConsumerState::Await(length as usize, 4)
        }
      }
      IResult::Error(_)      => ConsumerState::ConsumerError(0),
      IResult::Incomplete(_) => ConsumerState::Await(0, length as usize),
    }
  }
}

impl Consumer for MetaDataConsumer {
  fn consume(&mut self, input: &[u8]) -> ConsumerState {
    match self.state {
      ParserState::Marker      => self.consume_marker(input),
      ParserState::Header      => self.consume_header(input),
      ParserState::Block(data) => self.consume_block(input, data),
    }
  }

  fn failed(&mut self, error_code: u32) {
    println!("Failed with error code: {}", error_code);
  }

  fn end(&mut self) {}
}
<|endoftext|>


<commit_before>use crate::syntax::atom::Atom::{self, *};
use crate::syntax::{
    error, ident, Api, ExternFn, ExternType, Lang, Receiver, Ref, Slice, Struct, Ty1, Type, Types,
};
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
use quote::{quote, ToTokens};
use std::fmt::Display;
use syn::{Error, Result};

struct Check<'a> {
    apis: &'a [Api],
    types: &'a Types<'a>,
    errors: &'a mut Vec<Error>,
}

pub(crate) fn typecheck(apis: &[Api], types: &Types) -> Result<()> {
    let mut errors = Vec::new();
    let mut cx = Check {
        apis,
        types,
        errors: &mut errors,
    };
    do_typecheck(&mut cx);
    combine_errors(errors)
}

fn do_typecheck(cx: &mut Check) {
    for ty in cx.types {
        match ty {
            Type::Ident(ident) => check_type_ident(cx, ident),
            Type::RustBox(ptr) => check_type_box(cx, ptr),
            Type::RustVec(ty) => check_type_rust_vec(cx, ty),
            Type::UniquePtr(ptr) => check_type_unique_ptr(cx, ptr),
            Type::CxxVector(ptr) => check_type_cxx_vector(cx, ptr),
            Type::Ref(ty) => check_type_ref(cx, ty),
            Type::Slice(ty) => check_type_slice(cx, ty),
            _ => {}
        }
    }

    for api in cx.apis {
        match api {
            Api::Struct(strct) => check_api_struct(cx, strct),
            Api::CxxType(ty) | Api::RustType(ty) => check_api_type(cx, ty),
            Api::CxxFunction(efn) | Api::RustFunction(efn) => check_api_fn(cx, efn),
            _ => {}
        }
    }

    for api in cx.apis {
        if let Api::CxxFunction(efn) = api {
            check_mut_return_restriction(cx, efn);
        }
        if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api {
            check_multiple_arg_lifetimes(cx, efn);
        }
    }

    ident::check_all(cx.apis, cx.errors);
}

impl Check<'_> {
    fn error(&mut self, sp: impl ToTokens, msg: impl Display) {
        self.errors.push(Error::new_spanned(sp, msg));
    }
}

fn check_type_ident(cx: &mut Check, ident: &Ident) {
    if Atom::from(ident).is_none()
        && !cx.types.structs.contains_key(ident)
        && !cx.types.cxx.contains(ident)
        && !cx.types.rust.contains(ident)
    {
        cx.error(ident, "unsupported type");
    }
}

fn check_type_box(cx: &mut Check, ptr: &Ty1) {
    if let Type::Ident(ident) = &ptr.inner {
        if cx.types.cxx.contains(ident) {
            cx.error(ptr, error::BOX_CXX_TYPE.msg);
        }

        if Atom::from(ident).is_none() {
            return;
        }
    }

    cx.error(ptr, "unsupported target type of Box");
}

fn check_type_rust_vec(cx: &mut Check, ty: &Ty1) {
    if let Type::Ident(ident) = &ty.inner {
        if cx.types.cxx.contains(ident) {
            cx.error(ty, "Rust Vec containing C++ type is not supported yet");
            return;
        }

        match Atom::from(ident) {
            None | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize) | Some(I8)
            | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32) | Some(F64) => return,
            Some(Bool) | Some(RustString) => { /* todo */ }
            Some(CxxString) => {}
        }
    }

    cx.error(ty, "unsupported element type of Vec");
}

fn check_type_unique_ptr(cx: &mut Check, ptr: &Ty1) {
    if let Type::Ident(ident) = &ptr.inner {
        if cx.types.rust.contains(ident) {
            cx.error(ptr, "unique_ptr of a Rust type is not supported yet");
        }

        match Atom::from(ident) {
            None | Some(CxxString) => return,
            _ => {}
        }
    } else if let Type::CxxVector(_) = &ptr.inner {
        return;
    }

    cx.error(ptr, "unsupported unique_ptr target type");
}

fn check_type_cxx_vector(cx: &mut Check, ptr: &Ty1) {
    if let Type::Ident(ident) = &ptr.inner {
        if cx.types.rust.contains(ident) {
            cx.error(
                ptr,
                "C++ vector containing a Rust type is not supported yet",
            );
        }

        match Atom::from(ident) {
            None | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize) | Some(I8)
            | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32) | Some(F64) => return,
            Some(CxxString) => { /* todo */ }
            Some(Bool) | Some(RustString) => {}
        }
    }

    cx.error(ptr, "unsupported vector target type");
}

fn check_type_ref(cx: &mut Check, ty: &Ref) {
    if ty.lifetime.is_some() {
        cx.error(ty, "references with explicit lifetimes are not supported");
    }

    match ty.inner {
        Type::Fn(_) | Type::Void(_) => {}
        _ => return,
    }

    cx.error(ty, "unsupported reference type");
}

fn check_type_slice(cx: &mut Check, ty: &Slice) {
    cx.error(ty, "only &[u8] is supported so far, not other slice types");
}

fn check_api_struct(cx: &mut Check, strct: &Struct) {
    check_reserved_name(cx, &strct.ident);

    if strct.fields.is_empty() {
        let span = span_for_struct_error(strct);
        cx.error(span, "structs without any fields are not supported");
    }

    for field in &strct.fields {
        if is_unsized(cx, &field.ty) {
            let desc = describe(cx, &field.ty);
            let msg = format!("using {} by value is not supported", desc);
            cx.error(field, msg);
        }
        if let Type::Fn(_) = field.ty {
            cx.error(
                field,
                "function pointers in a struct field are not implemented yet",
            );
        }
    }
}

fn check_api_type(cx: &mut Check, ty: &ExternType) {
    check_reserved_name(cx, &ty.ident);
}

fn check_api_fn(cx: &mut Check, efn: &ExternFn) {
    if let Some(receiver) = &efn.receiver {
        let ref span = span_for_receiver_error(receiver);

        if receiver.ty == "Self" {
            let mutability = match receiver.mutability {
                Some(_) => "mut ",
                None => "",
            };
            let msg = format!(
                "unnamed receiver type is only allowed if the surrounding \
                 extern block contains exactly one extern type; \
                 use `self: &{mutability}TheType`",
                mutability = mutability,
            );
            cx.error(span, msg);
        } else if !cx.types.structs.contains_key(&receiver.ty)
            && !cx.types.cxx.contains(&receiver.ty)
            && !cx.types.rust.contains(&receiver.ty)
        {
            cx.error(span, "unrecognized receiver type");
        }

        if receiver.lifetime.is_some() {
            cx.error(span, "references with explicit lifetimes are not supported");
        }
    }

    for arg in &efn.args {
        if is_unsized(cx, &arg.ty) {
            let desc = describe(cx, &arg.ty);
            let msg = format!("passing {} by value is not supported", desc);
            cx.error(arg, msg);
        }
        if let Type::Fn(_) = arg.ty {
            if efn.lang == Lang::Rust {
                cx.error(
                    arg,
                    "passing a function pointer from C++ to Rust is not implemented yet",
                );
            }
        }
    }

    if let Some(ty) = &efn.ret {
        if is_unsized(cx, ty) {
            let desc = describe(cx, ty);
            let msg = format!("returning {} by value is not supported", desc);
            cx.error(ty, msg);
        }
        if let Type::Fn(_) = ty {
            cx.error(ty, "returning a function pointer is not implemented yet");
        }
    }
}

fn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) {
    match &efn.ret {
        Some(Type::Ref(ty)) if ty.mutability.is_some() => {}
        _ => return,
    }

    for arg in &efn.args {
        if let Type::Ref(ty) = &arg.ty {
            if ty.mutability.is_some() {
                return;
            }
        }
    }

    cx.error(
        efn,
        "&mut return type is not allowed unless there is a &mut argument",
    );
}

fn check_multiple_arg_lifetimes(cx: &mut Check, efn: &ExternFn) {
    match &efn.ret {
        Some(Type::Ref(_)) => {}
        _ => return,
    }

    let mut reference_args = 0;
    for arg in &efn.args {
        if let Type::Ref(_) = &arg.ty {
            reference_args += 1;
        }
    }

    if efn.receiver.is_some() {
        reference_args += 1;
    }

    if reference_args != 1 {
        cx.error(
            efn,
            "functions that return a reference must take exactly one input reference",
        );
    }
}

fn check_reserved_name(cx: &mut Check, ident: &Ident) {
    if ident == "Box"
        || ident == "UniquePtr"
        || ident == "Vec"
        || ident == "CxxVector"
        || Atom::from(ident).is_some()
    {
        cx.error(ident, "reserved name");
    }
}

fn is_unsized(cx: &mut Check, ty: &Type) -> bool {
    let ident = match ty {
        Type::Ident(ident) => ident,
        Type::CxxVector(_) | Type::Slice(_) | Type::Void(_) => return true,
        _ => return false,
    };
    ident == CxxString || cx.types.cxx.contains(ident) || cx.types.rust.contains(ident)
}

fn span_for_struct_error(strct: &Struct) -> TokenStream {
    let struct_token = strct.struct_token;
    let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
    brace_token.set_span(strct.brace_token.span);
    quote!(#struct_token #brace_token)
}

fn span_for_receiver_error(receiver: &Receiver) -> TokenStream {
    let ampersand = receiver.ampersand;
    let lifetime = &receiver.lifetime;
    let mutability = receiver.mutability;
    if receiver.shorthand {
        let var = receiver.var;
        quote!(#ampersand #lifetime #mutability #var)
    } else {
        let ty = &receiver.ty;
        quote!(#ampersand #lifetime #mutability #ty)
    }
}

fn combine_errors(errors: Vec<Error>) -> Result<()> {
    let mut iter = errors.into_iter();
    let mut all_errors = match iter.next() {
        Some(err) => err,
        None => return Ok(()),
    };
    for err in iter {
        all_errors.combine(err);
    }
    Err(all_errors)
}

fn describe(cx: &mut Check, ty: &Type) -> String {
    match ty {
        Type::Ident(ident) => {
            if cx.types.structs.contains_key(ident) {
                "struct".to_owned()
            } else if cx.types.cxx.contains(ident) {
                "C++ type".to_owned()
            } else if cx.types.rust.contains(ident) {
                "opaque Rust type".to_owned()
            } else if Atom::from(ident) == Some(CxxString) {
                "C++ string".to_owned()
            } else {
                ident.to_string()
            }
        }
        Type::RustBox(_) => "Box".to_owned(),
        Type::RustVec(_) => "Vec".to_owned(),
        Type::UniquePtr(_) => "unique_ptr".to_owned(),
        Type::Ref(_) => "reference".to_owned(),
        Type::Str(_) => "&str".to_owned(),
        Type::CxxVector(_) => "vector".to_owned(),
        Type::Slice(_) => "slice".to_owned(),
        Type::SliceRefU8(_) => "&[u8]".to_owned(),
        Type::Fn(_) => "function pointer".to_owned(),
        Type::Void(_) => "()".to_owned(),
    }
}
<commit_msg>Clarify mentions of C++ vector in error messages<commit_after>use crate::syntax::atom::Atom::{self, *};
use crate::syntax::{
    error, ident, Api, ExternFn, ExternType, Lang, Receiver, Ref, Slice, Struct, Ty1, Type, Types,
};
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
use quote::{quote, ToTokens};
use std::fmt::Display;
use syn::{Error, Result};

struct Check<'a> {
    apis: &'a [Api],
    types: &'a Types<'a>,
    errors: &'a mut Vec<Error>,
}

pub(crate) fn typecheck(apis: &[Api], types: &Types) -> Result<()> {
    let mut errors = Vec::new();
    let mut cx = Check {
        apis,
        types,
        errors: &mut errors,
    };
    do_typecheck(&mut cx);
    combine_errors(errors)
}

fn do_typecheck(cx: &mut Check) {
    for ty in cx.types {
        match ty {
            Type::Ident(ident) => check_type_ident(cx, ident),
            Type::RustBox(ptr) => check_type_box(cx, ptr),
            Type::RustVec(ty) => check_type_rust_vec(cx, ty),
            Type::UniquePtr(ptr) => check_type_unique_ptr(cx, ptr),
            Type::CxxVector(ptr) => check_type_cxx_vector(cx, ptr),
            Type::Ref(ty) => check_type_ref(cx, ty),
            Type::Slice(ty) => check_type_slice(cx, ty),
            _ => {}
        }
    }

    for api in cx.apis {
        match api {
            Api::Struct(strct) => check_api_struct(cx, strct),
            Api::CxxType(ty) | Api::RustType(ty) => check_api_type(cx, ty),
            Api::CxxFunction(efn) | Api::RustFunction(efn) => check_api_fn(cx, efn),
            _ => {}
        }
    }

    for api in cx.apis {
        if let Api::CxxFunction(efn) = api {
            check_mut_return_restriction(cx, efn);
        }
        if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api {
            check_multiple_arg_lifetimes(cx, efn);
        }
    }

    ident::check_all(cx.apis, cx.errors);
}

impl Check<'_> {
    fn error(&mut self, sp: impl ToTokens, msg: impl Display) {
        self.errors.push(Error::new_spanned(sp, msg));
    }
}

fn check_type_ident(cx: &mut Check, ident: &Ident) {
    if Atom::from(ident).is_none()
        && !cx.types.structs.contains_key(ident)
        && !cx.types.cxx.contains(ident)
        && !cx.types.rust.contains(ident)
    {
        cx.error(ident, "unsupported type");
    }
}

fn check_type_box(cx: &mut Check, ptr: &Ty1) {
    if let Type::Ident(ident) = &ptr.inner {
        if cx.types.cxx.contains(ident) {
            cx.error(ptr, error::BOX_CXX_TYPE.msg);
        }

        if Atom::from(ident).is_none() {
            return;
        }
    }

    cx.error(ptr, "unsupported target type of Box");
}

fn check_type_rust_vec(cx: &mut Check, ty: &Ty1) {
    if let Type::Ident(ident) = &ty.inner {
        if cx.types.cxx.contains(ident) {
            cx.error(ty, "Rust Vec containing C++ type is not supported yet");
            return;
        }

        match Atom::from(ident) {
            None | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize) | Some(I8)
            | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32) | Some(F64) => return,
            Some(Bool) | Some(RustString) => { /* todo */ }
            Some(CxxString) => {}
        }
    }

    cx.error(ty, "unsupported element type of Vec");
}

fn check_type_unique_ptr(cx: &mut Check, ptr: &Ty1) {
    if let Type::Ident(ident) = &ptr.inner {
        if cx.types.rust.contains(ident) {
            cx.error(ptr, "unique_ptr of a Rust type is not supported yet");
        }

        match Atom::from(ident) {
            None | Some(CxxString) => return,
            _ => {}
        }
    } else if let Type::CxxVector(_) = &ptr.inner {
        return;
    }

    cx.error(ptr, "unsupported unique_ptr target type");
}

fn check_type_cxx_vector(cx: &mut Check, ptr: &Ty1) {
    if let Type::Ident(ident) = &ptr.inner {
        if cx.types.rust.contains(ident) {
            cx.error(
                ptr,
                "C++ vector containing a Rust type is not supported yet",
            );
        }

        match Atom::from(ident) {
            None | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize) | Some(I8)
            | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32) | Some(F64) => return,
            Some(CxxString) => { /* todo */ }
            Some(Bool) | Some(RustString) => {}
        }
    }

    cx.error(ptr, "unsupported vector target type");
}

fn check_type_ref(cx: &mut Check, ty: &Ref) {
    if ty.lifetime.is_some() {
        cx.error(ty, "references with explicit lifetimes are not supported");
    }

    match ty.inner {
        Type::Fn(_) | Type::Void(_) => {}
        _ => return,
    }

    cx.error(ty, "unsupported reference type");
}

fn check_type_slice(cx: &mut Check, ty: &Slice) {
    cx.error(ty, "only &[u8] is supported so far, not other slice types");
}

fn check_api_struct(cx: &mut Check, strct: &Struct) {
    check_reserved_name(cx, &strct.ident);

    if strct.fields.is_empty() {
        let span = span_for_struct_error(strct);
        cx.error(span, "structs without any fields are not supported");
    }

    for field in &strct.fields {
        if is_unsized(cx, &field.ty) {
            let desc = describe(cx, &field.ty);
            let msg = format!("using {} by value is not supported", desc);
            cx.error(field, msg);
        }
        if let Type::Fn(_) = field.ty {
            cx.error(
                field,
                "function pointers in a struct field are not implemented yet",
            );
        }
    }
}

fn check_api_type(cx: &mut Check, ty: &ExternType) {
    check_reserved_name(cx, &ty.ident);
}

fn check_api_fn(cx: &mut Check, efn: &ExternFn) {
    if let Some(receiver) = &efn.receiver {
        let ref span = span_for_receiver_error(receiver);

        if receiver.ty == "Self" {
            let mutability = match receiver.mutability {
                Some(_) => "mut ",
                None => "",
            };
            let msg = format!(
                "unnamed receiver type is only allowed if the surrounding \
                 extern block contains exactly one extern type; \
                 use `self: &{mutability}TheType`",
                mutability = mutability,
            );
            cx.error(span, msg);
        } else if !cx.types.structs.contains_key(&receiver.ty)
            && !cx.types.cxx.contains(&receiver.ty)
            && !cx.types.rust.contains(&receiver.ty)
        {
            cx.error(span, "unrecognized receiver type");
        }

        if receiver.lifetime.is_some() {
            cx.error(span, "references with explicit lifetimes are not supported");
        }
    }

    for arg in &efn.args {
        if is_unsized(cx, &arg.ty) {
            let desc = describe(cx, &arg.ty);
            let msg = format!("passing {} by value is not supported", desc);
            cx.error(arg, msg);
        }
        if let Type::Fn(_) = arg.ty {
            if efn.lang == Lang::Rust {
                cx.error(
                    arg,
                    "passing a function pointer from C++ to Rust is not implemented yet",
                );
            }
        }
    }

    if let Some(ty) = &efn.ret {
        if is_unsized(cx, ty) {
            let desc = describe(cx, ty);
            let msg = format!("returning {} by value is not supported", desc);
            cx.error(ty, msg);
        }
        if let Type::Fn(_) = ty {
            cx.error(ty, "returning a function pointer is not implemented yet");
        }
    }
}

fn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) {
    match &efn.ret {
        Some(Type::Ref(ty)) if ty.mutability.is_some() => {}
        _ => return,
    }

    for arg in &efn.args {
        if let Type::Ref(ty) = &arg.ty {
            if ty.mutability.is_some() {
                return;
            }
        }
    }

    cx.error(
        efn,
        "&mut return type is not allowed unless there is a &mut argument",
    );
}

fn check_multiple_arg_lifetimes(cx: &mut Check, efn: &ExternFn) {
    match &efn.ret {
        Some(Type::Ref(_)) => {}
        _ => return,
    }

    let mut reference_args = 0;
    for arg in &efn.args {
        if let Type::Ref(_) = &arg.ty {
            reference_args += 1;
        }
    }

    if efn.receiver.is_some() {
        reference_args += 1;
    }

    if reference_args != 1 {
        cx.error(
            efn,
            "functions that return a reference must take exactly one input reference",
        );
    }
}

fn check_reserved_name(cx: &mut Check, ident: &Ident) {
    if ident == "Box"
        || ident == "UniquePtr"
        || ident == "Vec"
        || ident == "CxxVector"
        || Atom::from(ident).is_some()
    {
        cx.error(ident, "reserved name");
    }
}

fn is_unsized(cx: &mut Check, ty: &Type) -> bool {
    let ident = match ty {
        Type::Ident(ident) => ident,
        Type::CxxVector(_) | Type::Slice(_) | Type::Void(_) => return true,
        _ => return false,
    };
    ident == CxxString || cx.types.cxx.contains(ident) || cx.types.rust.contains(ident)
}

fn span_for_struct_error(strct: &Struct) -> TokenStream {
    let struct_token = strct.struct_token;
    let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
    brace_token.set_span(strct.brace_token.span);
    quote!(#struct_token #brace_token)
}

fn span_for_receiver_error(receiver: &Receiver) -> TokenStream {
    let ampersand = receiver.ampersand;
    let lifetime = &receiver.lifetime;
    let mutability = receiver.mutability;
    if receiver.shorthand {
        let var = receiver.var;
        quote!(#ampersand #lifetime #mutability #var)
    } else {
        let ty = &receiver.ty;
        quote!(#ampersand #lifetime #mutability #ty)
    }
}

fn combine_errors(errors: Vec<Error>) -> Result<()> {
    let mut iter = errors.into_iter();
    let mut all_errors = match iter.next() {
        Some(err) => err,
        None => return Ok(()),
    };
    for err in iter {
        all_errors.combine(err);
    }
    Err(all_errors)
}

fn describe(cx: &mut Check, ty: &Type) -> String {
    match ty {
        Type::Ident(ident) => {
            if cx.types.structs.contains_key(ident) {
                "struct".to_owned()
            } else if cx.types.cxx.contains(ident) {
                "C++ type".to_owned()
            } else if cx.types.rust.contains(ident) {
                "opaque Rust type".to_owned()
            } else if Atom::from(ident) == Some(CxxString) {
                "C++ string".to_owned()
            } else {
                ident.to_string()
            }
        }
        Type::RustBox(_) => "Box".to_owned(),
        Type::RustVec(_) => "Vec".to_owned(),
        Type::UniquePtr(_) => "unique_ptr".to_owned(),
        Type::Ref(_) => "reference".to_owned(),
        Type::Str(_) => "&str".to_owned(),
        Type::CxxVector(_) => "C++ vector".to_owned(),
        Type::Slice(_) => "slice".to_owned(),
        Type::SliceRefU8(_) => "&[u8]".to_owned(),
        Type::Fn(_) => "function pointer".to_owned(),
        Type::Void(_) => "()".to_owned(),
    }
}
<|endoftext|>


<commit_before>use rocksdb::{DB, ColumnFamilyDescriptor, Options};
use std::path::Path;
use std::io::Cursor;
use std::mem;

use tx::{TxVariant, BondTx};
use crypto::PublicKey;
use asset::Balance;
use serializer::*;

const CF_BLOCK_BYTE_POS: &str = "block_byte_pos";
const CF_ADDR_BAL: &str = "address_balance";
const CF_BOND: &str = "bond";

const KEY_CHAIN_HEIGHT: &[u8] = b"chain_height";

pub struct Indexer {
    db: DB
}

impl Indexer {
    pub fn new(path: &Path) -> Indexer {
        let mut db_opts = Options::default();
        db_opts.create_missing_column_families(true);
        db_opts.create_if_missing(true);

        let col_families = vec![
            ColumnFamilyDescriptor::new(CF_BLOCK_BYTE_POS, Options::default()),
            ColumnFamilyDescriptor::new(CF_BOND, Options::default())
        ];
        let db = DB::open_cf_descriptors(&db_opts, path, col_families).unwrap();
        Indexer { db }
    }

    pub fn get_block_byte_pos(&self, height: u64) -> Option<u64> {
        let cf = self.db.cf_handle(CF_BLOCK_BYTE_POS).unwrap();
        let buf = self.db.get_cf(cf, &{
            let mut key = Vec::with_capacity(8);
            key.push_u64(height);
            key
        }).unwrap()?;

        Some(u64_from_buf!(buf))
    }

    pub fn set_block_byte_pos(&self, height: u64, pos: u64) {
        let mut key = Vec::with_capacity(8);
        key.push_u64(height);
        let mut val = Vec::with_capacity(8);
        val.push_u64(pos);

        let cf = self.db.cf_handle(CF_BLOCK_BYTE_POS).unwrap();
        self.db.put_cf(cf, &key, &val).unwrap();
    }

    pub fn get_chain_height(&self) -> u64 {
        match self.db.get(KEY_CHAIN_HEIGHT).unwrap() {
            Some(val) => u64_from_buf!(val),
            None => 0
        }
    }

    pub fn set_chain_height(&self, height: u64) {
        let mut val = Vec::with_capacity(8);
        val.push_u64(height);
        self.db.put(KEY_CHAIN_HEIGHT, &val).unwrap();
    }

    pub fn get_bond(&self, minter: &PublicKey) -> Option<BondTx> {
        let cf = self.db.cf_handle(CF_BOND).unwrap();
        let tx_buf = self.db.get_cf(cf, minter.as_bytes()).unwrap()?;
        let cur = &mut Cursor::<&[u8]>::new(&tx_buf);
        let tx = TxVariant::decode_with_sigs(cur).unwrap();
        match tx {
            TxVariant::BondTx(bond) => Some(bond),
            _ => panic!("expected bond transaction")
        }
    }

    pub fn set_bond(&self, bond: &BondTx) {
        let cf = self.db.cf_handle(CF_BOND).unwrap();
        let key = bond.minter.as_bytes();
        let val = {
            let mut vec = Vec::with_capacity(2048);
            TxVariant::BondTx(bond.clone()).encode_with_sigs(&mut vec);
            vec
        };

        self.db.put_cf(cf, key, &val).unwrap();
    }

    pub fn get_balance(&self, addr: &PublicKey) -> Option<Balance> {
        let cf = self.db.cf_handle(CF_ADDR_BAL).unwrap();
        let bal_buf = self.db.get_cf(cf, addr.as_bytes()).unwrap()?;
        let cur = &mut Cursor::<&[u8]>::new(&bal_buf);
        let gold = cur.take_asset().unwrap();
        let silver = cur.take_asset().unwrap();
        Some(Balance { gold, silver })
    }

    pub fn set_balance(&self, addr: &PublicKey, bal: &Balance) {
        let cf = self.db.cf_handle(CF_ADDR_BAL).unwrap();
        let key = addr.as_bytes();
        let val = {
            let mut vec = Vec::with_capacity(mem::size_of::<Balance>());
            vec.push_asset(&bal.gold);
            vec.push_asset(&bal.silver);
            vec
        };
        self.db.put_cf(cf, key, &val).unwrap();
    }
}

#[cfg(test)]
mod tests {
    use rand::{thread_rng, Rng, distributions::Alphanumeric};
    use std::{env, fs, panic};
    use super::*;

    #[test]
    fn test_get_block_pos() {
        run_test(|indexer| {
            indexer.set_block_byte_pos(1, 327);
            assert!(indexer.get_block_byte_pos(0).is_none());
            assert_eq!(indexer.get_block_byte_pos(1).unwrap(), 327);
        });
    }

    #[test]
    fn test_get_chain_height() {
        run_test(|indexer| {
            assert_eq!(indexer.get_chain_height(), 0);
            indexer.set_chain_height(42);
            assert_eq!(indexer.get_chain_height(), 42);
        });
    }

    fn run_test<F>(func: F)
            where F: FnOnce(Indexer) -> () + panic::UnwindSafe {
        let mut tmp_dir = env::temp_dir();
        let mut s = String::from("godcoin_test_");
        s.push_str(&thread_rng().sample_iter(&Alphanumeric).take(4).collect::<String>());
        tmp_dir.push(s);
        fs::create_dir(&tmp_dir).expect(&format!("Could not create temp dir {:?}", &tmp_dir));

        let result = panic::catch_unwind(|| {
            let indexer = Indexer::new(&tmp_dir);
            func(indexer);
        });

        fs::remove_dir_all(&tmp_dir).expect("Failed to rm dir");
        assert!(result.is_ok());
    }
}
<commit_msg>Register the address_balance column family in the indexer<commit_after>use rocksdb::{DB, ColumnFamilyDescriptor, Options};
use std::path::Path;
use std::io::Cursor;
use std::mem;

use tx::{TxVariant, BondTx};
use crypto::PublicKey;
use asset::Balance;
use serializer::*;

const CF_BLOCK_BYTE_POS: &str = "block_byte_pos";
const CF_ADDR_BAL: &str = "address_balance";
const CF_BOND: &str = "bond";

const KEY_CHAIN_HEIGHT: &[u8] = b"chain_height";

pub struct Indexer {
    db: DB
}

impl Indexer {
    pub fn new(path: &Path) -> Indexer {
        let mut db_opts = Options::default();
        db_opts.create_missing_column_families(true);
        db_opts.create_if_missing(true);

        let col_families = vec![
            ColumnFamilyDescriptor::new(CF_BLOCK_BYTE_POS, Options::default()),
            ColumnFamilyDescriptor::new(CF_ADDR_BAL, Options::default()),
            ColumnFamilyDescriptor::new(CF_BOND, Options::default())
        ];
        let db = DB::open_cf_descriptors(&db_opts, path, col_families).unwrap();
        Indexer { db }
    }

    pub fn get_block_byte_pos(&self, height: u64) -> Option<u64> {
        let cf = self.db.cf_handle(CF_BLOCK_BYTE_POS).unwrap();
        let buf = self.db.get_cf(cf, &{
            let mut key = Vec::with_capacity(8);
            key.push_u64(height);
            key
        }).unwrap()?;

        Some(u64_from_buf!(buf))
    }

    pub fn set_block_byte_pos(&self, height: u64, pos: u64) {
        let mut key = Vec::with_capacity(8);
        key.push_u64(height);
        let mut val = Vec::with_capacity(8);
        val.push_u64(pos);

        let cf = self.db.cf_handle(CF_BLOCK_BYTE_POS).unwrap();
        self.db.put_cf(cf, &key, &val).unwrap();
    }

    pub fn get_chain_height(&self) -> u64 {
        match self.db.get(KEY_CHAIN_HEIGHT).unwrap() {
            Some(val) => u64_from_buf!(val),
            None => 0
        }
    }

    pub fn set_chain_height(&self, height: u64) {
        let mut val = Vec::with_capacity(8);
        val.push_u64(height);
        self.db.put(KEY_CHAIN_HEIGHT, &val).unwrap();
    }

    pub fn get_bond(&self, minter: &PublicKey) -> Option<BondTx> {
        let cf = self.db.cf_handle(CF_BOND).unwrap();
        let tx_buf = self.db.get_cf(cf, minter.as_bytes()).unwrap()?;
        let cur = &mut Cursor::<&[u8]>::new(&tx_buf);
        let tx = TxVariant::decode_with_sigs(cur).unwrap();
        match tx {
            TxVariant::BondTx(bond) => Some(bond),
            _ => panic!("expected bond transaction")
        }
    }

    pub fn set_bond(&self, bond: &BondTx) {
        let cf = self.db.cf_handle(CF_BOND).unwrap();
        let key = bond.minter.as_bytes();
        let val = {
            let mut vec = Vec::with_capacity(2048);
            TxVariant::BondTx(bond.clone()).encode_with_sigs(&mut vec);
            vec
        };

        self.db.put_cf(cf, key, &val).unwrap();
    }

    pub fn get_balance(&self, addr: &PublicKey) -> Option<Balance> {
        let cf = self.db.cf_handle(CF_ADDR_BAL).unwrap();
        let bal_buf = self.db.get_cf(cf, addr.as_bytes()).unwrap()?;
        let cur = &mut Cursor::<&[u8]>::new(&bal_buf);
        let gold = cur.take_asset().unwrap();
        let silver = cur.take_asset().unwrap();
        Some(Balance { gold, silver })
    }

    pub fn set_balance(&self, addr: &PublicKey, bal: &Balance) {
        let cf = self.db.cf_handle(CF_ADDR_BAL).unwrap();
        let key = addr.as_bytes();
        let val = {
            let mut vec = Vec::with_capacity(mem::size_of::<Balance>());
            vec.push_asset(&bal.gold);
            vec.push_asset(&bal.silver);
            vec
        };
        self.db.put_cf(cf, key, &val).unwrap();
    }
}

#[cfg(test)]
mod tests {
    use rand::{thread_rng, Rng, distributions::Alphanumeric};
    use std::{env, fs, panic};
    use super::*;

    #[test]
    fn test_get_block_pos() {
        run_test(|indexer| {
            indexer.set_block_byte_pos(1, 327);
            assert!(indexer.get_block_byte_pos(0).is_none());
            assert_eq!(indexer.get_block_byte_pos(1).unwrap(), 327);
        });
    }

    #[test]
    fn test_get_chain_height() {
        run_test(|indexer| {
            assert_eq!(indexer.get_chain_height(), 0);
            indexer.set_chain_height(42);
            assert_eq!(indexer.get_chain_height(), 42);
        });
    }

    fn run_test<F>(func: F)
            where F: FnOnce(Indexer) -> () + panic::UnwindSafe {
        let mut tmp_dir = env::temp_dir();
        let mut s = String::from("godcoin_test_");
        s.push_str(&thread_rng().sample_iter(&Alphanumeric).take(4).collect::<String>());
        tmp_dir.push(s);
        fs::create_dir(&tmp_dir).expect(&format!("Could not create temp dir {:?}", &tmp_dir));

        let result = panic::catch_unwind(|| {
            let indexer = Indexer::new(&tmp_dir);
            func(indexer);
        });

        fs::remove_dir_all(&tmp_dir).expect("Failed to rm dir");
        assert!(result.is_ok());
    }
}
<|endoftext|>


<commit_before>#[derive(Clone)]
pub struct VecMap<K, V> {
    vec: Vec<(K, V)>,
}

impl<K: PartialEq, V> VecMap<K, V> {
    #[inline]
    pub fn with_capacity(cap: usize) -> VecMap<K, V> {
        VecMap {
            vec: Vec::with_capacity(cap)
        }
    }

    #[inline]
    pub fn insert(&mut self, key: K, value: V) {
        match self.find(&key) {
            Some(pos) => self.vec[pos] = (key, value),
            None => self.vec.push((key, value))
        }
    }

    #[inline]
    pub fn entry(&mut self, key: K) -> Entry<K, V> {
        match self.find(&key) {
            Some(pos) => Entry::Occupied(OccupiedEntry {
                vec: self,
                pos: pos,
            }),
            None => Entry::Vacant(VacantEntry {
                vec: self,
                key: key,
            })
        }
    }

    #[inline]
    pub fn get<K2>(&self, key: &K2) -> Option<&V>
    where K2: PartialEq<K> + ?Sized {
        self.find(key).map(move |pos| &self.vec[pos].1)
    }

    #[inline]
    pub fn get_mut<K2>(&mut self, key: &K2) -> Option<&mut V>
    where K2: PartialEq<K> {
        self.find(key).map(move |pos| &mut self.vec[pos].1)
    }

    #[inline]
    pub fn contains_key<K2>(&self, key: &K2) -> bool
    where K2: PartialEq<K> {
        self.find(key).is_some()
    }

    #[inline]
    pub fn len(&self) -> usize { self.vec.len() }

    #[inline]
    pub fn iter(&self) -> ::std::slice::Iter<(K, V)> {
        self.vec.iter()
    }
    #[inline]
    pub fn remove<K2>(&mut self, key: &K2) -> Option<V>
    where K2: PartialEq<K> + ?Sized {
        self.find(key).map(|pos| self.vec.remove(pos)).map(|(_, v)| v)
    }
    #[inline]
    pub fn clear(&mut self) {
        self.vec.clear();
    }

    #[inline]
    fn find<K2>(&self, key: &K2) -> Option<usize>
    where K2: PartialEq<K> + ?Sized {
        self.vec.iter().position(|entry| key == &entry.0)
    }
}

pub enum Entry<'a, K: 'a, V: 'a> {
    Vacant(VacantEntry<'a, K, V>),
    Occupied(OccupiedEntry<'a, K, V>)
}

pub struct VacantEntry<'a, K: 'a, V: 'a> {
    vec: &'a mut VecMap<K, V>,
    key: K,
}

impl<'a, K, V> VacantEntry<'a, K, V> {
    pub fn insert(self, val: V) -> &'a mut V {
        let mut vec = self.vec;
        vec.vec.push((self.key, val));
        let pos = vec.vec.len() - 1;
        &mut vec.vec[pos].1
    }
}

pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
    vec: &'a mut VecMap<K, V>,
    pos: usize,
}

impl<'a, K, V> OccupiedEntry<'a, K, V> {
    pub fn into_mut(self) -> &'a mut V {
        &mut self.vec.vec[self.pos].1
    }
}
<commit_msg>style(header): remove ?Sized from where class to fix 1.10 build<commit_after>#[derive(Clone)]
pub struct VecMap<K, V> {
    vec: Vec<(K, V)>,
}

impl<K: PartialEq, V> VecMap<K, V> {
    #[inline]
    pub fn with_capacity(cap: usize) -> VecMap<K, V> {
        VecMap {
            vec: Vec::with_capacity(cap)
        }
    }

    #[inline]
    pub fn insert(&mut self, key: K, value: V) {
        match self.find(&key) {
            Some(pos) => self.vec[pos] = (key, value),
            None => self.vec.push((key, value))
        }
    }

    #[inline]
    pub fn entry(&mut self, key: K) -> Entry<K, V> {
        match self.find(&key) {
            Some(pos) => Entry::Occupied(OccupiedEntry {
                vec: self,
                pos: pos,
            }),
            None => Entry::Vacant(VacantEntry {
                vec: self,
                key: key,
            })
        }
    }

    #[inline]
    pub fn get<K2: PartialEq<K> + ?Sized>(&self, key: &K2) -> Option<&V> {
        self.find(key).map(move |pos| &self.vec[pos].1)
    }

    #[inline]
    pub fn get_mut<K2>(&mut self, key: &K2) -> Option<&mut V>
    where K2: PartialEq<K> {
        self.find(key).map(move |pos| &mut self.vec[pos].1)
    }

    #[inline]
    pub fn contains_key<K2>(&self, key: &K2) -> bool
    where K2: PartialEq<K> {
        self.find(key).is_some()
    }

    #[inline]
    pub fn len(&self) -> usize { self.vec.len() }

    #[inline]
    pub fn iter(&self) -> ::std::slice::Iter<(K, V)> {
        self.vec.iter()
    }
    #[inline]
    pub fn remove<K2: PartialEq<K> + ?Sized>(&mut self, key: &K2) -> Option<V> {
        self.find(key).map(|pos| self.vec.remove(pos)).map(|(_, v)| v)
    }
    #[inline]
    pub fn clear(&mut self) {
        self.vec.clear();
    }

    #[inline]
    fn find<K2>(&self, key: &K2) -> Option<usize>
    where K2: PartialEq<K> + ?Sized {
        self.vec.iter().position(|entry| key == &entry.0)
    }
}

pub enum Entry<'a, K: 'a, V: 'a> {
    Vacant(VacantEntry<'a, K, V>),
    Occupied(OccupiedEntry<'a, K, V>)
}

pub struct VacantEntry<'a, K: 'a, V: 'a> {
    vec: &'a mut VecMap<K, V>,
    key: K,
}

impl<'a, K, V> VacantEntry<'a, K, V> {
    pub fn insert(self, val: V) -> &'a mut V {
        let mut vec = self.vec;
        vec.vec.push((self.key, val));
        let pos = vec.vec.len() - 1;
        &mut vec.vec[pos].1
    }
}

pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
    vec: &'a mut VecMap<K, V>,
    pos: usize,
}

impl<'a, K, V> OccupiedEntry<'a, K, V> {
    pub fn into_mut(self) -> &'a mut V {
        &mut self.vec.vec[self.pos].1
    }
}
<|endoftext|>


<commit_before>use crate::common::*;
use crate::data::packet::Packet;
use crate::data::value::*;
use std::any::Any;
use std::io::{Cursor, ErrorKind, Seek, SeekFrom, Write};
use std::sync::Arc;

use crate::error::*;

/// A trait for a non-seekable object.
pub trait WriteOwned: Write + ToOwned {}
/// A trait for a seekable object.
pub trait WriteSeek: Write + Seek + ToOwned {}

impl<T: Write + ToOwned> WriteOwned for T {}
impl<T: Write + Seek + ToOwned> WriteSeek for T {}

/// Runtime wrapper around either a [`Write`] or a [`WriteSeek`] trait object which supports querying
/// for seek support.
pub enum Writer<WO = Cursor<Vec<u8>>, WS = Cursor<Vec<u8>>> {
    NonSeekable(WO, u64),
    Seekable(WS),
}

impl<WO: WriteOwned> Writer<WO, Cursor<Vec<u8>>> {
    /// Creates a [`Writer`] from an object that implements the [`Write`] trait.
    pub fn from_nonseekable(inner: WO) -> Self {
        Self::NonSeekable(inner, 0)
    }

    /// Returns the non-seekable object whether is present.
    pub fn non_seekable_object(&self) -> Option<(<WO as ToOwned>::Owned, u64)> {
        if let Self::NonSeekable(inner, index) = self {
            Some((inner.to_owned(), *index))
        } else {
            None
        }
    }
}

impl<WS: WriteSeek> Writer<Cursor<Vec<u8>>, WS> {
    /// Creates a [`Writer`] from an object that implements both [`Write`] and [`Seek`] traits.
    pub fn from_seekable(inner: WS) -> Self {
        Self::Seekable(inner)
    }

    /// Returns the seekable object whether is present.
    pub fn seekable_object(&self) -> Option<<WS as ToOwned>::Owned> {
        if let Self::Seekable(inner) = self {
            Some(inner.to_owned())
        } else {
            None
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Write for Writer<WO, WS> {
    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::NonSeekable(inner, ref mut index) => {
                let result = inner.write(bytes);

                if let Ok(written) = result {
                    *index += written as u64;
                }

                result
            }
            Self::Seekable(inner) => inner.write(bytes),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::NonSeekable(inner, ..) => inner.flush(),
            Self::Seekable(inner) => inner.flush(),
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Seek for Writer<WO, WS> {
    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
        match self {
            Self::NonSeekable(_, index) => {
                if let SeekFrom::Current(0) = seek {
                    Ok(*index)
                } else {
                    Err(std::io::Error::new(
                        ErrorKind::Other,
                        "Seeking not supported",
                    ))
                }
            }
            Self::Seekable(inner) => inner.seek(seek),
        }
    }
}

/// Used to implement muxing operations.
pub trait Muxer: Send {
    /// Configures a muxer.
    fn configure(&mut self) -> Result<()>;
    /// Writes a stream header into a data structure implementing
    /// the `Write` trait.
    fn write_header<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;
    /// Writes a stream packet into a data structure implementing
    /// the `Write` trait.
    fn write_packet<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
        pkt: Arc<Packet>,
    ) -> Result<()>;
    /// Writes a stream trailer into a data structure implementing
    /// the `Write` trait.
    fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;

    /// Sets global media file information for a muxer.
    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

/// Auxiliary structure to encapsulate a muxer object and
/// its additional data.
pub struct Context<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> {
    muxer: M,
    writer: Writer<WO, WS>,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Box<dyn Any + Send + Sync>>,
}

impl<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> Context<M, WO, WS> {
    /// Creates a new `Context` instance.
    pub fn new(muxer: M, writer: Writer<WO, WS>) -> Self {
        Context {
            muxer,
            writer,
            user_private: None,
        }
    }

    /// Configures a muxer.
    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    /// Writes a stream header to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_header(&mut self) -> Result<()> {
        self.muxer.write_header(&mut self.writer)
    }

    /// Writes a stream packet to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
        self.muxer.write_packet(&mut self.writer, pkt)
    }

    /// Writes a stream trailer to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_trailer(&mut self) -> Result<()> {
        self.muxer.write_trailer(&mut self.writer)?;
        self.writer.flush()?;

        Ok(())
    }

    /// Sets global media file information for a muxer.
    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
    where
        V: Into<Value<'a>>,
    {
        self.muxer.set_option(key, val.into())
    }

    /// Returns the underlying writer.
    pub fn writer(&self) -> &Writer<WO, WS> {
        &self.writer
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own muxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Muxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new muxer.
pub trait Descriptor {
    type OutputMuxer: Muxer + Send;

    /// Creates a new muxer for the requested format.
    fn create(&self) -> Self::OutputMuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;
}

/// Used to look for a specific format.
pub trait Lookup<T: Descriptor + ?Sized> {
    /// Retrieves a specific format by name.
    fn by_name(&self, name: &str) -> Option<&'static T>;
}

impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
    fn by_name(&self, name: &str) -> Option<&'static T> {
        self.iter().find(|&&d| d.describe().name == name).copied()
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::*;

    const DUMMY_HEADER_LENGTH: usize = 12;
    const DUMMY_PACKET_LENGTH: usize = 2;
    const DUMMY_PACKETS_NUMBER: usize = 2;
    const DUMMY_TRAILER_LENGTH: usize = 13;

    struct DummyDes {
        d: Descr,
    }

    struct DummyMuxer {}

    impl DummyMuxer {
        pub fn new() -> Self {
            Self {}
        }
    }

    impl Muxer for DummyMuxer {
        fn configure(&mut self) -> Result<()> {
            Ok(())
        }

        fn write_header<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
        ) -> Result<()> {
            let buf = b"Dummy header";
            out.write_all(buf.as_slice()).unwrap();
            Ok(())
        }

        fn write_packet<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
            pkt: Arc<Packet>,
        ) -> Result<()> {
            out.write_all(&pkt.data).unwrap();
            Ok(())
        }

        fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
        ) -> Result<()> {
            let buf = b"Dummy trailer";
            out.write_all(buf.as_slice()).unwrap();
            Ok(())
        }

        fn set_global_info(&mut self, _info: GlobalInfo) -> Result<()> {
            Ok(())
        }

        fn set_option<'a>(&mut self, _key: &str, _val: Value<'a>) -> Result<()> {
            Ok(())
        }
    }

    impl Descriptor for DummyDes {
        type OutputMuxer = DummyMuxer;

        fn create(&self) -> Self::OutputMuxer {
            DummyMuxer {}
        }
        fn describe(&self) -> &Descr {
            &self.d
        }
    }

    const DUMMY_DES: &dyn Descriptor<OutputMuxer = DummyMuxer> = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy mux",
            extensions: &["mx", "mux"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn lookup() {
        let muxers: &[&dyn Descriptor<OutputMuxer = DummyMuxer>] = &[DUMMY_DES];

        muxers.by_name("dummy").unwrap();
    }

    fn run_muxer<WO: WriteOwned, WS: WriteSeek>(
        writer: Writer<WO, WS>,
    ) -> Context<DummyMuxer, WO, WS> {
        let mux = DummyMuxer::new();

        let mut muxer = Context::new(mux, writer);

        muxer.configure().unwrap();
        muxer.write_header().unwrap();

        // Write zeroed packets of a certain size
        for _ in 0..DUMMY_PACKETS_NUMBER {
            let packet = Packet::zeroed(DUMMY_PACKET_LENGTH);
            muxer.write_packet(Arc::new(packet)).unwrap();
        }

        muxer.write_trailer().unwrap();
        muxer
    }

    fn check_underlying_buffer(buffer: Vec<u8>) {
        assert_eq!(
            buffer.get(..DUMMY_HEADER_LENGTH).unwrap(),
            b"Dummy header".as_slice()
        );

        assert_eq!(
            buffer
                // Get only packets, without header and trailer data
                .get(
                    DUMMY_HEADER_LENGTH
                        ..DUMMY_HEADER_LENGTH + (DUMMY_PACKETS_NUMBER * DUMMY_PACKET_LENGTH)
                )
                .unwrap(),
            &[0, 0, 0, 0]
        );

        assert_eq!(
            buffer
                // Skip header and packets
                .get(DUMMY_HEADER_LENGTH + (DUMMY_PACKETS_NUMBER * DUMMY_PACKET_LENGTH)..)
                .unwrap(),
            b"Dummy trailer".as_slice()
        );
    }

    #[test]
    fn non_seekable_muxer() {
        let muxer = run_muxer(Writer::from_nonseekable(Vec::new()));
        let (buffer, index) = muxer.writer().non_seekable_object().unwrap();
        check_underlying_buffer(buffer);
        assert_eq!(
            index as usize,
            DUMMY_HEADER_LENGTH
                + (DUMMY_PACKETS_NUMBER * DUMMY_PACKET_LENGTH)
                + DUMMY_TRAILER_LENGTH
        );
    }

    #[test]
    fn seekable_muxer() {
        let muxer = run_muxer(Writer::from_seekable(Cursor::new(Vec::new())));
        let buffer = muxer.writer().seekable_object().unwrap().into_inner();
        check_underlying_buffer(buffer);
    }
}
<commit_msg>format: Add an API to check if a source is seekable<commit_after>use crate::common::*;
use crate::data::packet::Packet;
use crate::data::value::*;
use std::any::Any;
use std::io::{Cursor, ErrorKind, Seek, SeekFrom, Write};
use std::sync::Arc;

use crate::error::*;

/// A trait for a non-seekable object.
pub trait WriteOwned: Write + ToOwned {}
/// A trait for a seekable object.
pub trait WriteSeek: Write + Seek + ToOwned {}

impl<T: Write + ToOwned> WriteOwned for T {}
impl<T: Write + Seek + ToOwned> WriteSeek for T {}

/// Runtime wrapper around either a [`Write`] or a [`WriteSeek`] trait object which supports querying
/// for seek support.
pub enum Writer<WO = Cursor<Vec<u8>>, WS = Cursor<Vec<u8>>> {
    NonSeekable(WO, u64),
    Seekable(WS),
}

impl<WO: WriteOwned> Writer<WO, Cursor<Vec<u8>>> {
    /// Creates a [`Writer`] from an object that implements the [`Write`] trait.
    pub fn from_nonseekable(inner: WO) -> Self {
        Self::NonSeekable(inner, 0)
    }

    /// Returns the non-seekable object whether is present.
    pub fn non_seekable_object(&self) -> Option<(<WO as ToOwned>::Owned, u64)> {
        if let Self::NonSeekable(inner, index) = self {
            Some((inner.to_owned(), *index))
        } else {
            None
        }
    }
}

impl<WS: WriteSeek> Writer<Cursor<Vec<u8>>, WS> {
    /// Creates a [`Writer`] from an object that implements both [`Write`] and [`Seek`] traits.
    pub fn from_seekable(inner: WS) -> Self {
        Self::Seekable(inner)
    }

    /// Returns the seekable object whether is present.
    pub fn seekable_object(&self) -> Option<<WS as ToOwned>::Owned> {
        if let Self::Seekable(inner) = self {
            Some(inner.to_owned())
        } else {
            None
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Writer<WO, WS> {
    /// Returns whether the [`Writer`] can seek within the source.
    pub fn is_seekable(&self) -> bool {
        matches!(self, Self::Seekable(_))
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Write for Writer<WO, WS> {
    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::NonSeekable(inner, ref mut index) => {
                let result = inner.write(bytes);

                if let Ok(written) = result {
                    *index += written as u64;
                }

                result
            }
            Self::Seekable(inner) => inner.write(bytes),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::NonSeekable(inner, ..) => inner.flush(),
            Self::Seekable(inner) => inner.flush(),
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Seek for Writer<WO, WS> {
    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
        match self {
            Self::NonSeekable(_, index) => {
                if let SeekFrom::Current(0) = seek {
                    Ok(*index)
                } else {
                    Err(std::io::Error::new(
                        ErrorKind::Other,
                        "Seeking not supported",
                    ))
                }
            }
            Self::Seekable(inner) => inner.seek(seek),
        }
    }
}

/// Used to implement muxing operations.
pub trait Muxer: Send {
    /// Configures a muxer.
    fn configure(&mut self) -> Result<()>;
    /// Writes a stream header into a data structure implementing
    /// the `Write` trait.
    fn write_header<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;
    /// Writes a stream packet into a data structure implementing
    /// the `Write` trait.
    fn write_packet<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
        pkt: Arc<Packet>,
    ) -> Result<()>;
    /// Writes a stream trailer into a data structure implementing
    /// the `Write` trait.
    fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;

    /// Sets global media file information for a muxer.
    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

/// Auxiliary structure to encapsulate a muxer object and
/// its additional data.
pub struct Context<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> {
    muxer: M,
    writer: Writer<WO, WS>,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Box<dyn Any + Send + Sync>>,
}

impl<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> Context<M, WO, WS> {
    /// Creates a new `Context` instance.
    pub fn new(muxer: M, writer: Writer<WO, WS>) -> Self {
        Context {
            muxer,
            writer,
            user_private: None,
        }
    }

    /// Configures a muxer.
    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    /// Writes a stream header to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_header(&mut self) -> Result<()> {
        self.muxer.write_header(&mut self.writer)
    }

    /// Writes a stream packet to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
        self.muxer.write_packet(&mut self.writer, pkt)
    }

    /// Writes a stream trailer to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_trailer(&mut self) -> Result<()> {
        self.muxer.write_trailer(&mut self.writer)?;
        self.writer.flush()?;

        Ok(())
    }

    /// Sets global media file information for a muxer.
    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
    where
        V: Into<Value<'a>>,
    {
        self.muxer.set_option(key, val.into())
    }

    /// Returns the underlying writer.
    pub fn writer(&self) -> &Writer<WO, WS> {
        &self.writer
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own muxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Muxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new muxer.
pub trait Descriptor {
    type OutputMuxer: Muxer + Send;

    /// Creates a new muxer for the requested format.
    fn create(&self) -> Self::OutputMuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;
}

/// Used to look for a specific format.
pub trait Lookup<T: Descriptor + ?Sized> {
    /// Retrieves a specific format by name.
    fn by_name(&self, name: &str) -> Option<&'static T>;
}

impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
    fn by_name(&self, name: &str) -> Option<&'static T> {
        self.iter().find(|&&d| d.describe().name == name).copied()
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::*;

    const DUMMY_HEADER_LENGTH: usize = 12;
    const DUMMY_PACKET_LENGTH: usize = 2;
    const DUMMY_PACKETS_NUMBER: usize = 2;
    const DUMMY_TRAILER_LENGTH: usize = 13;

    struct DummyDes {
        d: Descr,
    }

    struct DummyMuxer {}

    impl DummyMuxer {
        pub fn new() -> Self {
            Self {}
        }
    }

    impl Muxer for DummyMuxer {
        fn configure(&mut self) -> Result<()> {
            Ok(())
        }

        fn write_header<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
        ) -> Result<()> {
            let buf = b"Dummy header";
            out.write_all(buf.as_slice()).unwrap();
            Ok(())
        }

        fn write_packet<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
            pkt: Arc<Packet>,
        ) -> Result<()> {
            out.write_all(&pkt.data).unwrap();
            Ok(())
        }

        fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
        ) -> Result<()> {
            let buf = b"Dummy trailer";
            out.write_all(buf.as_slice()).unwrap();
            Ok(())
        }

        fn set_global_info(&mut self, _info: GlobalInfo) -> Result<()> {
            Ok(())
        }

        fn set_option<'a>(&mut self, _key: &str, _val: Value<'a>) -> Result<()> {
            Ok(())
        }
    }

    impl Descriptor for DummyDes {
        type OutputMuxer = DummyMuxer;

        fn create(&self) -> Self::OutputMuxer {
            DummyMuxer {}
        }
        fn describe(&self) -> &Descr {
            &self.d
        }
    }

    const DUMMY_DES: &dyn Descriptor<OutputMuxer = DummyMuxer> = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy mux",
            extensions: &["mx", "mux"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn lookup() {
        let muxers: &[&dyn Descriptor<OutputMuxer = DummyMuxer>] = &[DUMMY_DES];

        muxers.by_name("dummy").unwrap();
    }

    fn run_muxer<WO: WriteOwned, WS: WriteSeek>(
        writer: Writer<WO, WS>,
    ) -> Context<DummyMuxer, WO, WS> {
        let mux = DummyMuxer::new();

        let mut muxer = Context::new(mux, writer);

        muxer.configure().unwrap();
        muxer.write_header().unwrap();

        // Write zeroed packets of a certain size
        for _ in 0..DUMMY_PACKETS_NUMBER {
            let packet = Packet::zeroed(DUMMY_PACKET_LENGTH);
            muxer.write_packet(Arc::new(packet)).unwrap();
        }

        muxer.write_trailer().unwrap();
        muxer
    }

    fn check_underlying_buffer(buffer: Vec<u8>) {
        assert_eq!(
            buffer.get(..DUMMY_HEADER_LENGTH).unwrap(),
            b"Dummy header".as_slice()
        );

        assert_eq!(
            buffer
                // Get only packets, without header and trailer data
                .get(
                    DUMMY_HEADER_LENGTH
                        ..DUMMY_HEADER_LENGTH + (DUMMY_PACKETS_NUMBER * DUMMY_PACKET_LENGTH)
                )
                .unwrap(),
            &[0, 0, 0, 0]
        );

        assert_eq!(
            buffer
                // Skip header and packets
                .get(DUMMY_HEADER_LENGTH + (DUMMY_PACKETS_NUMBER * DUMMY_PACKET_LENGTH)..)
                .unwrap(),
            b"Dummy trailer".as_slice()
        );
    }

    #[test]
    fn non_seekable_muxer() {
        let muxer = run_muxer(Writer::from_nonseekable(Vec::new()));
        let (buffer, index) = muxer.writer().non_seekable_object().unwrap();
        debug_assert!(!muxer.writer().is_seekable());
        check_underlying_buffer(buffer);
        assert_eq!(
            index as usize,
            DUMMY_HEADER_LENGTH
                + (DUMMY_PACKETS_NUMBER * DUMMY_PACKET_LENGTH)
                + DUMMY_TRAILER_LENGTH
        );
    }

    #[test]
    fn seekable_muxer() {
        let muxer = run_muxer(Writer::from_seekable(Cursor::new(Vec::new())));
        let buffer = muxer.writer().seekable_object().unwrap().into_inner();
        debug_assert!(muxer.writer().is_seekable());
        check_underlying_buffer(buffer);
    }
}
<|endoftext|>


<commit_before>use std::kinds::marker::ContravariantLifetime;
use std::mem;

use runtime::Object;
use {class, Id, IdVector, IntoIdVector, Owned, Ownership, Shared, ShareId};
use super::{INSCopying, INSObject};

pub struct NSRange {
	pub location: uint,
	pub length: uint,
}

pub struct NSEnumerator<'a, T> {
	id: Id<Object>,
	marker: ContravariantLifetime<'a>,
}

impl<'a, T> NSEnumerator<'a, T> {
	pub unsafe fn from_ptr(ptr: *mut Object) -> NSEnumerator<'a, T> {
		NSEnumerator { id: Id::from_ptr(ptr), marker: ContravariantLifetime }
	}
}

impl<'a, T> Iterator<&'a T> for NSEnumerator<'a, T> {
	fn next(&mut self) -> Option<&'a T> {
		unsafe {
			let obj = msg_send![self.id nextObject] as *mut T;
			if obj.is_null() {
				None
			} else {
				Some(&*obj)
			}
		}
	}
}

pub trait INSArray<T: INSObject, O: Ownership> : INSObject {
	fn count(&self) -> uint {
		let result = unsafe {
			msg_send![self count]
		};
		result as uint
	}

	fn object_at(&self, index: uint) -> &T {
		unsafe {
			let result = msg_send![self objectAtIndex:index] as *mut T;
			&*result
		}
	}

	fn object_enumerator(&self) -> NSEnumerator<T> {
		unsafe {
			let result = msg_send![self objectEnumerator];
			NSEnumerator::from_ptr(result)
		}
	}

	unsafe fn from_refs(refs: &[&T]) -> Id<Self> {
		let cls = class::<Self>();
		let obj = msg_send![cls alloc];
		let obj = msg_send![obj initWithObjects:refs.as_ptr() count:refs.len()];
		Id::from_retained_ptr(obj as *mut Self)
	}

	fn from_vec(vec: Vec<Id<T, O>>) -> Id<Self> {
		let refs = vec.as_refs_slice();
		unsafe {
			INSArray::from_refs(refs)
		}
	}

	fn objects_in_range(&self, start: uint, len: uint) -> Vec<&T> {
		let vec: Vec<*mut T> = Vec::from_elem(len, RawPtr::null());
		let range = NSRange { location: start, length: len };
		unsafe {
			msg_send![self getObjects:vec.as_ptr() range:range];
			mem::transmute(vec)
		}
	}

	fn to_vec(&self) -> Vec<&T> {
		self.objects_in_range(0, self.count())
	}

	fn into_vec(array: Id<Self>) -> Vec<Id<T, O>> {
		let vec = array.to_vec();
		unsafe {
			vec.into_id_vec()
		}
	}
}

pub trait INSOwnedArray<T: INSObject> : INSArray<T, Owned> {
	fn mut_object_at(&mut self, index: uint) -> &mut T {
		unsafe {
			let result = msg_send![self objectAtIndex:index] as *mut T;
			&mut *result
		}
	}
}

pub trait INSSharedArray<T: INSObject> : INSArray<T, Shared> {
	fn shared_object_at(&self, index: uint) -> ShareId<T> {
		let obj = self.object_at(index);
		unsafe {
			Id::from_ptr(obj as *const _ as *mut T)
		}
	}

	fn from_slice(slice: &[ShareId<T>]) -> Id<Self> {
		let refs = slice.as_refs_slice();
		unsafe {
			INSArray::from_refs(refs)
		}
	}

	fn to_shared_vec(&self) -> Vec<ShareId<T>> {
		let vec = self.to_vec();
		unsafe {
			vec.into_id_vec()
		}
	}
}

object_struct!(NSArray<T>)

impl<T: INSObject> INSArray<T, Owned> for NSArray<T> { }

impl<T: INSObject> INSOwnedArray<T> for NSArray<T> { }

impl<T> INSCopying<NSArray<T>> for NSArray<T> { }

impl<T: INSObject> Collection for NSArray<T> {
	fn len(&self) -> uint {
		self.count()
	}
}

impl<T: INSObject> Index<uint, T> for NSArray<T> {
	fn index(&self, index: &uint) -> &T {
		self.object_at(*index)
	}
}

#[cfg(test)]
mod tests {
	use {Id};
	use foundation::{INSObject, NSObject};
	use super::{INSArray, NSArray};

	fn sample_array(len: uint) -> Id<NSArray<NSObject>> {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(len, |_| INSObject::new());
		INSArray::from_vec(vec)
	}

	#[test]
	fn test_count() {
		let empty_array: Id<NSArray<NSObject>> = INSObject::new();
		assert!(empty_array.count() == 0);

		let array = sample_array(4);
		assert!(array.count() == 4);
	}

	#[test]
	fn test_object_at() {
		let array = sample_array(4);
		assert!(array.object_at(0) != array.object_at(3));
	}

	#[test]
	fn test_object_enumerator() {
		let array = sample_array(4);

		assert!(array.object_enumerator().count() == 4);
		assert!(array.object_enumerator()
		             .enumerate()
		             .all(|(i, obj)| obj == array.object_at(i)));
	}

	#[test]
	fn test_objects_in_range() {
		let array = sample_array(4);

		let middle_objs = array.objects_in_range(1, 2);
		assert!(middle_objs.len() == 2);
		assert!(*middle_objs.get(0) == array.object_at(1));
		assert!(*middle_objs.get(1) == array.object_at(2));

		let empty_objs = array.objects_in_range(1, 0);
		assert!(empty_objs.len() == 0);

		let all_objs = array.objects_in_range(0, 4);
		assert!(all_objs.len() == 4);
	}

	#[test]
	fn test_into_vec() {
		let array = sample_array(4);

		let vec = INSArray::into_vec(array);
		assert!(vec.len() == 4);
	}
}
<commit_msg>Added INSMutableArray trait.<commit_after>use std::kinds::marker::ContravariantLifetime;
use std::mem;

use runtime::Object;
use {class, Id, IdVector, IntoIdVector, Owned, Ownership, Shared, ShareId};
use super::{INSCopying, INSObject};

pub struct NSRange {
	pub location: uint,
	pub length: uint,
}

pub struct NSEnumerator<'a, T> {
	id: Id<Object>,
	marker: ContravariantLifetime<'a>,
}

impl<'a, T> NSEnumerator<'a, T> {
	pub unsafe fn from_ptr(ptr: *mut Object) -> NSEnumerator<'a, T> {
		NSEnumerator { id: Id::from_ptr(ptr), marker: ContravariantLifetime }
	}
}

impl<'a, T> Iterator<&'a T> for NSEnumerator<'a, T> {
	fn next(&mut self) -> Option<&'a T> {
		unsafe {
			let obj = msg_send![self.id nextObject] as *mut T;
			if obj.is_null() {
				None
			} else {
				Some(&*obj)
			}
		}
	}
}

pub trait INSArray<T: INSObject, O: Ownership> : INSObject {
	fn count(&self) -> uint {
		let result = unsafe {
			msg_send![self count]
		};
		result as uint
	}

	fn object_at(&self, index: uint) -> &T {
		unsafe {
			let result = msg_send![self objectAtIndex:index] as *mut T;
			&*result
		}
	}

	fn object_enumerator(&self) -> NSEnumerator<T> {
		unsafe {
			let result = msg_send![self objectEnumerator];
			NSEnumerator::from_ptr(result)
		}
	}

	unsafe fn from_refs(refs: &[&T]) -> Id<Self> {
		let cls = class::<Self>();
		let obj = msg_send![cls alloc];
		let obj = msg_send![obj initWithObjects:refs.as_ptr() count:refs.len()];
		Id::from_retained_ptr(obj as *mut Self)
	}

	fn from_vec(vec: Vec<Id<T, O>>) -> Id<Self> {
		let refs = vec.as_refs_slice();
		unsafe {
			INSArray::from_refs(refs)
		}
	}

	fn objects_in_range(&self, start: uint, len: uint) -> Vec<&T> {
		let vec: Vec<*mut T> = Vec::from_elem(len, RawPtr::null());
		let range = NSRange { location: start, length: len };
		unsafe {
			msg_send![self getObjects:vec.as_ptr() range:range];
			mem::transmute(vec)
		}
	}

	fn to_vec(&self) -> Vec<&T> {
		self.objects_in_range(0, self.count())
	}

	fn into_vec(array: Id<Self>) -> Vec<Id<T, O>> {
		let vec = array.to_vec();
		unsafe {
			vec.into_id_vec()
		}
	}
}

pub trait INSOwnedArray<T: INSObject> : INSArray<T, Owned> {
	fn mut_object_at(&mut self, index: uint) -> &mut T {
		unsafe {
			let result = msg_send![self objectAtIndex:index] as *mut T;
			&mut *result
		}
	}
}

pub trait INSSharedArray<T: INSObject> : INSArray<T, Shared> {
	fn shared_object_at(&self, index: uint) -> ShareId<T> {
		let obj = self.object_at(index);
		unsafe {
			Id::from_ptr(obj as *const _ as *mut T)
		}
	}

	fn from_slice(slice: &[ShareId<T>]) -> Id<Self> {
		let refs = slice.as_refs_slice();
		unsafe {
			INSArray::from_refs(refs)
		}
	}

	fn to_shared_vec(&self) -> Vec<ShareId<T>> {
		let vec = self.to_vec();
		unsafe {
			vec.into_id_vec()
		}
	}
}

object_struct!(NSArray<T>)

impl<T: INSObject> INSArray<T, Owned> for NSArray<T> { }

impl<T: INSObject> INSOwnedArray<T> for NSArray<T> { }

impl<T> INSCopying<NSArray<T>> for NSArray<T> { }

impl<T: INSObject> Collection for NSArray<T> {
	fn len(&self) -> uint {
		self.count()
	}
}

impl<T: INSObject> Index<uint, T> for NSArray<T> {
	fn index(&self, index: &uint) -> &T {
		self.object_at(*index)
	}
}

pub trait INSMutableArray<T: INSObject, O: Ownership> : INSArray<T, O> {
	fn add_object(&mut self, obj: Id<T, O>) {
		unsafe {
			msg_send![self addObject:obj];
		}
	}

	fn insert_object_at(&mut self, index: uint, obj: Id<T, O>) {
		unsafe {
			msg_send![self insertObject:obj atIndex:index];
		}
	}

	fn remove_object_at(&mut self, index: uint) {
		unsafe {
			msg_send![self removeObjectAtIndex:index];
		}
	}
}

#[cfg(test)]
mod tests {
	use {Id};
	use foundation::{INSObject, NSObject};
	use super::{INSArray, NSArray};

	fn sample_array(len: uint) -> Id<NSArray<NSObject>> {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(len, |_| INSObject::new());
		INSArray::from_vec(vec)
	}

	#[test]
	fn test_count() {
		let empty_array: Id<NSArray<NSObject>> = INSObject::new();
		assert!(empty_array.count() == 0);

		let array = sample_array(4);
		assert!(array.count() == 4);
	}

	#[test]
	fn test_object_at() {
		let array = sample_array(4);
		assert!(array.object_at(0) != array.object_at(3));
	}

	#[test]
	fn test_object_enumerator() {
		let array = sample_array(4);

		assert!(array.object_enumerator().count() == 4);
		assert!(array.object_enumerator()
		             .enumerate()
		             .all(|(i, obj)| obj == array.object_at(i)));
	}

	#[test]
	fn test_objects_in_range() {
		let array = sample_array(4);

		let middle_objs = array.objects_in_range(1, 2);
		assert!(middle_objs.len() == 2);
		assert!(*middle_objs.get(0) == array.object_at(1));
		assert!(*middle_objs.get(1) == array.object_at(2));

		let empty_objs = array.objects_in_range(1, 0);
		assert!(empty_objs.len() == 0);

		let all_objs = array.objects_in_range(0, 4);
		assert!(all_objs.len() == 4);
	}

	#[test]
	fn test_into_vec() {
		let array = sample_array(4);

		let vec = INSArray::into_vec(array);
		assert!(vec.len() == 4);
	}
}
<|endoftext|>


<commit_before>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 Lumol's contributors — BSD license
use toml::Table;
use std::path::PathBuf;

use lumol::sys::{read_molecule, molecule_type};
use lumol::sim::mc::*;
use lumol::units;

use error::{Error, Result};
use FromTomlWithData;
use extract;
use simulations::get_input_path;

impl FromTomlWithData for MonteCarlo {
    type Data = PathBuf;
    fn from_toml(config: &Table, root: PathBuf) -> Result<MonteCarlo> {
        let temperature = try!(extract::str("temperature", config, "Monte-Carlo propagator"));
        let temperature = try!(units::from_str(temperature));

        let mut mc = MonteCarlo::new(temperature);

        let moves = try!(extract::slice("moves", config, "Monte-Carlo propagator"));
        for mc_move in moves {
            let mc_move = try!(mc_move.as_table().ok_or(
                Error::from("All moves must be tables in Monte-Carlo")
            ));

            let frequency = if mc_move.get("frequency").is_some() {
                try!(extract::number("frequency", mc_move, "Monte-Carlo move"))
            } else {
                1.0
            };

            let mc_move: Box<MCMove> = match try!(extract::typ(mc_move, "Monte-Carlo move")) {
                "Translate" => Box::new(try!(Translate::from_toml(mc_move, root.clone()))),
                "Rotate" => Box::new(try!(Rotate::from_toml(mc_move, root.clone()))),
                "Resize" => Box::new(try!(Resize::from_toml(mc_move, root.clone()))),
                other => return Err(Error::from(
                    format!("Unknown Monte-Carlo move '{}'", other)
                ))
            };

            mc.add(mc_move, frequency);
        }
        return Ok(mc);
    }
}

impl FromTomlWithData for Translate {
    type Data = PathBuf;
    fn from_toml(config: &Table, root: PathBuf) -> Result<Translate> {
        let delta = try!(extract::str("delta", config, "Translate move"));
        let delta = try!(units::from_str(delta));

        if config.get("molecule").is_some() {
            let molfile = try!(extract::str("molecule", config, "Translate move"));
            let molfile = get_input_path(root, molfile);
            let (molecule, atoms) = try!(read_molecule(molfile));
            let moltype = molecule_type(&molecule, &atoms);
            Ok(Translate::with_moltype(delta, moltype))
        } else {
            Ok(Translate::new(delta))
        }
    }
}

impl FromTomlWithData for Rotate {
    type Data = PathBuf;
    fn from_toml(config: &Table, root: PathBuf) -> Result<Rotate> {
        let delta = try!(extract::str("delta", config, "Rotate move"));
        let delta = try!(units::from_str(delta));

        if config.get("molecule").is_some() {
            let molfile = try!(extract::str("molecule", config, "Rotate move"));
            let molfile = get_input_path(root, molfile);
            let (molecule, atoms) = try!(read_molecule(molfile));
            let moltype = molecule_type(&molecule, &atoms);
            Ok(Rotate::with_moltype(delta, moltype))
        } else {
            Ok(Rotate::new(delta))
        }
    }
}

impl FromTomlWithData for Resize {
    type Data = PathBuf;
    fn from_toml(config: &Table, _: PathBuf) -> Result<Resize> {
        let pressure = try!(extract::str("pressure", config, "Resize move"));
        let pressure = try!(units::from_str(pressure));

        let delta = try!(extract::str("delta", config, "Resize move"));
        let delta = try!(units::from_str(delta));

        Ok(Resize::new(pressure, delta))
    }
}
<commit_msg>Add input support for move acceptance and update frequency.<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 Lumol's contributors — BSD license
use toml::Table;
use std::path::PathBuf;

use lumol::sys::{read_molecule, molecule_type};
use lumol::sim::mc::*;
use lumol::units;

use error::{Error, Result};
use FromTomlWithData;
use extract;
use simulations::get_input_path;

impl FromTomlWithData for MonteCarlo {
    type Data = PathBuf;
    fn from_toml(config: &Table, root: PathBuf) -> Result<MonteCarlo> {
        let temperature = try!(extract::str("temperature", config, "Monte-Carlo propagator"));
        let temperature = try!(units::from_str(temperature));

        let mut mc = MonteCarlo::new(temperature);

        if config.get("update_delta_every").is_some() {
            let update_amplitude = try!(extract::uint(
                    "update_delta_every", config, "Monte-Carlo propagator"));
            mc.set_amplitude_update_frequency(update_amplitude);
        }

        let moves = try!(extract::slice("moves", config, "Monte-Carlo propagator"));
        for mc_move in moves {
            let mc_move = try!(mc_move.as_table().ok_or(
                Error::from("All moves must be tables in Monte-Carlo")
            ));

            let frequency = if mc_move.get("frequency").is_some() {
                try!(extract::number("frequency", mc_move, "Monte-Carlo move"))
            } else {
                1.0
            };

            let target_acceptance = if mc_move.get("target_acceptance").is_some() {
                Some(try!(extract::number("target_acceptance", mc_move, "Monte-Carlo move")))
            } else {
                None
            };

            let mc_move: Box<MCMove> = match try!(extract::typ(mc_move, "Monte-Carlo move")) {
                "Translate" => Box::new(try!(Translate::from_toml(mc_move, root.clone()))),
                "Rotate" => Box::new(try!(Rotate::from_toml(mc_move, root.clone()))),
                "Resize" => Box::new(try!(Resize::from_toml(mc_move, root.clone()))),
                other => return Err(Error::from(
                    format!("Unknown Monte-Carlo move '{}'", other)
                ))
            };

            match target_acceptance {
                Some(ta) => mc.add_move_with_acceptance(mc_move, frequency, ta),
                None     => mc.add(mc_move, frequency),
            }
        }
        return Ok(mc);
    }
}

impl FromTomlWithData for Translate {
    type Data = PathBuf;
    fn from_toml(config: &Table, root: PathBuf) -> Result<Translate> {
        let delta = try!(extract::str("delta", config, "Translate move"));
        let delta = try!(units::from_str(delta));

        if config.get("molecule").is_some() {
            let molfile = try!(extract::str("molecule", config, "Translate move"));
            let molfile = get_input_path(root, molfile);
            let (molecule, atoms) = try!(read_molecule(molfile));
            let moltype = molecule_type(&molecule, &atoms);
            Ok(Translate::with_moltype(delta, moltype))
        } else {
            Ok(Translate::new(delta))
        }
    }
}

impl FromTomlWithData for Rotate {
    type Data = PathBuf;
    fn from_toml(config: &Table, root: PathBuf) -> Result<Rotate> {
        let delta = try!(extract::str("delta", config, "Rotate move"));
        let delta = try!(units::from_str(delta));

        if config.get("molecule").is_some() {
            let molfile = try!(extract::str("molecule", config, "Rotate move"));
            let molfile = get_input_path(root, molfile);
            let (molecule, atoms) = try!(read_molecule(molfile));
            let moltype = molecule_type(&molecule, &atoms);
            Ok(Rotate::with_moltype(delta, moltype))
        } else {
            Ok(Rotate::new(delta))
        }
    }
}

impl FromTomlWithData for Resize {
    type Data = PathBuf;
    fn from_toml(config: &Table, _: PathBuf) -> Result<Resize> {
        let pressure = try!(extract::str("pressure", config, "Resize move"));
        let pressure = try!(units::from_str(pressure));

        let delta = try!(extract::str("delta", config, "Resize move"));
        let delta = try!(units::from_str(delta));

        Ok(Resize::new(pressure, delta))
    }
}

<|endoftext|>