<commit_before>#![allow(unstable)]

extern crate "fsevent-sys" as fsevent;
extern crate libc;

use fsevent::core_foundation as cf;
use fsevent::fsevent as fs;

use std::ffi::CString;
use std::mem::transmute;
use std::slice::from_raw_mut_buf;
use std::raw::Slice;
use std::str::from_utf8;
use std::ffi::c_str_to_bytes;

pub const NULL: cf::CFRef = cf::NULL;

pub struct FsEvent<'a> {
  paths: cf::CFMutableArrayRef,
  since_when: fs::FSEventStreamEventId,
  latency: cf::CFTimeInterval,
  flags: fs::FSEventStreamCreateFlags,
  pub callback: FsEventCallback,
}

#[derive(Show)]
pub struct Event<'path> {
  event_id: u64,
  flag: u32,
  path: &'path str
}

pub type FsEventCallback = fn(Vec<Event>);

pub fn is_api_available() -> (bool, String) {
  let ma = cf::system_version_major();
  let mi = cf::system_version_minor();

  if ma == 10 && mi < 5 {
    return (false, "This version of OSX does not support the FSEvent library, cannot proceed".to_string());
  }
  return (true, "ok".to_string());
}

fn default_stream_context(info: *const FsEvent) -> fs::FSEventStreamContext {
  let ptr = info as *mut libc::c_void;
  let stream_context = fs::FSEventStreamContext{
    version: 0,
    info: ptr,
    retain: cf::NULL,
    copy_description: cf::NULL };

  stream_context
}

impl<'a> FsEvent<'a> {
  pub fn new(callback: FsEventCallback) -> FsEvent<'a> {
    let fsevent: FsEvent;
    unsafe {
      fsevent = FsEvent{
        paths: cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks),
        since_when: fs::kFSEventStreamEventIdSinceNow,
        latency: 0.1,
        flags: fs::kFSEventStreamCreateFlagNone,
        callback: callback,
      };
    }
    fsevent
  }

  // https://github.com/thibaudgg/rb-fsevent/blob/master/ext/fsevent_watch/main.c
  pub fn append_path(&self,source: &str) {
    unsafe {
      let cp = CString::from_slice(source.as_bytes());
      let c_path = cp.as_slice_with_nul();
      let mut url = cf::CFURLCreateFromFileSystemRepresentation(cf::kCFAllocatorDefault, c_path.as_ptr(), c_path.len() as i64, false);
      let mut placeholder = cf::CFURLCopyAbsoluteURL(url);
      cf::CFRelease(url);

      let imaginary: cf::CFRef = cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks);

      while !cf::CFURLResourceIsReachable(placeholder, cf::kCFAllocatorDefault) {

        let child = cf::CFURLCopyLastPathComponent(placeholder);
        cf::CFArrayInsertValueAtIndex(imaginary, 0, child);
        cf::CFRelease(child);

        url = cf::CFURLCreateCopyDeletingLastPathComponent(cf::kCFAllocatorDefault, placeholder);
        cf::CFRelease(placeholder);
        placeholder = url;
      }

      url = cf::CFURLCreateFileReferenceURL(cf::kCFAllocatorDefault, placeholder, cf::kCFAllocatorDefault);
      cf::CFRelease(placeholder);
      placeholder = cf::CFURLCreateFilePathURL(cf::kCFAllocatorDefault, url, cf::kCFAllocatorDefault);
      cf::CFRelease(url);

      if imaginary != cf::kCFAllocatorDefault {
        let mut count =  0;
        while { count < cf::CFArrayGetCount(imaginary) }
        {
          let component = cf::CFArrayGetValueAtIndex(imaginary, count);
          url = cf::CFURLCreateCopyAppendingPathComponent(cf::kCFAllocatorDefault, placeholder, component, false);
          cf::CFRelease(placeholder);
          placeholder = url;
          count = count + 1;
        }
        cf::CFRelease(imaginary);
      }

      let cf_path = cf::CFURLCopyFileSystemPath(placeholder, cf::kCFURLPOSIXPathStyle);
      cf::CFArrayAppendValue(self.paths, cf_path);
      cf::CFRelease(cf_path);
      cf::CFRelease(placeholder);
    }
  }
  pub fn observe(&self) {
    let stream_context = default_stream_context(self);

    let cb = callback as *mut _;

    unsafe {
      let stream = fs::FSEventStreamCreate(cf::kCFAllocatorDefault,
       cb,
       &stream_context,
       self.paths,
       self.since_when,
       self.latency,
       self.flags);

      fs::FSEventStreamShow(stream);

      fs::FSEventStreamScheduleWithRunLoop(stream,
        cf::CFRunLoopGetCurrent(),
        cf::kCFRunLoopDefaultMode);

      fs::FSEventStreamStart(stream);
      cf::CFRunLoopRun();
      fs::FSEventStreamFlushSync(stream);
      fs::FSEventStreamStop(stream);

    }
  }
}

fn from_c_str<'a>(p: &'a *const libc::c_char) -> &'a str {
    std::str::from_utf8( unsafe { std::ffi::c_str_to_bytes(p) } ).ok().expect("Found invalid utf8")
}

pub fn callback(
    stream_ref: fs::FSEventStreamRef,
    info: *mut libc::c_void,
    num_events: libc::size_t,      // size_t numEvents
    event_paths: *const *const libc::c_char, // void *eventPaths
    event_flags: *mut libc::c_void, // const FSEventStreamEventFlags eventFlags[]
    event_ids: *mut libc::c_void,  // const FSEventStreamEventId eventIds[]
  ) {
    let num = num_events as usize;
    let e_ptr = event_flags as *mut u32;
    let i_ptr = event_ids as *mut u64;
    let fs_event = info as *mut FsEvent;

    let mut events: Vec<Event> = Vec::new();

    unsafe {
      let paths: &[*const libc::c_char] = transmute(Slice { data: event_paths, len: num });
      let flags = from_raw_mut_buf(&e_ptr, num);
      let ids = from_raw_mut_buf(&i_ptr, num);

      for p in (0..num) {
        let path = from_utf8(c_str_to_bytes(&paths[p])).ok().expect("Bad UTF-8");
        events.push(Event{event_id: ids[p], flag: flags[p], path: path});
      }

      unsafe {
        let fs_e = *fs_event;
        (fs_e.callback)(events);
      }
    }

}<commit_msg>Yes (thanks @kalizoy)<commit_after>#![allow(unstable)]

extern crate "fsevent-sys" as fsevent;
extern crate libc;

use fsevent::core_foundation as cf;
use fsevent::fsevent as fs;

use std::ffi::CString;
use std::mem::transmute;
use std::slice::from_raw_mut_buf;
use std::raw::Slice;
use std::str::from_utf8;
use std::ffi::c_str_to_bytes;

pub const NULL: cf::CFRef = cf::NULL;

pub struct FsEvent<'a> {
  paths: cf::CFMutableArrayRef,
  since_when: fs::FSEventStreamEventId,
  latency: cf::CFTimeInterval,
  flags: fs::FSEventStreamCreateFlags,
  pub callback: FsEventCallback,
}

#[derive(Show)]
pub struct Event<'path> {
  event_id: u64,
  flag: u32,
  path: &'path str
}

pub type FsEventCallback = fn(Vec<Event>);

pub fn is_api_available() -> (bool, String) {
  let ma = cf::system_version_major();
  let mi = cf::system_version_minor();

  if ma == 10 && mi < 5 {
    return (false, "This version of OSX does not support the FSEvent library, cannot proceed".to_string());
  }
  return (true, "ok".to_string());
}

fn default_stream_context(info: *const FsEvent) -> fs::FSEventStreamContext {
  let ptr = info as *mut libc::c_void;
  let stream_context = fs::FSEventStreamContext{
    version: 0,
    info: ptr,
    retain: cf::NULL,
    copy_description: cf::NULL };

  stream_context
}

impl<'a> FsEvent<'a> {
  pub fn new(callback: FsEventCallback) -> FsEvent<'a> {
    let fsevent: FsEvent;
    unsafe {
      fsevent = FsEvent{
        paths: cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks),
        since_when: fs::kFSEventStreamEventIdSinceNow,
        latency: 0.1,
        flags: fs::kFSEventStreamCreateFlagNone,
        callback: callback,
      };
    }
    fsevent
  }

  // https://github.com/thibaudgg/rb-fsevent/blob/master/ext/fsevent_watch/main.c
  pub fn append_path(&self,source: &str) {
    unsafe {
      let cp = CString::from_slice(source.as_bytes());
      let c_path = cp.as_slice_with_nul();
      let mut url = cf::CFURLCreateFromFileSystemRepresentation(cf::kCFAllocatorDefault, c_path.as_ptr(), c_path.len() as i64, false);
      let mut placeholder = cf::CFURLCopyAbsoluteURL(url);
      cf::CFRelease(url);

      let imaginary: cf::CFRef = cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks);

      while !cf::CFURLResourceIsReachable(placeholder, cf::kCFAllocatorDefault) {

        let child = cf::CFURLCopyLastPathComponent(placeholder);
        cf::CFArrayInsertValueAtIndex(imaginary, 0, child);
        cf::CFRelease(child);

        url = cf::CFURLCreateCopyDeletingLastPathComponent(cf::kCFAllocatorDefault, placeholder);
        cf::CFRelease(placeholder);
        placeholder = url;
      }

      url = cf::CFURLCreateFileReferenceURL(cf::kCFAllocatorDefault, placeholder, cf::kCFAllocatorDefault);
      cf::CFRelease(placeholder);
      placeholder = cf::CFURLCreateFilePathURL(cf::kCFAllocatorDefault, url, cf::kCFAllocatorDefault);
      cf::CFRelease(url);

      if imaginary != cf::kCFAllocatorDefault {
        let mut count =  0;
        while { count < cf::CFArrayGetCount(imaginary) }
        {
          let component = cf::CFArrayGetValueAtIndex(imaginary, count);
          url = cf::CFURLCreateCopyAppendingPathComponent(cf::kCFAllocatorDefault, placeholder, component, false);
          cf::CFRelease(placeholder);
          placeholder = url;
          count = count + 1;
        }
        cf::CFRelease(imaginary);
      }

      let cf_path = cf::CFURLCopyFileSystemPath(placeholder, cf::kCFURLPOSIXPathStyle);
      cf::CFArrayAppendValue(self.paths, cf_path);
      cf::CFRelease(cf_path);
      cf::CFRelease(placeholder);
    }
  }
  pub fn observe(&self) {
    let stream_context = default_stream_context(self);

    let cb = callback as *mut _;

    unsafe {
      let stream = fs::FSEventStreamCreate(cf::kCFAllocatorDefault,
       cb,
       &stream_context,
       self.paths,
       self.since_when,
       self.latency,
       self.flags);

      fs::FSEventStreamShow(stream);

      fs::FSEventStreamScheduleWithRunLoop(stream,
        cf::CFRunLoopGetCurrent(),
        cf::kCFRunLoopDefaultMode);

      fs::FSEventStreamStart(stream);
      cf::CFRunLoopRun();
      fs::FSEventStreamFlushSync(stream);
      fs::FSEventStreamStop(stream);

    }
  }
}

fn from_c_str<'a>(p: &'a *const libc::c_char) -> &'a str {
    std::str::from_utf8( unsafe { std::ffi::c_str_to_bytes(p) } ).ok().expect("Found invalid utf8")
}

pub fn callback(
    stream_ref: fs::FSEventStreamRef,
    info: *mut libc::c_void,
    num_events: libc::size_t,      // size_t numEvents
    event_paths: *const *const libc::c_char, // void *eventPaths
    event_flags: *mut libc::c_void, // const FSEventStreamEventFlags eventFlags[]
    event_ids: *mut libc::c_void,  // const FSEventStreamEventId eventIds[]
  ) {
    let num = num_events as usize;
    let e_ptr = event_flags as *mut u32;
    let i_ptr = event_ids as *mut u64;
    let fs_event = info as *mut FsEvent;

    let mut events: Vec<Event> = Vec::new();

    unsafe {
      let paths: &[*const libc::c_char] = transmute(Slice { data: event_paths, len: num });
      let flags = from_raw_mut_buf(&e_ptr, num);
      let ids = from_raw_mut_buf(&i_ptr, num);

      for p in (0..num) {
        let path = from_utf8(c_str_to_bytes(&paths[p])).ok().expect("Bad UTF-8");
        events.push(Event{event_id: ids[p], flag: flags[p], path: path});
      }

      unsafe {
        ((*fs_event).callback)(events)
      }
    }

}<|endoftext|>


<commit_before>use std::mem;

use rustc::ty::{self, layout::{self, Size, Align}};
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc::mir;

use rand::RngCore;

use crate::*;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}

pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    /// Gets an instance for a path.
    fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> {
        let this = self.eval_context_ref();
        this.tcx
            .crates()
            .iter()
            .find(|&&krate| this.tcx.original_crate_name(krate).as_str() == path[0])
            .and_then(|krate| {
                let krate = DefId {
                    krate: *krate,
                    index: CRATE_DEF_INDEX,
                };
                let mut items = this.tcx.item_children(krate);
                let mut path_it = path.iter().skip(1).peekable();

                while let Some(segment) = path_it.next() {
                    for item in mem::replace(&mut items, Default::default()).iter() {
                        if item.ident.name.as_str() == *segment {
                            if path_it.peek().is_none() {
                                return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id()));
                            }

                            items = this.tcx.item_children(item.res.def_id());
                            break;
                        }
                    }
                }
                None
            })
            .ok_or_else(|| {
                let path = path.iter().map(|&s| s.to_owned()).collect();
                err_unsup!(PathNotFound(path)).into()
            })
    }

    /// Write a 0 of the appropriate size to `dest`.
    fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
        self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
    }

    /// Test if this immediate equals 0.
    fn is_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, bool> {
        let this = self.eval_context_ref();
        let null = Scalar::from_int(0, this.memory().pointer_size());
        this.ptr_eq(val, null)
    }

    /// Turn a Scalar into an Option<NonNullScalar>
    fn test_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, Option<Scalar<Tag>>> {
        let this = self.eval_context_ref();
        Ok(if this.is_null(val)? {
            None
        } else {
            Some(val)
        })
    }

    /// Get the `Place` for a local
    fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> {
        let this = self.eval_context_mut();
        let place = mir::Place { base: mir::PlaceBase::Local(local), projection: None };
        this.eval_place(&place)
    }

    /// Generate some random bytes, and write them to `dest`.
    fn gen_random(
        &mut self,
        ptr: Scalar<Tag>,
        len: usize,
    ) -> InterpResult<'tcx>  {
        let this = self.eval_context_mut();

        let ptr = match this.memory().check_ptr_access(ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap())? {
            Some(ptr) => ptr,
            None => return Ok(()), // zero-sized access
        };

        let rng = this.memory_mut().extra.rng.get_mut();
        let mut data = vec![0; len];
        rng.fill_bytes(&mut data);

        let tcx = &{this.tcx.tcx};
        this.memory_mut().get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data)
    }

    /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter
    /// will be true if this is frozen, false if this is in an `UnsafeCell`.
    fn visit_freeze_sensitive(
        &self,
        place: MPlaceTy<'tcx, Tag>,
        size: Size,
        mut action: impl FnMut(Pointer<Tag>, Size, bool) -> InterpResult<'tcx>,
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_ref();
        trace!("visit_frozen(place={:?}, size={:?})", *place, size);
        debug_assert_eq!(size,
            this.size_and_align_of_mplace(place)?
            .map(|(size, _)| size)
            .unwrap_or_else(|| place.layout.size)
        );
        // Store how far we proceeded into the place so far. Everything to the left of
        // this offset has already been handled, in the sense that the frozen parts
        // have had `action` called on them.
        let mut end_ptr = place.ptr.assert_ptr();
        // Called when we detected an `UnsafeCell` at the given offset and size.
        // Calls `action` and advances `end_ptr`.
        let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar<Tag>, unsafe_cell_size: Size| {
            let unsafe_cell_ptr = unsafe_cell_ptr.assert_ptr();
            debug_assert_eq!(unsafe_cell_ptr.alloc_id, end_ptr.alloc_id);
            debug_assert_eq!(unsafe_cell_ptr.tag, end_ptr.tag);
            // We assume that we are given the fields in increasing offset order,
            // and nothing else changes.
            let unsafe_cell_offset = unsafe_cell_ptr.offset;
            let end_offset = end_ptr.offset;
            assert!(unsafe_cell_offset >= end_offset);
            let frozen_size = unsafe_cell_offset - end_offset;
            // Everything between the end_ptr and this `UnsafeCell` is frozen.
            if frozen_size != Size::ZERO {
                action(end_ptr, frozen_size, /*frozen*/true)?;
            }
            // This `UnsafeCell` is NOT frozen.
            if unsafe_cell_size != Size::ZERO {
                action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/false)?;
            }
            // Update end end_ptr.
            end_ptr = unsafe_cell_ptr.wrapping_offset(unsafe_cell_size, this);
            // Done
            Ok(())
        };
        // Run a visitor
        {
            let mut visitor = UnsafeCellVisitor {
                ecx: this,
                unsafe_cell_action: |place| {
                    trace!("unsafe_cell_action on {:?}", place.ptr);
                    // We need a size to go on.
                    let unsafe_cell_size = this.size_and_align_of_mplace(place)?
                        .map(|(size, _)| size)
                        // for extern types, just cover what we can
                        .unwrap_or_else(|| place.layout.size);
                    // Now handle this `UnsafeCell`, unless it is empty.
                    if unsafe_cell_size != Size::ZERO {
                        unsafe_cell_action(place.ptr, unsafe_cell_size)
                    } else {
                        Ok(())
                    }
                },
            };
            visitor.visit_value(place)?;
        }
        // The part between the end_ptr and the end of the place is also frozen.
        // So pretend there is a 0-sized `UnsafeCell` at the end.
        unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?;
        // Done!
        return Ok(());

        /// Visiting the memory covered by a `MemPlace`, being aware of
        /// whether we are inside an `UnsafeCell` or not.
        struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
            where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            ecx: &'ecx MiriEvalContext<'mir, 'tcx>,
            unsafe_cell_action: F,
        }

        impl<'ecx, 'mir, 'tcx, F>
            ValueVisitor<'mir, 'tcx, Evaluator<'tcx>>
        for
            UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
        where
            F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            type V = MPlaceTy<'tcx, Tag>;

            #[inline(always)]
            fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> {
                &self.ecx
            }

            // Hook to detect `UnsafeCell`.
            fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty);
                let is_unsafe_cell = match v.layout.ty.sty {
                    ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(),
                    _ => false,
                };
                if is_unsafe_cell {
                    // We do not have to recurse further, this is an `UnsafeCell`.
                    (self.unsafe_cell_action)(v)
                } else if self.ecx.type_is_freeze(v.layout.ty) {
                    // This is `Freeze`, there cannot be an `UnsafeCell`
                    Ok(())
                } else {
                    // Proceed further
                    self.walk_value(v)
                }
            }

            // Make sure we visit aggregrates in increasing offset order.
            fn visit_aggregate(
                &mut self,
                place: MPlaceTy<'tcx, Tag>,
                fields: impl Iterator<Item=InterpResult<'tcx, MPlaceTy<'tcx, Tag>>>,
            ) -> InterpResult<'tcx> {
                match place.layout.fields {
                    layout::FieldPlacement::Array { .. } => {
                        // For the array layout, we know the iterator will yield sorted elements so
                        // we can avoid the allocation.
                        self.walk_aggregate(place, fields)
                    }
                    layout::FieldPlacement::Arbitrary { .. } => {
                        // Gather the subplaces and sort them before visiting.
                        let mut places = fields.collect::<InterpResult<'tcx, Vec<MPlaceTy<'tcx, Tag>>>>()?;
                        places.sort_by_key(|place| place.ptr.assert_ptr().offset);
                        self.walk_aggregate(place, places.into_iter().map(Ok))
                    }
                    layout::FieldPlacement::Union { .. } => {
                        // Uh, what?
                        bug!("a union is not an aggregate we should ever visit")
                    }
                }
            }

            // We have to do *something* for unions.
            fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                // With unions, we fall back to whatever the type says, to hopefully be consistent
                // with LLVM IR.
                // FIXME: are we consistent, and is this really the behavior we want?
                let frozen = self.ecx.type_is_freeze(v.layout.ty);
                if frozen {
                    Ok(())
                } else {
                    (self.unsafe_cell_action)(v)
                }
            }

            // We should never get to a primitive, but always short-circuit somewhere above.
            fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                bug!("we should always short-circuit before coming to a primitive")
            }
        }
    }
}
<commit_msg>Do nothing when we try to generate random data of length 0<commit_after>use std::mem;

use rustc::ty::{self, layout::{self, Size, Align}};
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc::mir;

use rand::RngCore;

use crate::*;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}

pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    /// Gets an instance for a path.
    fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> {
        let this = self.eval_context_ref();
        this.tcx
            .crates()
            .iter()
            .find(|&&krate| this.tcx.original_crate_name(krate).as_str() == path[0])
            .and_then(|krate| {
                let krate = DefId {
                    krate: *krate,
                    index: CRATE_DEF_INDEX,
                };
                let mut items = this.tcx.item_children(krate);
                let mut path_it = path.iter().skip(1).peekable();

                while let Some(segment) = path_it.next() {
                    for item in mem::replace(&mut items, Default::default()).iter() {
                        if item.ident.name.as_str() == *segment {
                            if path_it.peek().is_none() {
                                return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id()));
                            }

                            items = this.tcx.item_children(item.res.def_id());
                            break;
                        }
                    }
                }
                None
            })
            .ok_or_else(|| {
                let path = path.iter().map(|&s| s.to_owned()).collect();
                err_unsup!(PathNotFound(path)).into()
            })
    }

    /// Write a 0 of the appropriate size to `dest`.
    fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
        self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
    }

    /// Test if this immediate equals 0.
    fn is_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, bool> {
        let this = self.eval_context_ref();
        let null = Scalar::from_int(0, this.memory().pointer_size());
        this.ptr_eq(val, null)
    }

    /// Turn a Scalar into an Option<NonNullScalar>
    fn test_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, Option<Scalar<Tag>>> {
        let this = self.eval_context_ref();
        Ok(if this.is_null(val)? {
            None
        } else {
            Some(val)
        })
    }

    /// Get the `Place` for a local
    fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> {
        let this = self.eval_context_mut();
        let place = mir::Place { base: mir::PlaceBase::Local(local), projection: None };
        this.eval_place(&place)
    }

    /// Generate some random bytes, and write them to `dest`.
    fn gen_random(
        &mut self,
        ptr: Scalar<Tag>,
        len: usize,
    ) -> InterpResult<'tcx>  {
        // Some programs pass in a null pointer and a length of 0
        // to their platform's random-generation function (e.g. getrandom())
        // on Linux. For compatibility with these programs, we don't perform
        // any additional checks - it's okay if the pointer is invalid,
        // since we wouldn't actually be writing to it.
        if len == 0 {
            return Ok(())
        }
        let this = self.eval_context_mut();

        let ptr = match this.memory().check_ptr_access(ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap())? {
            Some(ptr) => ptr,
            None => return Ok(()), // zero-sized access
        };

        let rng = this.memory_mut().extra.rng.get_mut();
        let mut data = vec![0; len];
        rng.fill_bytes(&mut data);

        let tcx = &{this.tcx.tcx};
        this.memory_mut().get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data)
    }

    /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter
    /// will be true if this is frozen, false if this is in an `UnsafeCell`.
    fn visit_freeze_sensitive(
        &self,
        place: MPlaceTy<'tcx, Tag>,
        size: Size,
        mut action: impl FnMut(Pointer<Tag>, Size, bool) -> InterpResult<'tcx>,
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_ref();
        trace!("visit_frozen(place={:?}, size={:?})", *place, size);
        debug_assert_eq!(size,
            this.size_and_align_of_mplace(place)?
            .map(|(size, _)| size)
            .unwrap_or_else(|| place.layout.size)
        );
        // Store how far we proceeded into the place so far. Everything to the left of
        // this offset has already been handled, in the sense that the frozen parts
        // have had `action` called on them.
        let mut end_ptr = place.ptr.assert_ptr();
        // Called when we detected an `UnsafeCell` at the given offset and size.
        // Calls `action` and advances `end_ptr`.
        let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar<Tag>, unsafe_cell_size: Size| {
            let unsafe_cell_ptr = unsafe_cell_ptr.assert_ptr();
            debug_assert_eq!(unsafe_cell_ptr.alloc_id, end_ptr.alloc_id);
            debug_assert_eq!(unsafe_cell_ptr.tag, end_ptr.tag);
            // We assume that we are given the fields in increasing offset order,
            // and nothing else changes.
            let unsafe_cell_offset = unsafe_cell_ptr.offset;
            let end_offset = end_ptr.offset;
            assert!(unsafe_cell_offset >= end_offset);
            let frozen_size = unsafe_cell_offset - end_offset;
            // Everything between the end_ptr and this `UnsafeCell` is frozen.
            if frozen_size != Size::ZERO {
                action(end_ptr, frozen_size, /*frozen*/true)?;
            }
            // This `UnsafeCell` is NOT frozen.
            if unsafe_cell_size != Size::ZERO {
                action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/false)?;
            }
            // Update end end_ptr.
            end_ptr = unsafe_cell_ptr.wrapping_offset(unsafe_cell_size, this);
            // Done
            Ok(())
        };
        // Run a visitor
        {
            let mut visitor = UnsafeCellVisitor {
                ecx: this,
                unsafe_cell_action: |place| {
                    trace!("unsafe_cell_action on {:?}", place.ptr);
                    // We need a size to go on.
                    let unsafe_cell_size = this.size_and_align_of_mplace(place)?
                        .map(|(size, _)| size)
                        // for extern types, just cover what we can
                        .unwrap_or_else(|| place.layout.size);
                    // Now handle this `UnsafeCell`, unless it is empty.
                    if unsafe_cell_size != Size::ZERO {
                        unsafe_cell_action(place.ptr, unsafe_cell_size)
                    } else {
                        Ok(())
                    }
                },
            };
            visitor.visit_value(place)?;
        }
        // The part between the end_ptr and the end of the place is also frozen.
        // So pretend there is a 0-sized `UnsafeCell` at the end.
        unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?;
        // Done!
        return Ok(());

        /// Visiting the memory covered by a `MemPlace`, being aware of
        /// whether we are inside an `UnsafeCell` or not.
        struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
            where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            ecx: &'ecx MiriEvalContext<'mir, 'tcx>,
            unsafe_cell_action: F,
        }

        impl<'ecx, 'mir, 'tcx, F>
            ValueVisitor<'mir, 'tcx, Evaluator<'tcx>>
        for
            UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
        where
            F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            type V = MPlaceTy<'tcx, Tag>;

            #[inline(always)]
            fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> {
                &self.ecx
            }

            // Hook to detect `UnsafeCell`.
            fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty);
                let is_unsafe_cell = match v.layout.ty.sty {
                    ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(),
                    _ => false,
                };
                if is_unsafe_cell {
                    // We do not have to recurse further, this is an `UnsafeCell`.
                    (self.unsafe_cell_action)(v)
                } else if self.ecx.type_is_freeze(v.layout.ty) {
                    // This is `Freeze`, there cannot be an `UnsafeCell`
                    Ok(())
                } else {
                    // Proceed further
                    self.walk_value(v)
                }
            }

            // Make sure we visit aggregrates in increasing offset order.
            fn visit_aggregate(
                &mut self,
                place: MPlaceTy<'tcx, Tag>,
                fields: impl Iterator<Item=InterpResult<'tcx, MPlaceTy<'tcx, Tag>>>,
            ) -> InterpResult<'tcx> {
                match place.layout.fields {
                    layout::FieldPlacement::Array { .. } => {
                        // For the array layout, we know the iterator will yield sorted elements so
                        // we can avoid the allocation.
                        self.walk_aggregate(place, fields)
                    }
                    layout::FieldPlacement::Arbitrary { .. } => {
                        // Gather the subplaces and sort them before visiting.
                        let mut places = fields.collect::<InterpResult<'tcx, Vec<MPlaceTy<'tcx, Tag>>>>()?;
                        places.sort_by_key(|place| place.ptr.assert_ptr().offset);
                        self.walk_aggregate(place, places.into_iter().map(Ok))
                    }
                    layout::FieldPlacement::Union { .. } => {
                        // Uh, what?
                        bug!("a union is not an aggregate we should ever visit")
                    }
                }
            }

            // We have to do *something* for unions.
            fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                // With unions, we fall back to whatever the type says, to hopefully be consistent
                // with LLVM IR.
                // FIXME: are we consistent, and is this really the behavior we want?
                let frozen = self.ecx.type_is_freeze(v.layout.ty);
                if frozen {
                    Ok(())
                } else {
                    (self.unsafe_cell_action)(v)
                }
            }

            // We should never get to a primitive, but always short-circuit somewhere above.
            fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                bug!("we should always short-circuit before coming to a primitive")
            }
        }
    }
}
<|endoftext|>


<commit_before>use regex::{Regex, Captures};

use hyper::method::Method;
use hyper::method::Method::{Get, Post, Delete};

use command::{WebDriverMessage};
use error::{WebDriverResult, WebDriverError, ErrorStatus};

static ROUTES: [(Method, &'static str, Route); 47] = [
    (Post, "/session", Route::NewSession),
    (Delete, "/session/{sessionId}", Route::DeleteSession),
    (Post, "/session/{sessionId}/url", Route::Get),
    (Get, "/session/{sessionId}/url", Route::GetCurrentUrl),
    (Post, "/session/{sessionId}/back", Route::GoBack),
    (Post, "/session/{sessionId}/forward", Route::GoForward),
    (Post, "/session/{sessionId}/refresh", Route::Refresh),
    (Get, "/session/{sessionId}/title", Route::GetTitle),
    (Get, "/session/{sessionId}/window_handle", Route::GetWindowHandle),
    (Get, "/session/{sessionId}/window_handles", Route::GetWindowHandles),
    (Delete, "/session/{sessionId}/window_handle", Route::Close),
    (Post, "/session/{sessionId}/window/size", Route::SetWindowSize),
    (Get, "/session/{sessionId}/window/size", Route::GetWindowSize),
    (Post, "/session/{sessionId}/window/maximize", Route::MaximizeWindow),
    (Post, "/session/{sessionId}/window", Route::SwitchToWindow),
    (Post, "/session/{sessionId}/frame", Route::SwitchToFrame),
    (Post, "/session/{sessionId}/frame/parent", Route::SwitchToParentFrame),
    (Post, "/session/{sessionId}/element", Route::FindElement),
    (Post, "/session/{sessionId}/elements", Route::FindElements),
    (Post, "/session/{sessionId}/element/{elementId}/element", Route::FindElementElement),
    (Post, "/session/{sessionId}/element/{elementId}/elements", Route::FindElementElements),
    (Get, "/session/{sessionId}/element/active", Route::GetActiveElement),
    (Get, "/session/{sessionId}/element/{elementId}/displayed", Route::IsDisplayed),
    (Get, "/session/{sessionId}/element/{elementId}/selected", Route::IsSelected),
    (Get, "/session/{sessionId}/element/{elementId}/attribute/{name}", Route::GetElementAttribute),
    (Get, "/session/{sessionId}/element/{elementId}/css/{propertyName}", Route::GetCSSValue),
    (Get, "/session/{sessionId}/element/{elementId}/text", Route::GetElementText),
    (Get, "/session/{sessionId}/element/{elementId}/name", Route::GetElementTagName),
    (Get, "/session/{sessionId}/element/{elementId}/rect", Route::GetElementRect),
    (Get, "/session/{sessionId}/element/{elementId}/enabled", Route::IsEnabled),
    (Post, "/session/{sessionId}/execute", Route::ExecuteScript),
    (Post, "/session/{sessionId}/execute_async", Route::ExecuteAsyncScript),
    (Get, "/session/{sessionId}/cookie", Route::GetCookies),
    (Get, "/session/{sessionId}/cookie/{name}", Route::GetCookie),
    (Post, "/session/{sessionId}/cookie", Route::AddCookie),
    (Delete, "/session/{sessionId}/cookie", Route::DeleteCookies),
    (Delete, "/session/{sessionId}/cookie/{name}", Route::DeleteCookie),
    (Post, "/session/{sessionId}/timeouts", Route::SetTimeouts),
    //(Post, "/session/{sessionId}/actions", Route::Actions),
    (Post, "/session/{sessionId}/element/{elementId}/click", Route::ElementClick),
    (Post, "/session/{sessionId}/element/{elementId}/tap", Route::ElementTap),
    (Post, "/session/{sessionId}/element/{elementId}/clear", Route::ElementClear),
    (Post, "/session/{sessionId}/element/{elementId}/value", Route::ElementSendKeys),
    (Post, "/session/{sessionId}/dismiss_alert", Route::DismissAlert),
    (Post, "/session/{sessionId}/accept_alert", Route::AcceptAlert),
    (Get, "/session/{sessionId}/alert_text", Route::GetAlertText),
    (Post, "/session/{sessionId}/alert_text", Route::SendAlertText),
    (Get, "/session/{sessionId}/screenshot", Route::TakeScreenshot)
];

#[derive(Clone, Copy)]
pub enum Route {
    NewSession,
    DeleteSession,
    Get,
    GetCurrentUrl,
    GoBack,
    GoForward,
    Refresh,
    GetTitle,
    GetWindowHandle,
    GetWindowHandles,
    Close,
    SetWindowSize,
    GetWindowSize,
    MaximizeWindow,
    SwitchToWindow,
    SwitchToFrame,
    SwitchToParentFrame,
    FindElement,
    FindElements,
    FindElementElement,
    FindElementElements,
    GetActiveElement,
    IsDisplayed,
    IsSelected,
    GetElementAttribute,
    GetCSSValue,
    GetElementText,
    GetElementTagName,
    GetElementRect,
    IsEnabled,
    ExecuteScript,
    ExecuteAsyncScript,
    GetCookies,
    GetCookie,
    AddCookie,
    DeleteCookies,
    DeleteCookie,
    SetTimeouts,
    //Actions XXX - once I understand the spec, perhaps
    ElementClick,
    ElementTap,
    ElementClear,
    ElementSendKeys,
    DismissAlert,
    AcceptAlert,
    GetAlertText,
    SendAlertText,
    TakeScreenshot
}

#[derive(Clone)]
struct RequestMatcher {
    method: Method,
    path_regexp: Regex,
    match_type: Route
}

impl RequestMatcher {
    pub fn new(method: Method, path: &str, match_type: Route) -> RequestMatcher {
        let path_regexp = RequestMatcher::compile_path(path);
        RequestMatcher {
            method: method,
            path_regexp: path_regexp,
            match_type: match_type
        }
    }

    pub fn get_match<'t>(&'t self, method: Method, path: &'t str) -> (bool, Option<Captures>) {
        let captures = self.path_regexp.captures(path);
        (method == self.method, captures)
    }

    fn compile_path(path: &str) -> Regex {
        let mut rv = String::new();
        rv.push_str("^");
        let components = path.split('/');
        for component in components {
            if component.starts_with("{") {
                if !component.ends_with("}") {
                    panic!("Invalid url pattern")
                }
                rv.push_str(&format!("(?P<{}>[^/]+)/", &component[1..component.len()-1])[..]);
            } else {
                rv.push_str(&format!("{}/", component)[..]);
            }
        }
        //Remove the trailing /
        rv.pop();
        rv.push_str("$");
        //This will fail at runtime if the regexp is invalid
        Regex::new(&rv[..]).unwrap()
    }
}

pub struct WebDriverHttpApi {
    routes: Vec<(Method, RequestMatcher)>
}

impl WebDriverHttpApi {
    pub fn new() -> WebDriverHttpApi {
        let mut rv = WebDriverHttpApi {
            routes: vec![]
        };
        debug!("Creating routes");
        for &(ref method, ref url, ref match_type) in ROUTES.iter() {
            rv.add(method.clone(), *url, *match_type);
        };
        rv
    }

    fn add(&mut self, method: Method, path: &str, match_type: Route) {
        let http_matcher = RequestMatcher::new(method.clone(), path, match_type);
        self.routes.push((method, http_matcher));
    }

    pub fn decode_request(&self, method: Method, path: &str, body: &str) -> WebDriverResult<WebDriverMessage> {
        let mut error = ErrorStatus::UnknownPath;
        for &(ref match_method, ref matcher) in self.routes.iter() {
            if method == *match_method {
                let (method_match, captures) = matcher.get_match(method.clone(), path);
                if captures.is_some() {
                    if method_match {
                        return WebDriverMessage::from_http(matcher.match_type,
                                                           &captures.unwrap(),
                                                           body,
                                                           method == Post)
                    } else {
                        error = ErrorStatus::UnknownMethod;
                    }
                }
            }
        }
        Err(WebDriverError::new(error,
                                &format!("{} {} did not match a known command", method, path)[..]))
    }
}
<commit_msg>Update the HTTP Endpoints to match the current specification<commit_after>use regex::{Regex, Captures};

use hyper::method::Method;
use hyper::method::Method::{Get, Post, Delete};

use command::{WebDriverMessage};
use error::{WebDriverResult, WebDriverError, ErrorStatus};

static ROUTES: [(Method, &'static str, Route); 56] = [
    (Post, "/session", Route::NewSession),
    (Delete, "/session/{sessionId}", Route::DeleteSession),
    (Post, "/session/{sessionId}/url", Route::Get),
    (Get, "/session/{sessionId}/url", Route::GetCurrentUrl),
    (Post, "/session/{sessionId}/back", Route::GoBack),
    (Post, "/session/{sessionId}/forward", Route::GoForward),
    (Post, "/session/{sessionId}/refresh", Route::Refresh),
    (Get, "/session/{sessionId}/title", Route::GetTitle),
    (Get, "/session/{sessionId}/window", Route::GetWindowHandle),
    (Get, "/session/{sessionId}/window/handles", Route::GetWindowHandles),
    (Delete, "/session/{sessionId}/window", Route::Close),
    (Post, "/session/{sessionId}/window/size", Route::SetWindowSize),
    (Get, "/session/{sessionId}/window/size", Route::GetWindowSize),
    (Post, "/session/{sessionId}/window/maximize", Route::MaximizeWindow),
    (Post, "/session/{sessionId}/window", Route::SwitchToWindow),
    (Post, "/session/{sessionId}/frame", Route::SwitchToFrame),
    (Post, "/session/{sessionId}/frame/parent", Route::SwitchToParentFrame),
    (Post, "/session/{sessionId}/element", Route::FindElement),
    (Post, "/session/{sessionId}/elements", Route::FindElements),
    (Post, "/session/{sessionId}/element/{elementId}/element", Route::FindElementElement),
    (Post, "/session/{sessionId}/element/{elementId}/elements", Route::FindElementElements),
    (Get, "/session/{sessionId}/element/active", Route::GetActiveElement),
    (Get, "/session/{sessionId}/element/{elementId}/displayed", Route::IsDisplayed),
    (Get, "/session/{sessionId}/element/{elementId}/selected", Route::IsSelected),
    (Get, "/session/{sessionId}/element/{elementId}/attribute/{name}", Route::GetElementAttribute),
    (Get, "/session/{sessionId}/element/{elementId}/css/{propertyName}", Route::GetCSSValue),
    (Get, "/session/{sessionId}/element/{elementId}/text", Route::GetElementText),
    (Get, "/session/{sessionId}/element/{elementId}/name", Route::GetElementTagName),
    (Get, "/session/{sessionId}/element/{elementId}/rect", Route::GetElementRect),
    (Get, "/session/{sessionId}/element/{elementId}/enabled", Route::IsEnabled),
    (Post, "/session/{sessionId}/execute/sync", Route::ExecuteScript),
    (Post, "/session/{sessionId}/execute/async", Route::ExecuteAsyncScript),
    (Get, "/session/{sessionId}/cookie", Route::GetCookies),
    (Get, "/session/{sessionId}/cookie/{name}", Route::GetCookie),
    (Post, "/session/{sessionId}/cookie", Route::AddCookie),
    (Delete, "/session/{sessionId}/cookie", Route::DeleteCookies),
    (Delete, "/session/{sessionId}/cookie/{name}", Route::DeleteCookie),
    (Post, "/session/{sessionId}/timeouts", Route::SetTimeouts),
    //(Post, "/session/{sessionId}/actions", Route::Actions),
    (Post, "/session/{sessionId}/element/{elementId}/click", Route::ElementClick),
    (Post, "/session/{sessionId}/element/{elementId}/tap", Route::ElementTap),
    (Post, "/session/{sessionId}/element/{elementId}/clear", Route::ElementClear),
    (Post, "/session/{sessionId}/element/{elementId}/value", Route::ElementSendKeys),
    (Post, "/session/{sessionId}/alert/dismiss", Route::DismissAlert),
    (Post, "/session/{sessionId}/alert/accept", Route::AcceptAlert),
    (Get, "/session/{sessionId}/alert/text", Route::GetAlertText),
    (Post, "/session/{sessionId}/alert/text", Route::SendAlertText),
    (Get, "/session/{sessionId}/screenshot", Route::TakeScreenshot),
    // TODO Remove this when > v0.5 is released. There for compatibility reasons with existing
    //      Webdriver implementations.
    (Get, "/session/{sessionId}/alert_text", Route::GetAlertText),
    (Post, "/session/{sessionId}/alert_text", Route::SendAlertText),
    (Post, "/session/{sessionId}/accept_alert", Route::AcceptAlert),
    (Post, "/session/{sessionId}/dismiss_alert", Route::DismissAlert),
    (Get, "/session/{sessionId}/window_handle", Route::GetWindowHandle),
    (Get, "/session/{sessionId}/window_handles", Route::GetWindowHandles),
    (Delete, "/session/{sessionId}/window_handle", Route::Close),
    (Post, "/session/{sessionId}/execute_async", Route::ExecuteAsyncScript),
    (Post, "/session/{sessionId}/execute", Route::ExecuteScript),
];

#[derive(Clone, Copy)]
pub enum Route {
    NewSession,
    DeleteSession,
    Get,
    GetCurrentUrl,
    GoBack,
    GoForward,
    Refresh,
    GetTitle,
    GetWindowHandle,
    GetWindowHandles,
    Close,
    SetWindowSize,
    GetWindowSize,
    MaximizeWindow,
    SwitchToWindow,
    SwitchToFrame,
    SwitchToParentFrame,
    FindElement,
    FindElements,
    FindElementElement,
    FindElementElements,
    GetActiveElement,
    IsDisplayed,
    IsSelected,
    GetElementAttribute,
    GetCSSValue,
    GetElementText,
    GetElementTagName,
    GetElementRect,
    IsEnabled,
    ExecuteScript,
    ExecuteAsyncScript,
    GetCookies,
    GetCookie,
    AddCookie,
    DeleteCookies,
    DeleteCookie,
    SetTimeouts,
    //Actions XXX - once I understand the spec, perhaps
    ElementClick,
    ElementTap,
    ElementClear,
    ElementSendKeys,
    DismissAlert,
    AcceptAlert,
    GetAlertText,
    SendAlertText,
    TakeScreenshot
}

#[derive(Clone)]
struct RequestMatcher {
    method: Method,
    path_regexp: Regex,
    match_type: Route
}

impl RequestMatcher {
    pub fn new(method: Method, path: &str, match_type: Route) -> RequestMatcher {
        let path_regexp = RequestMatcher::compile_path(path);
        RequestMatcher {
            method: method,
            path_regexp: path_regexp,
            match_type: match_type
        }
    }

    pub fn get_match<'t>(&'t self, method: Method, path: &'t str) -> (bool, Option<Captures>) {
        let captures = self.path_regexp.captures(path);
        (method == self.method, captures)
    }

    fn compile_path(path: &str) -> Regex {
        let mut rv = String::new();
        rv.push_str("^");
        let components = path.split('/');
        for component in components {
            if component.starts_with("{") {
                if !component.ends_with("}") {
                    panic!("Invalid url pattern")
                }
                rv.push_str(&format!("(?P<{}>[^/]+)/", &component[1..component.len()-1])[..]);
            } else {
                rv.push_str(&format!("{}/", component)[..]);
            }
        }
        //Remove the trailing /
        rv.pop();
        rv.push_str("$");
        //This will fail at runtime if the regexp is invalid
        Regex::new(&rv[..]).unwrap()
    }
}

pub struct WebDriverHttpApi {
    routes: Vec<(Method, RequestMatcher)>
}

impl WebDriverHttpApi {
    pub fn new() -> WebDriverHttpApi {
        let mut rv = WebDriverHttpApi {
            routes: vec![]
        };
        debug!("Creating routes");
        for &(ref method, ref url, ref match_type) in ROUTES.iter() {
            rv.add(method.clone(), *url, *match_type);
        };
        rv
    }

    fn add(&mut self, method: Method, path: &str, match_type: Route) {
        let http_matcher = RequestMatcher::new(method.clone(), path, match_type);
        self.routes.push((method, http_matcher));
    }

    pub fn decode_request(&self, method: Method, path: &str, body: &str) -> WebDriverResult<WebDriverMessage> {
        let mut error = ErrorStatus::UnknownPath;
        for &(ref match_method, ref matcher) in self.routes.iter() {
            if method == *match_method {
                let (method_match, captures) = matcher.get_match(method.clone(), path);
                if captures.is_some() {
                    if method_match {
                        return WebDriverMessage::from_http(matcher.match_type,
                                                           &captures.unwrap(),
                                                           body,
                                                           method == Post)
                    } else {
                        error = ErrorStatus::UnknownMethod;
                    }
                }
            }
        }
        Err(WebDriverError::new(error,
                                &format!("{} {} did not match a known command", method, path)[..]))
    }
}
<|endoftext|>


<commit_before>#![allow(unsafe_code)]

#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::io;
#[cfg(any(target_os = "linux"))]
use {std::fs::File, std::io::Read};

/// See the Kernel's documentation for more information about this subsystem,
/// found at:  [Documentation/cgroup-v1/memory.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt)
///
/// If there's no memory limit specified on the container this may return
/// 0x7FFFFFFFFFFFF000 (2^63-1 rounded down to 4k which is a common page size).
/// So we know we are not running in a memory restricted environment.
#[cfg(target_os = "linux")]
fn get_cgroup_memory_limit() -> io::Result<u64> {
    File::open("/sys/fs/cgroup/memory/memory.limit_in_bytes")
        .and_then(read_u64_from)
}

#[cfg(target_os = "linux")]
fn read_u64_from(mut file: File) -> io::Result<u64> {
    let mut s = String::new();
    file.read_to_string(&mut s).and_then(|_| {
        s.trim()
            .parse()
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
    })
}

/// Returns the maximum size of total available memory of the process, in bytes.
/// If this limit is exceeded, the malloc() and mmap() functions shall fail with
/// errno set to [ENOMEM].
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn get_rlimit_as() -> io::Result<libc::rlimit> {
    let mut limit = std::mem::MaybeUninit::<libc::rlimit>::uninit();

    let ret = unsafe { libc::getrlimit(libc::RLIMIT_AS, limit.as_mut_ptr()) };

    if ret == 0 {
        Ok(unsafe { limit.assume_init() })
    } else {
        Err(io::Error::last_os_error())
    }
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn get_available_memory() -> io::Result<u64> {
    use std::convert::TryFrom;

    let pages = unsafe { libc::sysconf(libc::_SC_PHYS_PAGES) };
    if pages == -1 {
        return Err(io::Error::last_os_error());
    }

    let page_size = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) };
    if page_size == -1 {
        return Err(io::Error::last_os_error());
    }

    Ok(u64::try_from(pages).unwrap() * u64::try_from(page_size).unwrap())
}

pub fn get_memory_limit() -> u64 {
    // Maximum addressable memory space limit in u64
    static MAX_USIZE: u64 = usize::max_value() as u64;

    let mut max: u64 = 0;

    #[cfg(target_os = "linux")]
    {
        if let Ok(mem) = get_cgroup_memory_limit() {
            max = mem;
        }

        // If there's no memory limit specified on the container this
        // actually returns 0x7FFFFFFFFFFFF000 (2^63-1 rounded down to
        // 4k which is a common page size). So we know we are not
        // running in a memory restricted environment.
        // src: https://github.com/dotnet/coreclr/blob/master/src/pal/src/misc/cgroup.cpp#L385-L428
        if max > 0x7FFF_FFFF_0000_0000 {
            return 0;
        }
    }

    #[cfg(any(target_os = "linux", target_os = "macos"))]
    {
        if let Ok(rlim) = get_rlimit_as() {
            let rlim_cur = Into::<u64>::into(rlim.rlim_cur);
            if rlim_cur < max || max == 0 {
                max = rlim_cur;
            }
        }

        if let Ok(available) = get_available_memory() {
            if available < max || max == 0 {
                max = available;
            }
        }
    }

    if max > MAX_USIZE {
        // It is observed in practice when the memory is unrestricted, Linux
        // control group returns a physical limit that is bigger than
        // the address space
        max = MAX_USIZE;
    }

    max
}
<commit_msg>Add an empirical correction factor to memory limit<commit_after>#![allow(unsafe_code)]

#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::io;
#[cfg(any(target_os = "linux"))]
use {std::fs::File, std::io::Read};

/// See the Kernel's documentation for more information about this subsystem,
/// found at:  [Documentation/cgroup-v1/memory.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt)
///
/// If there's no memory limit specified on the container this may return
/// 0x7FFFFFFFFFFFF000 (2^63-1 rounded down to 4k which is a common page size).
/// So we know we are not running in a memory restricted environment.
#[cfg(target_os = "linux")]
fn get_cgroup_memory_limit() -> io::Result<u64> {
    File::open("/sys/fs/cgroup/memory/memory.limit_in_bytes")
        .and_then(read_u64_from)
}

#[cfg(target_os = "linux")]
fn read_u64_from(mut file: File) -> io::Result<u64> {
    let mut s = String::new();
    file.read_to_string(&mut s).and_then(|_| {
        s.trim()
            .parse()
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
    })
}

/// Returns the maximum size of total available memory of the process, in bytes.
/// If this limit is exceeded, the malloc() and mmap() functions shall fail with
/// errno set to [ENOMEM].
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn get_rlimit_as() -> io::Result<libc::rlimit> {
    let mut limit = std::mem::MaybeUninit::<libc::rlimit>::uninit();

    let ret = unsafe { libc::getrlimit(libc::RLIMIT_AS, limit.as_mut_ptr()) };

    if ret == 0 {
        Ok(unsafe { limit.assume_init() })
    } else {
        Err(io::Error::last_os_error())
    }
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn get_available_memory() -> io::Result<u64> {
    use std::convert::TryFrom;

    let pages = unsafe { libc::sysconf(libc::_SC_PHYS_PAGES) };
    if pages == -1 {
        return Err(io::Error::last_os_error());
    }

    let page_size = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) };
    if page_size == -1 {
        return Err(io::Error::last_os_error());
    }

    Ok(u64::try_from(pages).unwrap() * u64::try_from(page_size).unwrap())
}

pub fn get_memory_limit() -> u64 {
    // Maximum addressable memory space limit in u64
    static MAX_USIZE: u64 = usize::max_value() as u64;

    let mut max: u64 = 0;

    #[cfg(target_os = "linux")]
    {
        if let Ok(mem) = get_cgroup_memory_limit() {
            max = mem;
        }

        // If there's no memory limit specified on the container this
        // actually returns 0x7FFFFFFFFFFFF000 (2^63-1 rounded down to
        // 4k which is a common page size). So we know we are not
        // running in a memory restricted environment.
        // src: https://github.com/dotnet/coreclr/blob/master/src/pal/src/misc/cgroup.cpp#L385-L428
        if max > 0x7FFF_FFFF_0000_0000 {
            return 0;
        }
    }

    #[cfg(any(target_os = "linux", target_os = "macos"))]
    {
        if let Ok(rlim) = get_rlimit_as() {
            let rlim_cur = Into::<u64>::into(rlim.rlim_cur);
            if rlim_cur < max || max == 0 {
                max = rlim_cur;
            }
        }

        if let Ok(available) = get_available_memory() {
            if available < max || max == 0 {
                max = available;
            }
        }
    }

    if max > MAX_USIZE {
        // It is observed in practice when the memory is unrestricted, Linux
        // control group returns a physical limit that is bigger than
        // the address space
        max = MAX_USIZE;
    }

    #[cfg(miri)]
    {
        // Miri has a significant memory consumption overhead. During a small
        // test run, a memory amplification of ~35x was observed. Certain
        // memory overheads may increase asymptotically with longer test runs,
        // such as the interpreter's dead_alloc_map. Memory overhead is
        // dominated by stacked borrows tags; the asymptotic behavior of this
        // overhead needs further investigation.
        max /= 40;
    }

    max
}
<|endoftext|>


<commit_before>use scene::{BoxedScene, Scene};
use event::{Event, RenderArgs};
use conrod::UiContext;
use opengl_graphics::{Gl, Texture};
use graphics::{Context, AddImage, Draw};
use conrod::{
    Background,
    Color,
    Colorable,
    Drawable,
    Label,
    Labelable,
    Positionable
};
use input::{Release, Keyboard, keyboard};
use uorustlibs::art::{ArtReader, TileOrStatic, Art};
use uorustlibs::color::{Color16, Color32};
use uorustlibs::color::Color as ColorTrait;
use image::{GenericImage, ImageBuf, Rgba};

use std::io::IoResult;

pub struct TileScene {
    reader: IoResult<ArtReader>,
    image: ImageBuf<Rgba<u8>>,
    texture: Texture
}

impl TileScene {
    pub fn new() -> BoxedScene {
        let mut reader = ArtReader::new(&Path::new("./assets/artidx.mul"), &Path::new("./assets/art.mul"));
        let mut image = match reader {
            Ok(ref mut reader) => {
                let tile = match reader.read(0).ok().expect("Couldn't load tile 0") {
                    TileOrStatic::Tile(tile) => tile,
                    TileOrStatic::Static(tile) => panic!("LOL")
                };
                let (width, height, data) = tile.to_32bit();
                ImageBuf::from_fn(width, height, |x, y| {
                    let (r, g, b, a) = data[((x % height) + (y * width)) as uint].to_rgba();
                    Rgba(r, g, b, a)
                })
            }
            _ => ImageBuf::new(44, 44)
        };
        let mut texture = Texture::from_image(&image);

        let mut scene = box TileScene {
            reader: reader,
            image: image,
            texture: texture
        };

        scene
    }

    fn render(&self, args: RenderArgs, uic: &mut UiContext, gl: &mut Gl) {
        uic.background().color(Color::black()).draw(gl);
        let c = Context::abs(args.width as f64, args.height as f64);
        c.image(&self.texture).draw(gl);
    }
}

impl Scene for TileScene {
    fn handle_event(&mut self, e: &Event, ui_context: &mut UiContext, gl: &mut Gl) -> Option<BoxedScene> {
        match *e {
            Event::Render(args) => {
                self.render(args, ui_context, gl);
            },
            Event::Input(Release(Keyboard(key))) => {
                match key {
                    keyboard::Left => {
                    },
                    keyboard::Right => {
                    },
                    _ => ()
                }
            },
            _ => ()
        };
        None
    }
}
<commit_msg>Trying to composite images<commit_after>use scene::{BoxedScene, Scene};
use event::{Event, RenderArgs};
use conrod::UiContext;
use opengl_graphics::{Gl, Texture};
use graphics::{Context, AddImage, Draw};
use conrod::{
    Background,
    Color,
    Colorable,
    Drawable,
    Label,
    Labelable,
    Positionable
};
use input::{Release, Keyboard, keyboard};
use uorustlibs::art::{ArtReader, TileOrStatic, Art};
use uorustlibs::color::{Color16, Color32};
use uorustlibs::color::Color as ColorTrait;
use image::{GenericImage, ImageBuf, Rgba};

use std::io::IoResult;

pub struct TileScene {
    reader: IoResult<ArtReader>,
    image: ImageBuf<Rgba<u8>>,
    texture: Texture
}

impl TileScene {
    pub fn new() -> BoxedScene {
        let mut reader = ArtReader::new(&Path::new("./assets/artidx.mul"), &Path::new("./assets/art.mul"));
        let mut image = match reader {
            Ok(ref mut reader) => {
                let tile = match reader.read(0).ok().expect("Couldn't load tile 0") {
                    TileOrStatic::Tile(tile) => tile,
                    TileOrStatic::Static(tile) => panic!("LOL")
                };
                let (width, height, data) = tile.to_32bit();
                ImageBuf::from_fn(width, height, |x, y| {
                    let (r, g, b, a) = data[((x % height) + (y * width)) as uint].to_rgba();
                    Rgba(r, g, b, a)
                })
            }
            _ => ImageBuf::new(44, 44)
        };
        let mut texture = Texture::from_image(&image);

        let mut scene = box TileScene {
            reader: reader,
            image: image,
            texture: texture
        };

        scene
    }

    fn create_slice(&mut self, reader: &mut ArtReader) {
        let max_x = 18;
        let max_y = 13;
        let limit = max_x * max_y;
        let idx = 0;
        let start = limit * idx;

        for x in range(0, max_x) {
            for y in range(0, max_y) {
                let maybe_tile = reader.read((x % max_y) + (y * max_x));
                match maybe_tile {
                    Ok(TileOrStatic::Tile(tile)) => {
                        let (width, height, data) = tile.to_32bit();
                        let buf = ImageBuf::from_fn(width, height, |x, y| {
                            let (r, g, b, a) = data[((x % height) + (y * width)) as uint].to_rgba();
                            Rgba(r, g, b, a)
                        });
                        let texture = Texture::new(0, 44, 44);
                    },
                    _ => ()
                }
            }
        }

    }

    fn render(&self, args: RenderArgs, uic: &mut UiContext, gl: &mut Gl) {
        uic.background().color(Color::black()).draw(gl);
        let c = Context::abs(args.width as f64, args.height as f64);
        c.image(&self.texture).draw(gl);
    }
}

impl Scene for TileScene {
    fn handle_event(&mut self, e: &Event, ui_context: &mut UiContext, gl: &mut Gl) -> Option<BoxedScene> {
        match *e {
            Event::Render(args) => {
                self.render(args, ui_context, gl);
            },
            Event::Input(Release(Keyboard(key))) => {
                match key {
                    keyboard::Left => {
                    },
                    keyboard::Right => {
                    },
                    _ => ()
                }
            },
            _ => ()
        };
        None
    }
}
<|endoftext|>


<commit_before>pub fn remove_mean_offset(signal: &[f32]) -> Vec<f32> {
    let mean = signal.iter().sum::<f32>()/signal.len() as f32;
    signal.iter().map(|x| x - mean).collect()
}

pub fn correlation(signal: &[f32]) -> Vec<f32> {
    (0..signal.len()).map(|offset| {
        signal.iter().take(signal.len() - offset)
            .zip(signal.iter().skip(offset))
            .map(|(sig_i, sig_j)| sig_i * sig_j)
            .sum()
    }).collect()
}

pub fn find_fundamental_frequency_correlation(signal: &[f32], sample_rate: f32) -> Option<f32> {
    let normalized_signal = remove_mean_offset(signal);

    if normalized_signal.iter().all(|&x| x.abs() < 0.05) {
        // silence
        return None;
    }

    let correlation = correlation(&normalized_signal);

    let first_peak_end = match correlation.iter().position(|&c| c < 0.0) {
        Some(p) => p,
        None => {
            // musical signals will drop below 0 at some point
            return None
        }
    };

    let peak = correlation.iter()
        .enumerate()
        .skip(first_peak_end)
        .fold((first_peak_end, 0.0), |(xi, xmag), (yi, &ymag)| if ymag > xmag { (yi, ymag) } else { (xi, xmag) });

    let (peak_index, _) = peak;

    let refined_peak_index = refine_fundamentals(&correlation, peak_index as f32 - 0.5, peak_index as f32 + 0.5);

    if is_noise(&correlation, refined_peak_index) {
        None
    }
    else {
        Some(sample_rate / refined_peak_index)
    }
}

fn refine_fundamentals(correlation: &[f32], low_bound: f32, high_bound: f32) -> f32 {
    let data_points = 2 * correlation.len() / high_bound.ceil() as usize;
    let range = high_bound - low_bound;
    let midpoint = (low_bound + high_bound) / 2.0;

    if (range * data_points as f32) < 1.0 {
        midpoint
    }
    else {
        let low_guess = score_guess(correlation, low_bound, data_points);
        let high_guess = score_guess(correlation, high_bound, data_points);

        if high_guess > low_guess {
            refine_fundamentals(correlation, midpoint, high_bound)
        }
        else {
            refine_fundamentals(correlation, low_bound, midpoint)
        }
    }
}

fn is_noise(correlation: &[f32], fundamental: f32) -> bool {
    let value_at_point = interpolate(correlation, fundamental);
    let score_data_points = 2 * correlation.len() / fundamental.ceil() as usize;
    let score = score_guess(correlation, fundamental, score_data_points);

    value_at_point > 2.0*score
}

fn score_guess(correlation: &[f32], period: f32, data_points: usize) -> f32 {
    (1..data_points).map(|i| {
        let expected_sign = if i % 2 == 0 { 1.0 } else { -1.0 };
        let x = i as f32 * period / 2.0;
        let weight = 0.5 * i as f32;
        expected_sign * weight * interpolate(correlation, x)
    }).sum()
}

fn interpolate(correlation: &[f32], x: f32) -> f32 {
    if x < 0.0 {
        correlation[0]
    }
    else if x >= correlation.len() as f32 {
        correlation[correlation.len()-1]
    }
    else {
        let x0 = x.floor();
        let y0 = correlation[x0 as usize];
        let x1 = x.ceil();
        let y1 = correlation[x1 as usize];

        if x0 as usize == x1 as usize {
            y0
        }
        else {
            (y0*(x1-x) + y1*(x-x0)) / (x1-x0)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::f32::consts::PI;

    const SAMPLE_RATE: f32 = 44100.0;
    const FRAMES: usize = 512;

    fn frequency_resolution() -> f32 {
        SAMPLE_RATE / 2.0 / FRAMES as f32
    }

    fn sin_arg(f: f32, t: f32, phase: f32) -> f32 {
        2.0 as f32 * PI * f * t + phase
    }

    fn sample_sinusoud(amplitude: f32, frequency: f32, phase: f32) -> Vec<f32> {
        (0..FRAMES)
            .map(|x| {
                let t = x as f32 / SAMPLE_RATE;
                sin_arg(frequency, t, phase).sin() * amplitude
            }).collect()
    }

    #[test]
    fn correlation_on_sine_wave() {
        let frequency = 440.0 as f32; //concert A

        let samples = sample_sinusoud(1.0, frequency, 0.0);
        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).expect("Find fundamental returned None");
        assert!((fundamental-frequency).abs() < frequency_resolution(), "expected={}, actual={}", frequency, fundamental);
    }

    #[test]
    fn correlation_on_two_sine_waves() {
        //Unfortunately, real signals won't be this neat
        let samples1a = sample_sinusoud(2.0, 440.0, 0.0);
        let samples2a = sample_sinusoud(1.0, 880.0, 0.0);
        let expected_fundamental = 440.0;

        let samples: Vec<f32> = samples1a.iter().zip(samples2a.iter())
            .map(|(a, b)| a+b)
            .collect();

        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).expect("Find fundamental returned None");

        assert!((fundamental-expected_fundamental).abs() < frequency_resolution(), "expected_fundamental={}, actual={}", expected_fundamental, fundamental);
    }

    #[test]
    fn interpolate_half_way() {
        assert_eq!(0.5, interpolate(&vec!(0.0, 1.0), 0.5))
    }
}

pub fn hz_to_midi_number(hz: f32) -> f32 {
    69.0 + 12.0 * (hz / 440.0).log2()
}

pub fn hz_to_cents_error(hz: f32) -> f32 {
    let midi_number = hz_to_midi_number(hz);
    let cents = (midi_number * 100.0).round() % 100.0;
    if cents >= 50.0 {
        cents - 100.0
    }
    else {
        cents
    }
}

pub fn hz_to_pitch(hz: f32) -> String {
    let pitch_names = [
        "C ",
        "C#",
        "D ",
        "Eb",
        "E ",
        "F ",
        "F#",
        "G ",
        "G#",
        "A ",
        "Bb",
        "B "
    ];

    let midi_number = hz_to_midi_number(hz);
    //midi_number of 0 is C-1.

    let rounded_pitch = midi_number.round() as i32;
    let name = pitch_names[rounded_pitch as usize % pitch_names.len()];
    let octave = rounded_pitch / pitch_names.len() as i32 - 1; //0 is C-1
    if octave < 0 {
        return "< C 1".to_string();
    }

    format!("{}{}", name, octave)
}

#[test]
fn a4_is_correct() {
    assert_eq!(hz_to_pitch(440.0), "A 4");
}

#[test]
fn a2_is_correct() {
    assert_eq!(hz_to_pitch(110.0), "A 2");
}

#[test]
fn c4_is_correct() {
    assert_eq!(hz_to_pitch(261.63), "C 4");
}

#[test]
fn f5_is_correct() {
    assert_eq!(hz_to_pitch(698.46), "F 5");
}

pub fn align_to_rising_edge(samples: &[f32]) -> Vec<f32> {
    remove_mean_offset(samples)
        .iter()
        .skip_while(|x| !x.is_sign_negative())
        .skip_while(|x| x.is_sign_negative())
        .cloned()
        .collect()
}
<commit_msg>Updated sharp/flat characters to use correct unicode<commit_after>pub fn remove_mean_offset(signal: &[f32]) -> Vec<f32> {
    let mean = signal.iter().sum::<f32>()/signal.len() as f32;
    signal.iter().map(|x| x - mean).collect()
}

pub fn correlation(signal: &[f32]) -> Vec<f32> {
    (0..signal.len()).map(|offset| {
        signal.iter().take(signal.len() - offset)
            .zip(signal.iter().skip(offset))
            .map(|(sig_i, sig_j)| sig_i * sig_j)
            .sum()
    }).collect()
}

pub fn find_fundamental_frequency_correlation(signal: &[f32], sample_rate: f32) -> Option<f32> {
    let normalized_signal = remove_mean_offset(signal);

    if normalized_signal.iter().all(|&x| x.abs() < 0.05) {
        // silence
        return None;
    }

    let correlation = correlation(&normalized_signal);

    let first_peak_end = match correlation.iter().position(|&c| c < 0.0) {
        Some(p) => p,
        None => {
            // musical signals will drop below 0 at some point
            return None
        }
    };

    let peak = correlation.iter()
        .enumerate()
        .skip(first_peak_end)
        .fold((first_peak_end, 0.0), |(xi, xmag), (yi, &ymag)| if ymag > xmag { (yi, ymag) } else { (xi, xmag) });

    let (peak_index, _) = peak;

    let refined_peak_index = refine_fundamentals(&correlation, peak_index as f32 - 0.5, peak_index as f32 + 0.5);

    if is_noise(&correlation, refined_peak_index) {
        None
    }
    else {
        Some(sample_rate / refined_peak_index)
    }
}

fn refine_fundamentals(correlation: &[f32], low_bound: f32, high_bound: f32) -> f32 {
    let data_points = 2 * correlation.len() / high_bound.ceil() as usize;
    let range = high_bound - low_bound;
    let midpoint = (low_bound + high_bound) / 2.0;

    if (range * data_points as f32) < 1.0 {
        midpoint
    }
    else {
        let low_guess = score_guess(correlation, low_bound, data_points);
        let high_guess = score_guess(correlation, high_bound, data_points);

        if high_guess > low_guess {
            refine_fundamentals(correlation, midpoint, high_bound)
        }
        else {
            refine_fundamentals(correlation, low_bound, midpoint)
        }
    }
}

fn is_noise(correlation: &[f32], fundamental: f32) -> bool {
    let value_at_point = interpolate(correlation, fundamental);
    let score_data_points = 2 * correlation.len() / fundamental.ceil() as usize;
    let score = score_guess(correlation, fundamental, score_data_points);

    value_at_point > 2.0*score
}

fn score_guess(correlation: &[f32], period: f32, data_points: usize) -> f32 {
    (1..data_points).map(|i| {
        let expected_sign = if i % 2 == 0 { 1.0 } else { -1.0 };
        let x = i as f32 * period / 2.0;
        let weight = 0.5 * i as f32;
        expected_sign * weight * interpolate(correlation, x)
    }).sum()
}

fn interpolate(correlation: &[f32], x: f32) -> f32 {
    if x < 0.0 {
        correlation[0]
    }
    else if x >= correlation.len() as f32 {
        correlation[correlation.len()-1]
    }
    else {
        let x0 = x.floor();
        let y0 = correlation[x0 as usize];
        let x1 = x.ceil();
        let y1 = correlation[x1 as usize];

        if x0 as usize == x1 as usize {
            y0
        }
        else {
            (y0*(x1-x) + y1*(x-x0)) / (x1-x0)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::f32::consts::PI;

    const SAMPLE_RATE: f32 = 44100.0;
    const FRAMES: usize = 512;

    fn frequency_resolution() -> f32 {
        SAMPLE_RATE / 2.0 / FRAMES as f32
    }

    fn sin_arg(f: f32, t: f32, phase: f32) -> f32 {
        2.0 as f32 * PI * f * t + phase
    }

    fn sample_sinusoud(amplitude: f32, frequency: f32, phase: f32) -> Vec<f32> {
        (0..FRAMES)
            .map(|x| {
                let t = x as f32 / SAMPLE_RATE;
                sin_arg(frequency, t, phase).sin() * amplitude
            }).collect()
    }

    #[test]
    fn correlation_on_sine_wave() {
        let frequency = 440.0 as f32; //concert A

        let samples = sample_sinusoud(1.0, frequency, 0.0);
        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).expect("Find fundamental returned None");
        assert!((fundamental-frequency).abs() < frequency_resolution(), "expected={}, actual={}", frequency, fundamental);
    }

    #[test]
    fn correlation_on_two_sine_waves() {
        //Unfortunately, real signals won't be this neat
        let samples1a = sample_sinusoud(2.0, 440.0, 0.0);
        let samples2a = sample_sinusoud(1.0, 880.0, 0.0);
        let expected_fundamental = 440.0;

        let samples: Vec<f32> = samples1a.iter().zip(samples2a.iter())
            .map(|(a, b)| a+b)
            .collect();

        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).expect("Find fundamental returned None");

        assert!((fundamental-expected_fundamental).abs() < frequency_resolution(), "expected_fundamental={}, actual={}", expected_fundamental, fundamental);
    }

    #[test]
    fn interpolate_half_way() {
        assert_eq!(0.5, interpolate(&vec!(0.0, 1.0), 0.5))
    }
}

pub fn hz_to_midi_number(hz: f32) -> f32 {
    69.0 + 12.0 * (hz / 440.0).log2()
}

pub fn hz_to_cents_error(hz: f32) -> f32 {
    let midi_number = hz_to_midi_number(hz);
    let cents = (midi_number * 100.0).round() % 100.0;
    if cents >= 50.0 {
        cents - 100.0
    }
    else {
        cents
    }
}

pub fn hz_to_pitch(hz: f32) -> String {
    let pitch_names = [
        "C",
        "C♯",
        "D",
        "E♭",
        "E",
        "F",
        "F♯",
        "G",
        "G♯",
        "A",
        "B♭",
        "B"
    ];

    let midi_number = hz_to_midi_number(hz);
    //midi_number of 0 is C-1.

    let rounded_pitch = midi_number.round() as i32;
    let name = pitch_names[rounded_pitch as usize % pitch_names.len()];
    let octave = rounded_pitch / pitch_names.len() as i32 - 1; //0 is C-1
    if octave < 0 {
        return "< C 1".to_string();
    }

    format!("{: <2}{}", name, octave)
}

#[test]
fn a4_is_correct() {
    assert_eq!(hz_to_pitch(440.0), "A 4");
}

#[test]
fn a2_is_correct() {
    assert_eq!(hz_to_pitch(110.0), "A 2");
}

#[test]
fn c4_is_correct() {
    assert_eq!(hz_to_pitch(261.63), "C 4");
}

#[test]
fn f5_is_correct() {
    assert_eq!(hz_to_pitch(698.46), "F 5");
}

pub fn align_to_rising_edge(samples: &[f32]) -> Vec<f32> {
    remove_mean_offset(samples)
        .iter()
        .skip_while(|x| !x.is_sign_negative())
        .skip_while(|x| x.is_sign_negative())
        .cloned()
        .collect()
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

#[phase(plugin)]
extern crate gl_generator;

extern crate glutin;
extern crate cgmath;
extern crate serialize;

use self::glutin::{Event, VirtualKeyCode}; // TODO: why 'self'?
use visualizer_types::{Color3};
use mgl::Mgl;
use mgl;
use std::mem;

use std::c_str::CString;

// TODO: remove 'gl'
use gl;
use gl::types::{GLfloat, GLuint, GLint};

static VS_SRC: &'static str =
   "#version 100\n\
    attribute vec2 position;\n\
    void main() {\n\
        gl_Position = vec4(position, 0.0, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 100\n\
    void main() {\n\
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n\
    }";

pub struct Visualizer {
    mgl: Mgl,
    window: glutin::Window,
    should_close: bool,
    color_counter: i32, // TODO: remove
    program: GLuint,
}

impl Visualizer {
    pub fn new() -> Visualizer {
        let window = glutin::Window::new().unwrap();
        unsafe {
            window.make_current();
        };
        let mgl = Mgl::new(|s| window.get_proc_address(s));
        {
            let version = unsafe {
                CString::new(mgl.gl.GetString(gl::VERSION) as *const i8, false)
            };
            println!("OpenGL version {}", version.as_str().unwrap());
        }
        {
            let version = unsafe {
                CString::new(mgl.gl.GetString(gl::SHADING_LANGUAGE_VERSION) as *const i8, false)
            };
            println!("GLSL ES version {}", version.as_str().unwrap());
        }
        let vs = mgl::compile_shader(&mgl.gl, VS_SRC, gl::VERTEX_SHADER);
        let fs = mgl::compile_shader(&mgl.gl, FS_SRC, gl::FRAGMENT_SHADER);
        let program = mgl::link_program(&mgl.gl, vs, fs);
        Visualizer {
            mgl: mgl,
            window: window,
            should_close: false,
            color_counter: 0,
            program: program,
        }
    }

    pub fn is_running(&self) -> bool {
        !self.should_close
    }

    fn handle_events(&mut self) {
        let events = self.window.poll_events().collect::<Vec<_>>();
        if !events.is_empty() {
            println!("{}", events);
        }
        for event in events.iter() {
            match *event {
                Event::KeyboardInput(_, _, Some(VirtualKeyCode::Escape))
                    | Event::Closed =>
                {
                    self.should_close = true;
                },
                _ => {},
            }
        }
    }

    fn draw(&mut self) {
        match self.color_counter {
            0 => self.mgl.set_clear_color(Color3{r: 0.5, g: 0.0, b: 0.0}),
            30 => self.mgl.set_clear_color(Color3{r: 0.0, g: 0.5, b: 0.0}),
            60 => self.mgl.set_clear_color(Color3{r: 0.0, g: 0.0, b: 0.5}),
            _ => if self.color_counter > 90 {
                self.color_counter = -1;
            },
        }
        self.color_counter += 1;
        self.mgl.clear_screen();
        unsafe {
            let vertices: [GLfloat, ..3 * 3] = [
                0.0,  0.5, 0.0,
                0.5, -0.5, 0.0,
                -0.5, -0.5, 0.0,
            ];

            let (w, h) = self.window.get_inner_size().unwrap();
            self.mgl.gl.Viewport(0, 0, w as GLint, h as GLint);

            self.mgl.gl.Clear(gl::COLOR_BUFFER_BIT);
            self.mgl.gl.UseProgram(self.program);
            self.mgl.gl.VertexAttribPointer(
                0, 3, gl::FLOAT, gl::FALSE, 0, mem::transmute(&vertices));
            self.mgl.gl.EnableVertexAttribArray(0);
            self.mgl.gl.DrawArrays(gl::TRIANGLES, 0, 3);
        }
        self.window.swap_buffers();
    }

    pub fn tick(&mut self) {
        self.handle_events();
        // self.logic();
        self.draw();
        // self.update_time();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>visualizer.rs: Removed unneded gl.Clear call<commit_after>// See LICENSE file for copyright and license details.

#[phase(plugin)]
extern crate gl_generator;

extern crate glutin;
extern crate cgmath;
extern crate serialize;

use self::glutin::{Event, VirtualKeyCode}; // TODO: why 'self'?
use visualizer_types::{Color3};
use mgl::Mgl;
use mgl;
use std::mem;

use std::c_str::CString;

// TODO: remove 'gl'
use gl;
use gl::types::{GLfloat, GLuint, GLint};

static VS_SRC: &'static str =
   "#version 100\n\
    attribute vec2 position;\n\
    void main() {\n\
        gl_Position = vec4(position, 0.0, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 100\n\
    void main() {\n\
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n\
    }";

pub struct Visualizer {
    mgl: Mgl,
    window: glutin::Window,
    should_close: bool,
    color_counter: i32, // TODO: remove
    program: GLuint,
}

impl Visualizer {
    pub fn new() -> Visualizer {
        let window = glutin::Window::new().unwrap();
        unsafe {
            window.make_current();
        };
        let mgl = Mgl::new(|s| window.get_proc_address(s));
        {
            let version = unsafe {
                CString::new(mgl.gl.GetString(gl::VERSION) as *const i8, false)
            };
            println!("OpenGL version {}", version.as_str().unwrap());
        }
        {
            let version = unsafe {
                CString::new(mgl.gl.GetString(gl::SHADING_LANGUAGE_VERSION) as *const i8, false)
            };
            println!("GLSL ES version {}", version.as_str().unwrap());
        }
        let vs = mgl::compile_shader(&mgl.gl, VS_SRC, gl::VERTEX_SHADER);
        let fs = mgl::compile_shader(&mgl.gl, FS_SRC, gl::FRAGMENT_SHADER);
        let program = mgl::link_program(&mgl.gl, vs, fs);
        Visualizer {
            mgl: mgl,
            window: window,
            should_close: false,
            color_counter: 0,
            program: program,
        }
    }

    pub fn is_running(&self) -> bool {
        !self.should_close
    }

    fn handle_events(&mut self) {
        let events = self.window.poll_events().collect::<Vec<_>>();
        if !events.is_empty() {
            println!("{}", events);
        }
        for event in events.iter() {
            match *event {
                Event::KeyboardInput(_, _, Some(VirtualKeyCode::Escape))
                    | Event::Closed =>
                {
                    self.should_close = true;
                },
                _ => {},
            }
        }
    }

    fn draw(&mut self) {
        match self.color_counter {
            0 => self.mgl.set_clear_color(Color3{r: 0.5, g: 0.0, b: 0.0}),
            30 => self.mgl.set_clear_color(Color3{r: 0.0, g: 0.5, b: 0.0}),
            60 => self.mgl.set_clear_color(Color3{r: 0.0, g: 0.0, b: 0.5}),
            _ => if self.color_counter > 90 {
                self.color_counter = -1;
            },
        }
        self.color_counter += 1;
        self.mgl.clear_screen();
        unsafe {
            let vertices: [GLfloat, ..3 * 3] = [
                0.0,  0.5, 0.0,
                0.5, -0.5, 0.0,
                -0.5, -0.5, 0.0,
            ];

            let (w, h) = self.window.get_inner_size().unwrap();
            self.mgl.gl.Viewport(0, 0, w as GLint, h as GLint);

            self.mgl.gl.UseProgram(self.program);
            self.mgl.gl.VertexAttribPointer(
                0, 3, gl::FLOAT, gl::FALSE, 0, mem::transmute(&vertices));
            self.mgl.gl.EnableVertexAttribArray(0);
            self.mgl.gl.DrawArrays(gl::TRIANGLES, 0, 3);
        }
        self.window.swap_buffers();
    }

    pub fn tick(&mut self) {
        self.handle_events();
        // self.logic();
        self.draw();
        // self.update_time();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>// FIXME: Remove this attribute once false positive is resolved.
#![allow(unused_parens)]
// conditionally allow deprecated items to allow using the
// "deprecated" table! macro
#![cfg_attr(
    any(feature = "huge-tables", feature = "large-tables"),
    allow(deprecated)
)]

use super::backend::{FailedToLookupTypeError, InnerPgTypeMetadata};
use super::{Pg, PgTypeMetadata};
use crate::prelude::*;

use std::borrow::Cow;
use std::collections::HashMap;

/// Determines the OID of types at runtime
///
/// Custom implementations of `Connection<Backend = Pg>` should not implement this trait directly.
/// Instead `GetPgMetadataCache` should be implemented, afterwards the generic implementation will provide
/// the necessary functions to perform the type lookup.
pub trait PgMetadataLookup {
    /// Determine the type metadata for the given `type_name`
    ///
    /// This function should only be used for user defined types, or types which
    /// come from an extension. This function may perform a SQL query to look
    /// up the type. For built-in types, a static OID should be preferred.
    fn lookup_type(&mut self, type_name: &str, schema: Option<&str>) -> PgTypeMetadata;
}

impl<T> PgMetadataLookup for T
where
    T: Connection<Backend = Pg> + GetPgMetadataCache,
{
    fn lookup_type(&mut self, type_name: &str, schema: Option<&str>) -> PgTypeMetadata {
        let cache_key = PgMetadataCacheKey {
            schema: schema.map(Cow::Borrowed),
            type_name: Cow::Borrowed(type_name),
        };

        {
            let metadata_cache = self.get_metadata_cache();

            if let Some(metadata) = metadata_cache.lookup_type(&cache_key) {
                return metadata;
            }
        }

        let r = lookup_type(&&cache_key, self);

        match r {
            Ok(type_metadata) => {
                self.get_metadata_cache()
                    .store_type(cache_key, type_metadata);
                PgTypeMetadata(Ok(type_metadata))
            }
            Err(_e) => PgTypeMetadata(Err(FailedToLookupTypeError::new(cache_key.into_owned()))),
        }
    }
}

/// Gets the `PgMetadataCache` for a `Connection<Backend=Pg>`
/// so that the lookup of user defined types, or types which come from an extension can be cached.
///
/// Implementing this trait for a `Connection<Backend=Pg>` will cause `PgMetadataLookup` to be auto implemented.
pub trait GetPgMetadataCache {
    /// Get the `PgMetadataCache`
    fn get_metadata_cache(&mut self) -> &mut PgMetadataCache;
}

fn lookup_type<T: Connection<Backend = Pg>>(
    cache_key: &PgMetadataCacheKey<'_>,
    conn: &mut T,
) -> QueryResult<InnerPgTypeMetadata> {
    let metadata_query = pg_type::table.select((pg_type::oid, pg_type::typarray));

    let metadata = if let Some(schema) = cache_key.schema.as_deref() {
        // We have an explicit type name and schema given here
        // that should resolve to an unique type
        metadata_query
            .inner_join(pg_namespace::table)
            .filter(pg_type::typname.eq(&cache_key.type_name))
            .filter(pg_namespace::nspname.eq(schema))
            .first(conn)?
    } else {
        // We don't have a schema here. A type with the same name could exists
        // in more than one schema at once, even in more than one schema that
        // is in the current search path. As we don't want to reimplement
        // postgres name resolution here we just cast the time name to a concrete type
        // and let postgres figure out the name resolution on it's own.
        metadata_query
            .filter(
                pg_type::oid.eq(crate::dsl::sql("")
                    .bind::<crate::sql_types::Text, _>(&cache_key.type_name)
                    .sql("::regtype::oid")),
            )
            .first(conn)?
    };

    Ok(metadata)
}

/// The key used to lookup cached type oid's inside of
/// a [PgMetadataCache].
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
pub struct PgMetadataCacheKey<'a> {
    pub(in crate::pg) schema: Option<Cow<'a, str>>,
    pub(in crate::pg) type_name: Cow<'a, str>,
}

impl<'a> PgMetadataCacheKey<'a> {
    /// Construct a new cache key from an optional schema name and
    /// a type name
    pub fn new(schema: Option<Cow<'a, str>>, type_name: Cow<'a, str>) -> Self {
        Self { schema, type_name }
    }

    /// Convert the possibly borrowed version of this metadata cache key
    /// into a lifetime independ owned version
    pub fn into_owned(self) -> PgMetadataCacheKey<'static> {
        let PgMetadataCacheKey { schema, type_name } = self;
        PgMetadataCacheKey {
            schema: schema.map(|s| Cow::Owned(s.into_owned())),
            type_name: Cow::Owned(type_name.into_owned()),
        }
    }
}

/// Cache for the [OIDs] of custom Postgres types
///
/// [OIDs]: https://www.postgresql.org/docs/current/static/datatype-oid.html
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct PgMetadataCache {
    cache: HashMap<PgMetadataCacheKey<'static>, InnerPgTypeMetadata>,
}

impl PgMetadataCache {
    /// Construct a new `PgMetadataCache`
    pub fn new() -> Self {
        Default::default()
    }

    /// Lookup the OID of a custom type
    pub fn lookup_type(&self, type_name: &PgMetadataCacheKey<'_>) -> Option<PgTypeMetadata> {
        Some(PgTypeMetadata(Ok(*self.cache.get(type_name)?)))
    }

    /// Store the OID of a custom type
    pub fn store_type(
        &mut self,
        type_name: PgMetadataCacheKey<'_>,
        type_metadata: impl Into<InnerPgTypeMetadata>,
    ) {
        self.cache
            .insert(type_name.into_owned(), type_metadata.into());
    }
}

table! {
    pg_type (oid) {
        oid -> Oid,
        typname -> Text,
        typarray -> Oid,
        typnamespace -> Oid,
    }
}

table! {
    pg_namespace (oid) {
        oid -> Oid,
        nspname -> Text,
    }
}

joinable!(pg_type -> pg_namespace(typnamespace));
allow_tables_to_appear_in_same_query!(pg_type, pg_namespace);

sql_function! { fn pg_my_temp_schema() -> Oid; }
<commit_msg>add quote_ident to fix resolution of lowercase custom types<commit_after>// FIXME: Remove this attribute once false positive is resolved.
#![allow(unused_parens)]
// conditionally allow deprecated items to allow using the
// "deprecated" table! macro
#![cfg_attr(
    any(feature = "huge-tables", feature = "large-tables"),
    allow(deprecated)
)]

use super::backend::{FailedToLookupTypeError, InnerPgTypeMetadata};
use super::{Pg, PgTypeMetadata};
use crate::prelude::*;

use std::borrow::Cow;
use std::collections::HashMap;

/// Determines the OID of types at runtime
///
/// Custom implementations of `Connection<Backend = Pg>` should not implement this trait directly.
/// Instead `GetPgMetadataCache` should be implemented, afterwards the generic implementation will provide
/// the necessary functions to perform the type lookup.
pub trait PgMetadataLookup {
    /// Determine the type metadata for the given `type_name`
    ///
    /// This function should only be used for user defined types, or types which
    /// come from an extension. This function may perform a SQL query to look
    /// up the type. For built-in types, a static OID should be preferred.
    fn lookup_type(&mut self, type_name: &str, schema: Option<&str>) -> PgTypeMetadata;
}

impl<T> PgMetadataLookup for T
where
    T: Connection<Backend = Pg> + GetPgMetadataCache,
{
    fn lookup_type(&mut self, type_name: &str, schema: Option<&str>) -> PgTypeMetadata {
        let cache_key = PgMetadataCacheKey {
            schema: schema.map(Cow::Borrowed),
            type_name: Cow::Borrowed(type_name),
        };

        {
            let metadata_cache = self.get_metadata_cache();

            if let Some(metadata) = metadata_cache.lookup_type(&cache_key) {
                return metadata;
            }
        }

        let r = lookup_type(&&cache_key, self);

        match r {
            Ok(type_metadata) => {
                self.get_metadata_cache()
                    .store_type(cache_key, type_metadata);
                PgTypeMetadata(Ok(type_metadata))
            }
            Err(_e) => PgTypeMetadata(Err(FailedToLookupTypeError::new(cache_key.into_owned()))),
        }
    }
}

/// Gets the `PgMetadataCache` for a `Connection<Backend=Pg>`
/// so that the lookup of user defined types, or types which come from an extension can be cached.
///
/// Implementing this trait for a `Connection<Backend=Pg>` will cause `PgMetadataLookup` to be auto implemented.
pub trait GetPgMetadataCache {
    /// Get the `PgMetadataCache`
    fn get_metadata_cache(&mut self) -> &mut PgMetadataCache;
}

fn lookup_type<T: Connection<Backend = Pg>>(
    cache_key: &PgMetadataCacheKey<'_>,
    conn: &mut T,
) -> QueryResult<InnerPgTypeMetadata> {
    let metadata_query = pg_type::table.select((pg_type::oid, pg_type::typarray));

    let metadata = if let Some(schema) = cache_key.schema.as_deref() {
        // We have an explicit type name and schema given here
        // that should resolve to an unique type
        metadata_query
            .inner_join(pg_namespace::table)
            .filter(pg_type::typname.eq(&cache_key.type_name))
            .filter(pg_namespace::nspname.eq(schema))
            .first(conn)?
    } else {
        // We don't have a schema here. A type with the same name could exists
        // in more than one schema at once, even in more than one schema that
        // is in the current search path. As we don't want to reimplement
        // postgres name resolution here we just cast the time name to a concrete type
        // and let postgres figure out the name resolution on it's own.
        metadata_query
            .filter(
                pg_type::oid.eq(crate::dsl::sql("quote_ident(")
                    .bind::<crate::sql_types::Text, _>(&cache_key.type_name)
                    .sql(")::regtype::oid")),
            )
            .first(conn)?
    };

    Ok(metadata)
}

/// The key used to lookup cached type oid's inside of
/// a [PgMetadataCache].
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
pub struct PgMetadataCacheKey<'a> {
    pub(in crate::pg) schema: Option<Cow<'a, str>>,
    pub(in crate::pg) type_name: Cow<'a, str>,
}

impl<'a> PgMetadataCacheKey<'a> {
    /// Construct a new cache key from an optional schema name and
    /// a type name
    pub fn new(schema: Option<Cow<'a, str>>, type_name: Cow<'a, str>) -> Self {
        Self { schema, type_name }
    }

    /// Convert the possibly borrowed version of this metadata cache key
    /// into a lifetime independ owned version
    pub fn into_owned(self) -> PgMetadataCacheKey<'static> {
        let PgMetadataCacheKey { schema, type_name } = self;
        PgMetadataCacheKey {
            schema: schema.map(|s| Cow::Owned(s.into_owned())),
            type_name: Cow::Owned(type_name.into_owned()),
        }
    }
}

/// Cache for the [OIDs] of custom Postgres types
///
/// [OIDs]: https://www.postgresql.org/docs/current/static/datatype-oid.html
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct PgMetadataCache {
    cache: HashMap<PgMetadataCacheKey<'static>, InnerPgTypeMetadata>,
}

impl PgMetadataCache {
    /// Construct a new `PgMetadataCache`
    pub fn new() -> Self {
        Default::default()
    }

    /// Lookup the OID of a custom type
    pub fn lookup_type(&self, type_name: &PgMetadataCacheKey<'_>) -> Option<PgTypeMetadata> {
        Some(PgTypeMetadata(Ok(*self.cache.get(type_name)?)))
    }

    /// Store the OID of a custom type
    pub fn store_type(
        &mut self,
        type_name: PgMetadataCacheKey<'_>,
        type_metadata: impl Into<InnerPgTypeMetadata>,
    ) {
        self.cache
            .insert(type_name.into_owned(), type_metadata.into());
    }
}

table! {
    pg_type (oid) {
        oid -> Oid,
        typname -> Text,
        typarray -> Oid,
        typnamespace -> Oid,
    }
}

table! {
    pg_namespace (oid) {
        oid -> Oid,
        nspname -> Text,
    }
}

joinable!(pg_type -> pg_namespace(typnamespace));
allow_tables_to_appear_in_same_query!(pg_type, pg_namespace);

sql_function! { fn pg_my_temp_schema() -> Oid; }
<|endoftext|>


<commit_before>use std;
use ::serialize::{self, Serializable, UInt256};

#[derive(Debug,Default,Clone)]
pub struct BlockLocator {
   pub haves: Vec<UInt256>,
}

impl std::fmt::Display for BlockLocator {
   fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
      write!(f, "BlockLocator(len={})", self.haves.len())
   }
}

impl Serializable for BlockLocator {
   fn get_serialize_size(&self, ser:&serialize::SerializeParam) -> usize {
      let mut r:usize = 4;
      if ser.sertype & serialize::SER_GETHASH != 0 {
         r += ser.version.get_serialize_size(ser);
      }
      r += self.haves.get_serialize_size(ser);
      r
   }
   fn serialize(&self, io:&mut std::io::Write, ser:&serialize::SerializeParam) -> serialize::Result {
      let mut r:usize = 0;
      if ser.sertype & serialize::SER_GETHASH != 0 {
         r += try!(ser.version.serialize(io, ser));
      }
      r += try!(self.haves.serialize(io, ser));
      Ok(r)
   }
   fn deserialize(&mut self, io:&mut std::io::Read, ser:&serialize::SerializeParam) -> serialize::Result {
      let mut r:usize = 0;
      if ser.sertype & serialize::SER_GETHASH != 0 {
         let mut version:i32 = 0;
         r += try!(version.deserialize(io, ser));
      }
      r += try!(self.haves.deserialize(io, ser));
      Ok(r)
   }
}

<commit_msg>debug serialize of BlockLocator<commit_after>use std;
use ::serialize::{self, Serializable, UInt256};

#[derive(Debug,Default,Clone)]
pub struct BlockLocator {
   pub haves: Vec<UInt256>,
}

impl std::fmt::Display for BlockLocator {
   fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
      write!(f, "BlockLocator(len={})", self.haves.len())
   }
}

impl Serializable for BlockLocator {
   fn get_serialize_size(&self, ser:&serialize::SerializeParam) -> usize {
      let mut r:usize = 0;
      if ser.sertype & serialize::SER_GETHASH == 0 {
         r += ser.version.get_serialize_size(ser);
      }
      r += self.haves.get_serialize_size(ser);
      r
   }
   fn serialize(&self, io:&mut std::io::Write, ser:&serialize::SerializeParam) -> serialize::Result {
      let mut r:usize = 0;
      if ser.sertype & serialize::SER_GETHASH == 0 {
         r += try!(ser.version.serialize(io, ser));
      }
      r += try!(self.haves.serialize(io, ser));
      Ok(r)
   }
   fn deserialize(&mut self, io:&mut std::io::Read, ser:&serialize::SerializeParam) -> serialize::Result {
      let mut r:usize = 0;
      if ser.sertype & serialize::SER_GETHASH == 0 {
         let mut version:i32 = 0;
         r += try!(version.deserialize(io, ser));
      }
      r += try!(self.haves.deserialize(io, ser));
      Ok(r)
   }
}

<|endoftext|>