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

//! GdkPixbufLoader — Application-driven progressive image loading.

use std;
use ffi;
use glib::{to_bool, GlibContainer};
use glib::translate::ToGlibPtr;
use libc::{c_int, c_uint};

#[repr(C)]
pub struct PixbufLoader {
    pointer: *mut ffi::C_GdkPixbufLoader
}

impl PixbufLoader {
    /// Creates a new pixbuf loader object.
    ///
    /// # Failures
    /// Returns `None` if the pixbuf loader cannot be created.
    pub fn new() -> Option<PixbufLoader> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new() };

        if tmp.is_null() {
            None
        } else {
            Some(PixbufLoader::wrap_pointer(tmp))
        }
    }

    /// Creates a new pixbuf loader object that always attempts to parse image
    /// data as if it were an image of type `image_type`, instead of
    /// identifying the type automatically. Useful if you want an error if the
    /// image isn't the expected type, for loading image formats that can't be
    /// reliably identified by looking at the data, or if the user manually
    /// forces a specific type.
    ///
    /// The list of supported image formats depends on what image loaders are
    /// installed, but typically "png", "jpeg", "gif", "tiff" and "xpm" are
    /// among the supported formats.
    ///
    /// # Failures
    /// Returns `None` if the pixbuf loader cannot be created.
    pub fn new_with_type(image_type: &str, error: &mut ::glib::Error) -> Option<PixbufLoader> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new_with_type(image_type.borrow_to_glib().0, &mut error.unwrap()) };

        if tmp.is_null() {
            None
        } else {
            Some(PixbufLoader::wrap_pointer(tmp))
        }
    }

    /// Creates a new pixbuf loader object that always attempts to parse image
    /// data as if it were an image of mime type `mime_type`, instead of
    /// identifying the type automatically. Useful if you want an error if the
    /// image isn't the expected mime type, for loading image formats that can't
    /// be reliably identified by looking at the data, or if the user manually
    /// forces a specific mime type.
    ///
    /// The list of supported mime types depends on what image loaders are
    /// installed, but typically "image/png", "image/jpeg", "image/gif",
    /// "image/tiff" and "image/x-xpixmap" are among the supported mime types.
    ///
    /// # Failures
    /// Returns `None` if the pixbuf loader cannot be created.
    pub fn new_with_mime_type(mime_type: &str, error: &mut ::glib::Error) -> Option<PixbufLoader> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new_with_mime_type(mime_type.borrow_to_glib().0, &mut error.unwrap()) };

        if tmp.is_null() {
            None
        } else {
            Some(PixbufLoader::wrap_pointer(tmp))
        }
    }

    /// Obtains the available information about the format of the currently
    /// loading image file.
    pub fn get_format(&self) -> Option<::PixbufFormat> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_get_format(self.unwrap_pointer()) };

        if tmp.is_null() {
            None
        } else {
            Some(::PixbufFormat::wrap_pointer(tmp))
        }
    }

    /// This will cause a pixbuf loader to parse the  bytes of an image stored
    /// in `buf`. It will return `Ok` if the data was loaded successfully, and
    /// `Err` if an error occurred. In the latter case, the loader will be
    /// closed, and will not accept further writes.
    pub fn loader_write(&self, buf: &[u8]) -> Result<(), ::glib::Error> {
        unsafe {
            let mut error: *mut ::glib::ffi::C_GError = std::ptr::null_mut();
            match to_bool(ffi::gdk_pixbuf_loader_write(self.unwrap_pointer(), buf.as_ptr(), buf.len() as c_uint, &mut error)) {
                true => Ok(()),
                false => Err(::glib::Error::wrap(error))
            }
        }
    }

    /*pub fn loader_write_bytes(&self, buffer: &glib::Bytes, error: &mut ::glib::Error) -> bool {
      gdk_pixbuf_loader_write_bytes
      }*/

    /// Causes the image to be scaled while it is loaded. The desired image
    /// size can be determined relative to the original size of the image by
    /// calling `set_size()` from a signal handler for the `size-prepared`
    /// signal.
    ///
    /// Attempts to set the desired image size are ignored after the emission
    /// of the `size-prepared` signal.
    pub fn set_size(&self, width: isize, height: isize) {
        unsafe { ffi::gdk_pixbuf_loader_set_size(self.unwrap_pointer(), width as c_int, height as c_int) }
    }

    /// Queries the `Pixbuf` that a pixbuf loader is currently creating. In
    /// general it only makes sense to call this function after the
    /// `area-prepared` signal has been emitted by the loader; this means that
    /// enough data has been read to know the size of the image that will be
    /// allocated. If the loader has not received enough data via
    /// `loader_write()`, then this function returns `None`. If the loader is
    /// an animation, it will return the "static image" of the animation.
    pub fn get_pixbuf(&self) -> Option<::Pixbuf> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_get_pixbuf(self.unwrap_pointer()) };

        if tmp.is_null() {
            None
        } else {
            Some(::Pixbuf::wrap_pointer(tmp))
        }
    }

    /*pub fn get_animation(&self) -> Option<::PixbufAnimation> {
      let tmp = unsafe { ffi::gdk_pixbuf_loader_get_animation(self.unwrap_pointer()) };

      if tmp.is_null() {
      None
      } else {
      Some(::PixbufAnimation::wrap_pointer(tmp))
      }
      }*/

    /// Informs a pixbuf loader that no further writes with `loader_write()`
    /// will occur, so that it can free its internal loading structures. Also,
    /// tries to parse any data that hasn't yet been parsed; if the remaining
    /// data is partial or corrupt, an error will be returned.
    pub fn close(&self) -> Result<(), ::glib::Error> {
        unsafe {
            let mut error: *mut ::glib::ffi::C_GError = std::ptr::null_mut();
            match to_bool(ffi::gdk_pixbuf_loader_close(self.unwrap_pointer(), &mut error)) {
                true => Ok(()),
                false => Err(::glib::Error::wrap(error))
            }
        }
    }
}

impl_GObjectFunctions!(PixbufLoader, C_GdkPixbufLoader);
<commit_msg>Minor style changes, updating documentation<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! GdkPixbufLoader — Application-driven progressive image loading.

use std;
use ffi;
use glib::{to_bool, GlibContainer, Error};
use glib::translate::ToGlibPtr;
use libc::{c_int, c_uint};

#[repr(C)]
pub struct PixbufLoader {
    pointer: *mut ffi::C_GdkPixbufLoader
}

impl PixbufLoader {
    /// Creates a new pixbuf loader object.
    ///
    /// # Failures
    /// Returns `None` if the pixbuf loader cannot be created.
    pub fn new() -> Option<PixbufLoader> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new() };

        if tmp.is_null() {
            None
        } else {
            Some(PixbufLoader::wrap_pointer(tmp))
        }
    }

    /// Creates a new pixbuf loader object that always attempts to parse image
    /// data as if it were an image of type `image_type`, instead of
    /// identifying the type automatically. Useful if you want an error if the
    /// image isn't the expected type, for loading image formats that can't be
    /// reliably identified by looking at the data, or if the user manually
    /// forces a specific type.
    ///
    /// The list of supported image formats depends on what image loaders are
    /// installed, but typically "png", "jpeg", "gif", "tiff" and "xpm" are
    /// among the supported formats.
    ///
    /// # Failures
    /// Returns `None` if the pixbuf loader cannot be created.
    pub fn new_with_type(image_type: &str, error: &mut Error) -> Option<PixbufLoader> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new_with_type(image_type.borrow_to_glib().0, &mut error.unwrap()) };

        if tmp.is_null() {
            None
        } else {
            Some(PixbufLoader::wrap_pointer(tmp))
        }
    }

    /// Creates a new pixbuf loader object that always attempts to parse image
    /// data as if it were an image of mime type `mime_type`, instead of
    /// identifying the type automatically. Useful if you want an error if the
    /// image isn't the expected mime type, for loading image formats that can't
    /// be reliably identified by looking at the data, or if the user manually
    /// forces a specific mime type.
    ///
    /// The list of supported mime types depends on what image loaders are
    /// installed, but typically "image/png", "image/jpeg", "image/gif",
    /// "image/tiff" and "image/x-xpixmap" are among the supported mime types.
    ///
    /// # Failures
    /// Returns `None` if the pixbuf loader cannot be created.
    pub fn new_with_mime_type(mime_type: &str, error: &mut Error) -> Option<PixbufLoader> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new_with_mime_type(mime_type.borrow_to_glib().0, &mut error.unwrap()) };

        if tmp.is_null() {
            None
        } else {
            Some(PixbufLoader::wrap_pointer(tmp))
        }
    }

    /// Obtains the available information about the format of the currently
    /// loading image file.
    ///
    /// # Failures
    /// Returns `None` if the pixbuf format cannot be retrieved, or if not
    /// enough data is available to create the format.
    pub fn get_format(&self) -> Option<::PixbufFormat> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_get_format(self.unwrap_pointer()) };

        if tmp.is_null() {
            None
        } else {
            Some(::PixbufFormat::wrap_pointer(tmp))
        }
    }

    /// This will cause a pixbuf loader to parse the  bytes of an image stored
    /// in `buf`. It will return `Ok` if the data was loaded successfully, and
    /// `Err` if an error occurred. In the latter case, the loader will be
    /// closed, and will not accept further writes.
    ///
    /// # Failures
    /// Returns an `Error` if `buf` cannot be written to the loader.  Query the
    /// `Error` for more detailed information.
    pub fn loader_write(&self, buf: &[u8]) -> Result<(), Error> {
        unsafe {
            let mut error = std::ptr::null_mut();
            match to_bool(ffi::gdk_pixbuf_loader_write(self.unwrap_pointer(), buf.as_ptr(), buf.len() as c_uint, &mut error)) {
                true => Ok(()),
                false => Err(Error::wrap(error))
            }
        }
    }

    /*pub fn loader_write_bytes(&self, buffer: &glib::Bytes, error: &mut Error) -> bool {
      gdk_pixbuf_loader_write_bytes
      }*/

    /// Causes the image to be scaled while it is loaded. The desired image
    /// size can be determined relative to the original size of the image by
    /// calling `set_size()` from a signal handler for the `size-prepared`
    /// signal.
    ///
    /// Attempts to set the desired image size are ignored after the emission
    /// of the `size-prepared` signal.
    pub fn set_size(&self, width: isize, height: isize) {
        unsafe { ffi::gdk_pixbuf_loader_set_size(self.unwrap_pointer(), width as c_int, height as c_int) }
    }

    /// Queries the `Pixbuf` that a pixbuf loader is currently creating. In
    /// general it only makes sense to call this function after the
    /// `area-prepared` signal has been emitted by the loader; this means that
    /// enough data has been read to know the size of the image that will be
    /// allocated. If the loader has not received enough data via
    /// `loader_write()`, then this function returns `None`. If the loader is
    /// an animation, it will return the "static image" of the animation.
    ///
    /// # Failures
    /// Returns `None` if the pixbuf cannot be retrieved, or if not enough data
    /// is available to create the pixbuf.
    pub fn get_pixbuf(&self) -> Option<::Pixbuf> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_get_pixbuf(self.unwrap_pointer()) };

        if tmp.is_null() {
            None
        } else {
            Some(::Pixbuf::wrap_pointer(tmp))
        }
    }

    /*pub fn get_animation(&self) -> Option<::PixbufAnimation> {
      let tmp = unsafe { ffi::gdk_pixbuf_loader_get_animation(self.unwrap_pointer()) };

      if tmp.is_null() {
      None
      } else {
      Some(::PixbufAnimation::wrap_pointer(tmp))
      }
      }*/

    /// Informs a pixbuf loader that no further writes with `loader_write()`
    /// will occur, so that it can free its internal loading structures. Also,
    /// tries to parse any data that hasn't yet been parsed.
    ///
    /// # Failures
    /// If the remaining data is partial or corrupt, an error will be returned.
    /// Query the `Error` for more detailed information.
    pub fn close(&self) -> Result<(), Error> {
        unsafe {
            let mut error = std::ptr::null_mut();
            match to_bool(ffi::gdk_pixbuf_loader_close(self.unwrap_pointer(), &mut error)) {
                true => Ok(()),
                false => Err(Error::wrap(error))
            }
        }
    }
}

impl_GObjectFunctions!(PixbufLoader, C_GdkPixbufLoader);
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(io)]
#![feature(path)]
#![feature(env)]

extern crate protobuf;
extern crate rand;
extern crate time;

use std::old_io::File;
use std::default::Default;

use rand::Rng;
use rand::StdRng;
use rand::SeedableRng;

use protobuf::Message;
use protobuf::MessageStatic;
use perftest_data::PerftestData;

mod perftest_data;

fn measure_ns<R, F: FnMut() -> R>(mut f: F) -> (u64, R) {
    let start = time::precise_time_ns();
    let r = f();
    (time::precise_time_ns() - start, r)
}

fn measure_and_print<R, F: FnMut() -> R>(title: &str, iter: u64, f: F) -> R {
    let (ns, r) = measure_ns(f);
    let ns_per_iter = ns / iter;
    println!("{}: {} ns per iter", title, ns_per_iter);
    r
}

fn run_test<M : Message + MessageStatic>(name: &str, data: &[M]) {
    let mut rng: StdRng = SeedableRng::from_seed([10, 20, 30, 40].as_slice());
    let mut random_data: Vec<M> = Vec::new();

    let mut total_size = 0;
    while total_size < 1000000 {
        let ref item = data[rng.gen_range(0, data.len())];
        random_data.push(item.clone());
        total_size += item.compute_size();
    }

    let mut buf = Vec::new();
    measure_and_print(format!("{}: write", name).as_slice(), random_data.len() as u64, || {
        for m in random_data.iter() {
            m.write_length_delimited_to_writer(&mut buf).unwrap();
        }
    });

    let read_data = measure_and_print(format!("{}: read", name).as_slice(), random_data.len() as u64, || {
        let mut r = Vec::new();
        let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(buf.as_slice());
        while !coded_input_stream.eof().unwrap() {
            r.push(protobuf::parse_length_delimited_from::<M>(&mut coded_input_stream).unwrap());
        }
        r
    });

    assert_eq!(random_data, read_data);

    let merged = measure_and_print(format!("{}: read reuse", name).as_slice(), random_data.len() as u64, || {
        let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(buf.as_slice());
        let mut msg: M = Default::default();
        let mut count = 0;
        while !coded_input_stream.eof().unwrap() {
            msg.clear();
            coded_input_stream.merge_message(&mut msg).unwrap();
            count += 1;
        }
        count
    });

    assert_eq!(random_data.len(), merged);
}

struct TestRunner {
    selected: Option<String>,
    any_matched: bool,
}

impl TestRunner {
    fn test<M : Message + MessageStatic>(&mut self, name: &str, data: &[M]) {
        if self.selected.is_none() || name == self.selected.as_ref().unwrap().as_slice() {
            run_test(name, data);
            self.any_matched = true;
        }
    }

    fn check(&self) {
        if !self.any_matched {
            let name = self.selected.as_ref().map(|s| s.as_slice()).unwrap_or("bug");
            panic!("no tests found with name {}", name);
        }
    }
}

fn main() {
    let args = std::env::args().collect::<Vec<_>>();
    let selected = match args.iter().map(|s| s.as_slice()).collect::<Vec<_>>().as_slice() {
        [_] => None,
        [_, ref test] => Some(test.to_string()),
        v => panic!("usage: {} <test>", v[0]),
    };

    let mut runner = TestRunner { selected: selected, any_matched: false };

    let mut is = File::open(&Path::new("perftest_data.pbbin"));
    let test_data = protobuf::parse_from_reader::<PerftestData>(&mut is).unwrap();

    runner.test("test1", test_data.get_test1());
    runner.test("test_repeated_bool", test_data.get_test_repeated_bool());
    runner.test("test_repeated_packed_int32", test_data.get_test_repeated_packed_int32());
    runner.test("test_repeated_messages", test_data.get_test_repeated_messages());
    runner.test("test_optional_messages", test_data.get_test_optional_messages());
    runner.test("test_strings", test_data.get_test_strings());
    runner.check();
}
<commit_msg>Migrate perftest binary to new std::io.<commit_after>#![feature(core)]
#![feature(path)]

extern crate protobuf;
extern crate rand;
extern crate time;

use std::default::Default;
use std::fs::File;
use std::path::Path;

use rand::Rng;
use rand::StdRng;
use rand::SeedableRng;

use protobuf::Message;
use protobuf::MessageStatic;
use perftest_data::PerftestData;

mod perftest_data;

fn measure_ns<R, F: FnMut() -> R>(mut f: F) -> (u64, R) {
    let start = time::precise_time_ns();
    let r = f();
    (time::precise_time_ns() - start, r)
}

fn measure_and_print<R, F: FnMut() -> R>(title: &str, iter: u64, f: F) -> R {
    let (ns, r) = measure_ns(f);
    let ns_per_iter = ns / iter;
    println!("{}: {} ns per iter", title, ns_per_iter);
    r
}

fn run_test<M : Message + MessageStatic>(name: &str, data: &[M]) {
    let mut rng: StdRng = SeedableRng::from_seed([10, 20, 30, 40].as_slice());
    let mut random_data: Vec<M> = Vec::new();

    let mut total_size = 0;
    while total_size < 1000000 {
        let ref item = data[rng.gen_range(0, data.len())];
        random_data.push(item.clone());
        total_size += item.compute_size();
    }

    let mut buf = Vec::new();
    measure_and_print(format!("{}: write", name).as_slice(), random_data.len() as u64, || {
        for m in random_data.iter() {
            m.write_length_delimited_to_writer(&mut buf).unwrap();
        }
    });

    let read_data = measure_and_print(format!("{}: read", name).as_slice(), random_data.len() as u64, || {
        let mut r = Vec::new();
        let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(buf.as_slice());
        while !coded_input_stream.eof().unwrap() {
            r.push(protobuf::parse_length_delimited_from::<M>(&mut coded_input_stream).unwrap());
        }
        r
    });

    assert_eq!(random_data, read_data);

    let merged = measure_and_print(format!("{}: read reuse", name).as_slice(), random_data.len() as u64, || {
        let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(buf.as_slice());
        let mut msg: M = Default::default();
        let mut count = 0;
        while !coded_input_stream.eof().unwrap() {
            msg.clear();
            coded_input_stream.merge_message(&mut msg).unwrap();
            count += 1;
        }
        count
    });

    assert_eq!(random_data.len(), merged);
}

struct TestRunner {
    selected: Option<String>,
    any_matched: bool,
}

impl TestRunner {
    fn test<M : Message + MessageStatic>(&mut self, name: &str, data: &[M]) {
        if self.selected.is_none() || name == self.selected.as_ref().unwrap().as_slice() {
            run_test(name, data);
            self.any_matched = true;
        }
    }

    fn check(&self) {
        if !self.any_matched {
            let name = self.selected.as_ref().map(|s| s.as_slice()).unwrap_or("bug");
            panic!("no tests found with name {}", name);
        }
    }
}

fn main() {
    let args = std::env::args().collect::<Vec<_>>();
    let selected = match args.iter().map(|s| s.as_slice()).collect::<Vec<_>>().as_slice() {
        [_] => None,
        [_, ref test] => Some(test.to_string()),
        v => panic!("usage: {} <test>", v[0]),
    };

    let mut runner = TestRunner { selected: selected, any_matched: false };

    let mut is = File::open(&Path::new("perftest_data.pbbin")).unwrap();
    let test_data = protobuf::parse_from_reader::<PerftestData>(&mut is).unwrap();

    runner.test("test1", test_data.get_test1());
    runner.test("test_repeated_bool", test_data.get_test_repeated_bool());
    runner.test("test_repeated_packed_int32", test_data.get_test_repeated_packed_int32());
    runner.test("test_repeated_messages", test_data.get_test_repeated_messages());
    runner.test("test_optional_messages", test_data.get_test_optional_messages());
    runner.test("test_strings", test_data.get_test_strings());
    runner.check();
}
<|endoftext|>


<commit_before>
use std::io;
use std::borrow::Cow;
use std::fmt;
use std::error;

use common::{Position, TextPosition};

use super::{Error, ErrorKind};

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {}", self.pos, self.msg())
    }
}

impl Position for Error {
    #[inline]
    fn position(&self) -> TextPosition { self.pos }
}

impl Error {
    /// Returns a reference to a message which is contained inside this error.
    #[inline]
    pub fn msg(&self) -> &str {
    	use super::ErrorKind::*;
    	match self.kind {
    		UnexpectedEof => &"Unexpected EOF",
    		Utf8( ref reason ) => error_description( reason ),
    		Io( ref io_error ) => error_description( io_error ),
    		Syntax( ref msg ) => msg.as_ref(),
    	}
    }

    pub fn kind( &self ) -> &ErrorKind { &self.kind }
}

impl error::Error for Error {
    #[inline]
    fn description(&self) -> &str { self.msg() }
}

impl<'a, P, M> From<( &'a P, M )> for Error where P: Position, M: Into<Cow<'static, str>> {
	fn from( orig: (&'a P, M) ) -> Self {
		Error{
			pos: orig.0.position(),
			kind: ErrorKind::Syntax( orig.1.into() )
		}
	}
}

impl From<::util::CharReadError> for Error {
	fn from( e: ::util::CharReadError ) -> Self {
		use ::util::CharReadError::*;
		Error{
			pos: TextPosition::new(),
			kind: match e {
				UnexpectedEof => ErrorKind::UnexpectedEof,
				Utf8( ref reason ) => ErrorKind::Utf8( reason.clone() ),
				Io( ref io_error ) =>
					ErrorKind::Io(
						io::Error::new(
							io_error.kind(),
							error_description( io_error )
						)
					),
			}
		}
	}
}

impl Clone for ErrorKind {
	fn clone( &self ) -> Self {
		use super::ErrorKind::*;
		match *self {
			UnexpectedEof => UnexpectedEof,
			Utf8( ref reason ) => Utf8( reason.clone() ),
			Io( ref io_error ) => Io( io::Error::new( io_error.kind(), error_description( io_error ) ) ),
			Syntax( ref msg ) => Syntax( msg.clone() ),
		}
	}
}
impl PartialEq for ErrorKind {
	fn eq( &self, other: &ErrorKind ) -> bool {
		use super::ErrorKind::*;
		match ( self, other ) {
			( &UnexpectedEof, &UnexpectedEof ) => true,
			( &Utf8( ref left ), &Utf8( ref right ) ) => left == right,
			( &Io( ref left ), &Io( ref right ) ) =>
				left.kind() == right.kind() &&
				error_description( left ) == error_description( right ),
			( &Syntax( ref left ), &Syntax( ref right ) ) =>
				left == right,

			( _, _ ) => false,
		}
	}
}
impl Eq for ErrorKind {}

fn error_description( e: &error::Error ) -> &str { e.description() }<commit_msg>s/::util::/util::/ (with `use util;`)<commit_after>
use std::io;
use std::borrow::Cow;
use std::fmt;
use std::error;

use util;
use common::{Position, TextPosition};

use super::{Error, ErrorKind};

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {}", self.pos, self.msg())
    }
}

impl Position for Error {
    #[inline]
    fn position(&self) -> TextPosition { self.pos }
}

impl Error {
    /// Returns a reference to a message which is contained inside this error.
    #[inline]
    pub fn msg(&self) -> &str {
    	use super::ErrorKind::*;
    	match self.kind {
    		UnexpectedEof => &"Unexpected EOF",
    		Utf8( ref reason ) => error_description( reason ),
    		Io( ref io_error ) => error_description( io_error ),
    		Syntax( ref msg ) => msg.as_ref(),
    	}
    }

    pub fn kind( &self ) -> &ErrorKind { &self.kind }
}

impl error::Error for Error {
    #[inline]
    fn description(&self) -> &str { self.msg() }
}

impl<'a, P, M> From<( &'a P, M )> for Error where P: Position, M: Into<Cow<'static, str>> {
	fn from( orig: (&'a P, M) ) -> Self {
		Error{
			pos: orig.0.position(),
			kind: ErrorKind::Syntax( orig.1.into() )
		}
	}
}

impl From<util::CharReadError> for Error {
	fn from( e: util::CharReadError ) -> Self {
		use util::CharReadError::*;
		Error{
			pos: TextPosition::new(),
			kind: match e {
				UnexpectedEof => ErrorKind::UnexpectedEof,
				Utf8( ref reason ) => ErrorKind::Utf8( reason.clone() ),
				Io( ref io_error ) =>
					ErrorKind::Io(
						io::Error::new(
							io_error.kind(),
							error_description( io_error )
						)
					),
			}
		}
	}
}

impl Clone for ErrorKind {
	fn clone( &self ) -> Self {
		use super::ErrorKind::*;
		match *self {
			UnexpectedEof => UnexpectedEof,
			Utf8( ref reason ) => Utf8( reason.clone() ),
			Io( ref io_error ) => Io( io::Error::new( io_error.kind(), error_description( io_error ) ) ),
			Syntax( ref msg ) => Syntax( msg.clone() ),
		}
	}
}
impl PartialEq for ErrorKind {
	fn eq( &self, other: &ErrorKind ) -> bool {
		use super::ErrorKind::*;
		match ( self, other ) {
			( &UnexpectedEof, &UnexpectedEof ) => true,
			( &Utf8( ref left ), &Utf8( ref right ) ) => left == right,
			( &Io( ref left ), &Io( ref right ) ) =>
				left.kind() == right.kind() &&
				error_description( left ) == error_description( right ),
			( &Syntax( ref left ), &Syntax( ref right ) ) =>
				left == right,

			( _, _ ) => false,
		}
	}
}
impl Eq for ErrorKind {}

fn error_description( e: &error::Error ) -> &str { e.description() }<|endoftext|>


<commit_before>use libc::{c_char, c_int, wchar_t, FILE};
use core::ptr;
use object::*;
use pystate::PyThreadState;
#[cfg(not(Py_LIMITED_API))]
use pyarena::PyArena;

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" { // TODO: these moved to pylifecycle.h
    #[cfg(Py_3_4)]
    pub fn Py_SetStandardStreamEncoding(encoding: *const c_char, errors: *const c_char) -> c_int;
    pub fn Py_SetProgramName(arg1: *const wchar_t) -> ();
    pub fn Py_GetProgramName() -> *mut wchar_t;
    pub fn Py_SetPythonHome(arg1: *const wchar_t) -> ();
    pub fn Py_GetPythonHome() -> *mut wchar_t;
    pub fn Py_Initialize() -> ();
    pub fn Py_InitializeEx(arg1: c_int) -> ();
    pub fn Py_Finalize() -> ();
    pub fn Py_IsInitialized() -> c_int;
    pub fn Py_NewInterpreter() -> *mut PyThreadState;
    pub fn Py_EndInterpreter(arg1: *mut PyThreadState) -> ();
}

// Note: PyCompilerFlags was moved to compile.h in Python 3.7;
// We still have our version in pythonrun.rs
#[repr(C)]
#[derive(Copy, Clone)]
#[cfg(not(Py_LIMITED_API))]
pub struct PyCompilerFlags {
    cf_flags : c_int
}

#[cfg(not(Py_LIMITED_API))]
pub enum _mod {}

#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    pub fn PyRun_SimpleStringFlags(arg1: *const c_char,
                                   arg2: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_AnyFileFlags(arg1: *mut FILE, arg2: *const c_char,
                              arg3: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_AnyFileExFlags(fp: *mut FILE,
                                filename: *const c_char,
                                closeit: c_int,
                                flags: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_SimpleFileExFlags(fp: *mut FILE,
                                   filename: *const c_char,
                                   closeit: c_int,
                                   flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveOneFlags(fp: *mut FILE,
                                     filename: *const c_char,
                                     flags: *mut PyCompilerFlags)
     -> c_int;
    #[cfg(Py_3_4)]
    pub fn PyRun_InteractiveOneObject(fp: *mut FILE, filename: *mut PyObject,
                                      flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveLoopFlags(fp: *mut FILE,
                                      filename: *const c_char,
                                      flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyParser_ASTFromString(s: *const c_char,
                                  filename: *const c_char,
                                  start: c_int,
                                  flags: *mut PyCompilerFlags,
                                  arena: *mut PyArena) -> *mut _mod;
    #[cfg(Py_3_4)]
    pub fn PyParser_ASTFromStringObject(s: *const c_char,
                                        filename: *mut PyObject,
                                        start: c_int,
                                        flags: *mut PyCompilerFlags,
                                        arena: *mut PyArena)
     -> *mut _mod;
    pub fn PyParser_ASTFromFile(fp: *mut FILE,
                                filename: *const c_char,
                                enc: *const c_char,
                                start: c_int,
                                ps1: *const c_char,
                                ps2: *const c_char,
                                flags: *mut PyCompilerFlags,
                                errcode: *mut c_int,
                                arena: *mut PyArena) -> *mut _mod;
    #[cfg(Py_3_4)]
    pub fn PyParser_ASTFromFileObject(fp: *mut FILE, filename: *mut PyObject,
                                      enc: *const c_char,
                                      start: c_int,
                                      ps1: *const c_char,
                                      ps2: *const c_char,
                                      flags: *mut PyCompilerFlags,
                                      errcode: *mut c_int,
                                      arena: *mut PyArena)
     -> *mut _mod;
}

pub enum symtable {}
pub enum _node {}

#[inline]
pub unsafe fn PyParser_SimpleParseString(s: *const c_char, b: c_int) -> *mut _node {
    PyParser_SimpleParseStringFlags(s, b, 0)
}

#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn PyParser_SimpleParseFile(fp: *mut FILE, s: *const c_char, b: c_int) -> *mut _node {
    PyParser_SimpleParseFileFlags(fp, s, b, 0)
}

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    pub fn PyParser_SimpleParseStringFlags(arg1: *const c_char,
                                           arg2: c_int,
                                           arg3: c_int)
     -> *mut _node;
    pub fn PyParser_SimpleParseStringFlagsFilename(arg1:
                                                       *const c_char,
                                                   arg2:
                                                       *const c_char,
                                                   arg3: c_int,
                                                   arg4: c_int)
     -> *mut _node;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyParser_SimpleParseFileFlags(arg1: *mut FILE,
                                         arg2: *const c_char,
                                         arg3: c_int,
                                         arg4: c_int)
     -> *mut _node;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyRun_StringFlags(arg1: *const c_char, arg2: c_int,
                             arg3: *mut PyObject, arg4: *mut PyObject,
                             arg5: *mut PyCompilerFlags) -> *mut PyObject;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyRun_FileExFlags(fp: *mut FILE, filename: *const c_char,
                             start: c_int, globals: *mut PyObject,
                             locals: *mut PyObject, closeit: c_int,
                             flags: *mut PyCompilerFlags) -> *mut PyObject;
    #[cfg(Py_LIMITED_API)]
    pub fn Py_CompileString(string: *const c_char,
                            p: *const c_char, s: c_int)
     -> *mut PyObject;
}
#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn Py_CompileString(string: *const c_char, p: *const c_char, s: c_int) -> *mut PyObject {
    Py_CompileStringExFlags(string, p, s, ptr::null_mut(), -1)
}
#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn Py_CompileStringFlags(string: *const c_char, p: *const c_char, s: c_int, f: *mut PyCompilerFlags) -> *mut PyObject {
    Py_CompileStringExFlags(string, p, s, f, -1)
}
#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    #[cfg(not(Py_LIMITED_API))]
    pub fn Py_CompileStringExFlags(str: *const c_char,
                                   filename: *const c_char,
                                   start: c_int,
                                   flags: *mut PyCompilerFlags,
                                   optimize: c_int) -> *mut PyObject;
    #[cfg(not(Py_LIMITED_API))]
    #[cfg(Py_3_4)]
    pub fn Py_CompileStringObject(str: *const c_char,
                                  filename: *mut PyObject,
                                  start: c_int,
                                  flags: *mut PyCompilerFlags,
                                  optimize: c_int) -> *mut PyObject;
    pub fn Py_SymtableString(str: *const c_char,
                             filename: *const c_char,
                             start: c_int) -> *mut symtable;
    #[cfg(not(Py_LIMITED_API))]
    #[cfg(Py_3_4)]
    pub fn Py_SymtableStringObject(str: *const c_char,
                                   filename: *mut PyObject,
                                   start: c_int)
     -> *mut symtable;

    pub fn PyErr_Print() -> ();
    pub fn PyErr_PrintEx(arg1: c_int) -> ();
    pub fn PyErr_Display(arg1: *mut PyObject, arg2: *mut PyObject,
                         arg3: *mut PyObject) -> ();

    // TODO: these moved to pylifecycle.h
    pub fn Py_AtExit(func: Option<extern "C" fn() -> ()>)
     -> c_int;
    pub fn Py_Exit(arg1: c_int) -> ();
    pub fn Py_Main(argc: c_int, argv: *mut *mut wchar_t)
     -> c_int;
    pub fn Py_GetProgramFullPath() -> *mut wchar_t;
    pub fn Py_GetPrefix() -> *mut wchar_t;
    pub fn Py_GetExecPrefix() -> *mut wchar_t;
    pub fn Py_GetPath() -> *mut wchar_t;
    pub fn Py_SetPath(arg1: *const wchar_t) -> ();
    pub fn Py_GetVersion() -> *const c_char;
    pub fn Py_GetPlatform() -> *const c_char;
    pub fn Py_GetCopyright() -> *const c_char;
    pub fn Py_GetCompiler() -> *const c_char;
    pub fn Py_GetBuildInfo() -> *const c_char;
}

<commit_msg>Expose Py_FinalizeEx()<commit_after>use libc::{c_char, c_int, wchar_t, FILE};
use core::ptr;
use object::*;
use pystate::PyThreadState;
#[cfg(not(Py_LIMITED_API))]
use pyarena::PyArena;

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" { // TODO: these moved to pylifecycle.h
    #[cfg(Py_3_4)]
    pub fn Py_SetStandardStreamEncoding(encoding: *const c_char, errors: *const c_char) -> c_int;
    pub fn Py_SetProgramName(arg1: *const wchar_t) -> ();
    pub fn Py_GetProgramName() -> *mut wchar_t;
    pub fn Py_SetPythonHome(arg1: *const wchar_t) -> ();
    pub fn Py_GetPythonHome() -> *mut wchar_t;
    pub fn Py_Initialize() -> ();
    pub fn Py_InitializeEx(arg1: c_int) -> ();
    pub fn Py_Finalize() -> ();
    #[cfg(Py_3_6)]
    pub fn Py_FinalizeEx() -> c_int;
    pub fn Py_IsInitialized() -> c_int;
    pub fn Py_NewInterpreter() -> *mut PyThreadState;
    pub fn Py_EndInterpreter(arg1: *mut PyThreadState) -> ();
}

// Note: PyCompilerFlags was moved to compile.h in Python 3.7;
// We still have our version in pythonrun.rs
#[repr(C)]
#[derive(Copy, Clone)]
#[cfg(not(Py_LIMITED_API))]
pub struct PyCompilerFlags {
    cf_flags : c_int
}

#[cfg(not(Py_LIMITED_API))]
pub enum _mod {}

#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    pub fn PyRun_SimpleStringFlags(arg1: *const c_char,
                                   arg2: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_AnyFileFlags(arg1: *mut FILE, arg2: *const c_char,
                              arg3: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_AnyFileExFlags(fp: *mut FILE,
                                filename: *const c_char,
                                closeit: c_int,
                                flags: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_SimpleFileExFlags(fp: *mut FILE,
                                   filename: *const c_char,
                                   closeit: c_int,
                                   flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveOneFlags(fp: *mut FILE,
                                     filename: *const c_char,
                                     flags: *mut PyCompilerFlags)
     -> c_int;
    #[cfg(Py_3_4)]
    pub fn PyRun_InteractiveOneObject(fp: *mut FILE, filename: *mut PyObject,
                                      flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveLoopFlags(fp: *mut FILE,
                                      filename: *const c_char,
                                      flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyParser_ASTFromString(s: *const c_char,
                                  filename: *const c_char,
                                  start: c_int,
                                  flags: *mut PyCompilerFlags,
                                  arena: *mut PyArena) -> *mut _mod;
    #[cfg(Py_3_4)]
    pub fn PyParser_ASTFromStringObject(s: *const c_char,
                                        filename: *mut PyObject,
                                        start: c_int,
                                        flags: *mut PyCompilerFlags,
                                        arena: *mut PyArena)
     -> *mut _mod;
    pub fn PyParser_ASTFromFile(fp: *mut FILE,
                                filename: *const c_char,
                                enc: *const c_char,
                                start: c_int,
                                ps1: *const c_char,
                                ps2: *const c_char,
                                flags: *mut PyCompilerFlags,
                                errcode: *mut c_int,
                                arena: *mut PyArena) -> *mut _mod;
    #[cfg(Py_3_4)]
    pub fn PyParser_ASTFromFileObject(fp: *mut FILE, filename: *mut PyObject,
                                      enc: *const c_char,
                                      start: c_int,
                                      ps1: *const c_char,
                                      ps2: *const c_char,
                                      flags: *mut PyCompilerFlags,
                                      errcode: *mut c_int,
                                      arena: *mut PyArena)
     -> *mut _mod;
}

pub enum symtable {}
pub enum _node {}

#[inline]
pub unsafe fn PyParser_SimpleParseString(s: *const c_char, b: c_int) -> *mut _node {
    PyParser_SimpleParseStringFlags(s, b, 0)
}

#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn PyParser_SimpleParseFile(fp: *mut FILE, s: *const c_char, b: c_int) -> *mut _node {
    PyParser_SimpleParseFileFlags(fp, s, b, 0)
}

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    pub fn PyParser_SimpleParseStringFlags(arg1: *const c_char,
                                           arg2: c_int,
                                           arg3: c_int)
     -> *mut _node;
    pub fn PyParser_SimpleParseStringFlagsFilename(arg1:
                                                       *const c_char,
                                                   arg2:
                                                       *const c_char,
                                                   arg3: c_int,
                                                   arg4: c_int)
     -> *mut _node;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyParser_SimpleParseFileFlags(arg1: *mut FILE,
                                         arg2: *const c_char,
                                         arg3: c_int,
                                         arg4: c_int)
     -> *mut _node;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyRun_StringFlags(arg1: *const c_char, arg2: c_int,
                             arg3: *mut PyObject, arg4: *mut PyObject,
                             arg5: *mut PyCompilerFlags) -> *mut PyObject;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyRun_FileExFlags(fp: *mut FILE, filename: *const c_char,
                             start: c_int, globals: *mut PyObject,
                             locals: *mut PyObject, closeit: c_int,
                             flags: *mut PyCompilerFlags) -> *mut PyObject;
    #[cfg(Py_LIMITED_API)]
    pub fn Py_CompileString(string: *const c_char,
                            p: *const c_char, s: c_int)
     -> *mut PyObject;
}
#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn Py_CompileString(string: *const c_char, p: *const c_char, s: c_int) -> *mut PyObject {
    Py_CompileStringExFlags(string, p, s, ptr::null_mut(), -1)
}
#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn Py_CompileStringFlags(string: *const c_char, p: *const c_char, s: c_int, f: *mut PyCompilerFlags) -> *mut PyObject {
    Py_CompileStringExFlags(string, p, s, f, -1)
}
#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    #[cfg(not(Py_LIMITED_API))]
    pub fn Py_CompileStringExFlags(str: *const c_char,
                                   filename: *const c_char,
                                   start: c_int,
                                   flags: *mut PyCompilerFlags,
                                   optimize: c_int) -> *mut PyObject;
    #[cfg(not(Py_LIMITED_API))]
    #[cfg(Py_3_4)]
    pub fn Py_CompileStringObject(str: *const c_char,
                                  filename: *mut PyObject,
                                  start: c_int,
                                  flags: *mut PyCompilerFlags,
                                  optimize: c_int) -> *mut PyObject;
    pub fn Py_SymtableString(str: *const c_char,
                             filename: *const c_char,
                             start: c_int) -> *mut symtable;
    #[cfg(not(Py_LIMITED_API))]
    #[cfg(Py_3_4)]
    pub fn Py_SymtableStringObject(str: *const c_char,
                                   filename: *mut PyObject,
                                   start: c_int)
     -> *mut symtable;

    pub fn PyErr_Print() -> ();
    pub fn PyErr_PrintEx(arg1: c_int) -> ();
    pub fn PyErr_Display(arg1: *mut PyObject, arg2: *mut PyObject,
                         arg3: *mut PyObject) -> ();

    // TODO: these moved to pylifecycle.h
    pub fn Py_AtExit(func: Option<extern "C" fn() -> ()>)
     -> c_int;
    pub fn Py_Exit(arg1: c_int) -> ();
    pub fn Py_Main(argc: c_int, argv: *mut *mut wchar_t)
     -> c_int;
    pub fn Py_GetProgramFullPath() -> *mut wchar_t;
    pub fn Py_GetPrefix() -> *mut wchar_t;
    pub fn Py_GetExecPrefix() -> *mut wchar_t;
    pub fn Py_GetPath() -> *mut wchar_t;
    pub fn Py_SetPath(arg1: *const wchar_t) -> ();
    pub fn Py_GetVersion() -> *const c_char;
    pub fn Py_GetPlatform() -> *const c_char;
    pub fn Py_GetCopyright() -> *const c_char;
    pub fn Py_GetCompiler() -> *const c_char;
    pub fn Py_GetBuildInfo() -> *const c_char;
}

<|endoftext|>


<commit_before>#[feature(macro_rules)];
use std::{cast};

// emulating C++ classes using Traits as vtables, could the safety be improved?

pub trait Foo {
	fn foo(&self,i:int);
}

pub struct CppClass<RawDataStruct,TraitInterface> {
	priv vtable_ptr: *(),	// you must not change this :(
							// it is a ptr to the vtable
	dat:RawDataStruct
}

impl<Struct,Trait> Deref<Struct> for  CppClass<Struct,Trait> {
	fn deref<'a> (&'a self)->&'a Struct { &self.dat }
}
impl<Struct,Trait> DerefMut<Struct> for  CppClass<Struct,Trait> {
	fn deref_mut<'a> (&'a mut self)->&'a mut Struct { &mut self.dat }
}
/*
// TODO - we can't get this to work.
impl<Struct,T> Deref<T> for  CppClass<Struct,&'static T> {
	fn deref<'a> (&'a self)->&'a T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a T>( (self.vtable_ptr, &self.dat) )}
	}
}
impl<Struct,T> DerefMut<T> for  CppClass<Struct,&'static T> {
	fn deref_mut<'a> (&'a mut self)->&'a mut T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a mut T>( (self.vtable_ptr, &mut self.dat) )}
	}
}
*/
//impl<Struct,Trait> DerefMut<Trait> for  CppClass<Struct,Trait> {
//	fn deref_mut<'a> (&'a mut self)->&'a mut Struct { &mut self.data }
//}

impl<Struct,Trait>  CppClass<Struct,Trait> {
	pub fn as_trait<'a>(&'a self)->Trait  {
	    unsafe {
			cast::transmute::<_,Trait>( (self.vtable_ptr, &self.dat) )
		}
	}
	pub fn data<'a>(&'a self)->&'a Struct { &'a self.dat }
	pub fn data_mut<'a>(&'a mut self)->&'a mut Struct { &'a mut self.dat }
}

macro_rules! new_class {

	($tname:ty for $sname:ident { $($field:ident : $val:expr),* })=>{
		// todo: we can't make initializer list work for arbitrary type,
		// so add another rule to accept a constructor function for non ident type.
		CppClass::<$sname,& $tname> {
			vtable_ptr:unsafe {
				let null_obj=cast::transmute::<_,&'static $sname>(0);
				let (vt,_):(*u8,*u8)=
					cast::transmute(null_obj as &'static $tname);
				cast::transmute(vt)
			},

			dat: $sname { $($field: $val),* }
		}
	}
}

struct Banana { x:int }
impl Foo for Banana {
	fn foo(&self,i:int) {
		println!("hello from banana.foo {:?} {:?} {:?}",i, self.x, i+self.x);
	}
}

fn main() {
	let mut b :CppClass<Banana,&Foo> = new_class!( Foo for Banana  {x:10} );
	b.dat.x=10;
	// can you write to 'vtable_ptr' unsafely?

	b.as_trait().foo(3);

}

<commit_msg>added data accessors, but couldn't get deref to return trait automatically<commit_after>#[feature(macro_rules)];
use std::{cast};

// emulating C++ classes using Traits as vtables, could the safety be improved?

pub trait Foo {
	fn foo(&self,i:int);
}

pub struct CppClass<RawDataStruct,TraitInterface> {
	priv vtable_ptr: *(),	// you must not change this :(
							// it is a ptr to the vtable
	dat:RawDataStruct
}

impl<Struct,Trait> Deref<Struct> for  CppClass<Struct,Trait> {
	fn deref<'a> (&'a self)->&'a Struct { &self.dat }
}
impl<Struct,Trait> DerefMut<Struct> for  CppClass<Struct,Trait> {
	fn deref_mut<'a> (&'a mut self)->&'a mut Struct { &mut self.dat }
}
/*
// TODO - we can't get this to work.
impl<Struct,T> Deref<T> for  CppClass<Struct,&'static T> {
	fn deref<'a> (&'a self)->&'a T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a T>( (self.vtable_ptr, &self.dat) )}
	}
}
impl<Struct,T> DerefMut<T> for  CppClass<Struct,&'static T> {
	fn deref_mut<'a> (&'a mut self)->&'a mut T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a mut T>( (self.vtable_ptr, &mut self.dat) )}
	}
}
*/

impl<Struct,Trait>  CppClass<Struct,Trait> {
	pub fn as_trait<'a>(&'a self)->Trait  {
	    unsafe {
			cast::transmute::<_,Trait>( (self.vtable_ptr, &self.dat) )
		}
	}
	pub fn data<'a>(&'a self)->&'a Struct { &'a self.dat }
	pub fn data_mut<'a>(&'a mut self)->&'a mut Struct { &'a mut self.dat }
}

macro_rules! new_class {

	($tname:ty for $sname:ident { $($field:ident : $val:expr),* })=>{
		// todo: we can't make initializer list work for arbitrary type,
		// so add another rule to accept a constructor function for non ident type.
		CppClass::<$sname,& $tname> {
			vtable_ptr:unsafe {
				let null_obj=cast::transmute::<_,&'static $sname>(0);
				let (vt,_):(*u8,*u8)=
					cast::transmute(null_obj as &'static $tname);
				cast::transmute(vt)
			},

			dat: $sname { $($field: $val),* }
		}
	}
}

struct Banana { x:int }
impl Foo for Banana {
	fn foo(&self,i:int) {
		println!("hello from banana.foo {:?} {:?} {:?}",i, self.x, i+self.x);
	}
}

fn main() {
	let mut b :CppClass<Banana,&Foo> = new_class!( Foo for Banana  {x:10} );
	b.dat.x=10;
	// can you write to 'vtable_ptr' unsafely?

	b.as_trait().foo(3);

}

<|endoftext|>


<commit_before>//! Kata OS process management support

extern crate alloc;
use alloc::boxed::Box;
use alloc::string::String;
use core::convert::TryFrom;
use core::marker::Sync;
use hashbrown::HashMap;
use kata_proc_common::{Bundle, DEFAULT_BUNDLE_ID_CAPACITY};
use log::trace;
use smallstr::SmallString;

use kata_proc_common as proc;
use proc::*;

pub type BundleId = SmallString<[u8; DEFAULT_BUNDLE_ID_CAPACITY]>;

// Bundle capacity before spillover to the heap.
pub const DEFAULT_BUNDLES_CAPACITY: usize = 10;

// Bundle state tracks start/stop operations.
#[derive(Debug, Eq, PartialEq)]
enum BundleState {
    Stopped,
    Running,
}

// We track the Bundle & ProcessControlInterface state.
struct BundleData {
    state: BundleState,
    bundle: Box<Bundle>,
    // TODO(sleffler): seL4 capability (minted from bundle.app_token)?
    // TODO(sleffler): seL4 capability for bundle.app_memory_address?
}

impl BundleData {
    fn new(bundle: &Bundle) -> Self {
        BundleData {
            state: BundleState::Stopped,
            bundle: Box::new(bundle.clone()),
        }
    }
}

// The ProcessManager presents the PackageManagementInterface (for loading
// applications from storage) and the ProcessControlInterface (for starting
// and stopping associated applications). The interface to the underlying
// system(s) are abstracted through the ProcessManagerInterface. One instance
// of the ProcessManager is created at start and accessed through SeL4 RPC's
// (from other components).
pub struct ProcessManager {
    manager: Box<dyn ProcessManagerInterface + Sync>,
    bundles: HashMap<BundleId, BundleData>,
}

impl ProcessManager {
    // Creates a new ProcessManager instance.
    pub fn new(manager: impl ProcessManagerInterface + Sync + 'static) -> ProcessManager {
        ProcessManager {
            manager: Box::new(manager),
            bundles: HashMap::with_capacity(DEFAULT_BUNDLES_CAPACITY),
        }
    }

    pub fn capacity(&self) -> usize {
        self.bundles.capacity()
    }
}

impl PackageManagementInterface for ProcessManager {
    // NB: doc says a bundle may have multiple apps; support one for now
    //   (assume a fixed pathname to the app is used)
    fn install(
        &mut self,
        pkg_buffer: *const u8,
        pkg_buffer_len: usize,
    ) -> Result<String, ProcessManagerError> {
        let pkg_buffer_size = match u32::try_from(pkg_buffer_len) {
            Ok(v) => v,
            Err(_) => return Err(ProcessManagerError::PackageBufferLenInvalid),
        };

        // We assume the seL4 capability for the memory associated with
        // pkg_buffer has been setup for us so we can pass it along (as needed)
        // to the Security Core.
        //
        // NB: defer to StorageManager for handling an install of a previously
        // installed app. We do not have the app_id to check locally so if the
        // StorageManager disallows re-install then we'll return it's error;
        // otherwise we update the returned Bundle state.
        // TODO(sleffler): owner's public key?
        let bundle_id = self.manager.install(pkg_buffer, pkg_buffer_size)?;
        trace!(
            "install pkg {:p}:{} => bundle_id:{}",
            pkg_buffer,
            pkg_buffer_size,
            bundle_id
        );

        let mut bundle = Bundle::new();
        bundle.app_id = bundle_id;
        assert!(self
            .bundles
            .insert(BundleId::from_str(&bundle.app_id), BundleData::new(&bundle))
            .is_none());

        Ok(bundle.app_id)
    }

    fn uninstall(&mut self, bundle_id: &str) -> Result<(), ProcessManagerError> {
        trace!("uninstall bundle_id:{}", bundle_id);
        let bid = BundleId::from_str(bundle_id);
        match self.bundles.get(&bid) {
            Some(bundle) => {
                trace!(
                    "uninstall bundle_id:{}: state {:?}",
                    bundle_id,
                    bundle.state
                );
                if bundle.state == BundleState::Running {
                    return Err(ProcessManagerError::BundleRunning);
                }
                let _ = self.bundles.remove(&bid);
            }
            None => {}
        }
        // NB: the hashmap is ephemeral so always call through to the manager
        self.manager.uninstall(bundle_id)
    }
}

impl ProcessControlInterface for ProcessManager {
    fn start(&mut self, bundle_id: &str) -> Result<(), ProcessManagerError> {
        let bid = BundleId::from_str(bundle_id);
        match self.bundles.get_mut(&bid) {
            Some(bundle) => {
                trace!("start bundle_id:{}: state {:?}", bundle_id, bundle.state);
                if bundle.state == BundleState::Stopped {
                    self.manager.start(&bundle.bundle)?;
                }
                bundle.state = BundleState::Running;
                Ok(())
            }
            None => {
                // We depend on the hashmap contents since we need the Bundle
                // to setup/start the application. To that end we pre-populate
                // the hashmap at start by querying the StorageManager for
                // previously installed applications.
                trace!("start bundle_id:{}: not found", bundle_id);
                Err(ProcessManagerError::BundleNotFound)
            }
        }
    }

    fn stop(&mut self, bundle_id: &str) -> Result<(), ProcessManagerError> {
        let bid = BundleId::from_str(bundle_id);
        match self.bundles.get_mut(&bid) {
            Some(bundle) => {
                trace!("stop bundle_id:{}: state {:?}", bundle_id, bundle.state);
                if bundle.state == BundleState::Running {
                    self.manager.stop(&bundle.bundle)?;
                }
                bundle.state = BundleState::Stopped;
                Ok(())
            }
            None => {
                trace!("stop bundle_id:{}: not found", bundle_id);
                Err(ProcessManagerError::BundleNotFound)
            }
        }
    }

    fn get_running_bundles(&self) -> Result<BundleIdArray, ProcessManagerError> {
        trace!("get_running_bundles");
        let mut result = BundleIdArray::new();
        for (bundle_id, _bundle) in self
            .bundles
            .iter()
            .filter(|(_, bundle)| matches!(bundle.state, BundleState::Running))
        {
            result.push(String::from(bundle_id.as_str()));
        }
        Ok(result)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use proc::ProcessManagerError as pme;

    // NB: just enough state to track install'd bundles
    struct FakeManager {
        bundles: HashMap<String, u32>, // pkg_buffer:pkg_buffer_size
    }
    impl FakeManager {
        pub fn new() -> Self {
            FakeManager {
                bundles: HashMap::new(),
            }
        }
    }
    impl ProcessManagerInterface for FakeManager {
        fn install(&mut self, pkg_buffer: *const u8, pkg_buffer_size: u32) -> Result<Bundle, pme> {
            let str = (pkg_buffer as usize).to_string();
            if self.bundles.contains_key(&str) {
                return Err(ProcessManagerError::BundleFound);
            }
            assert!(self.bundles.insert(str, pkg_buffer_size).is_none());
            Ok(Bundle {
                app_id: (pkg_buffer as usize).to_string(),
                data: [0u8; 64],
            })
        }
        fn uninstall(&mut self, bundle_id: &str) -> Result<(), pme> {
            match self.bundles.remove(bundle_id) {
                Some(_) => Ok(()),
                None => Err(ProcessManagerError::BundleNotFound),
            }
        }
        fn start(&mut self, bundle: &Bundle) -> Result<(), pme> {
            assert!(self.bundles.contains_key(&bundle.app_id));
            Ok(())
        }
        fn stop(&mut self, bundle: &Bundle) -> Result<(), pme> {
            assert!(self.bundles.contains_key(&bundle.app_id));
            Ok(())
        }
    }

    #[test]
    fn test_bundle_id_basics() {
        let bundle_id = BundleId::new();
        assert_eq!(bundle_id.len(), 0);
        assert_eq!(bundle_id.inline_size(), DEFAULT_BUNDLE_ID_CAPACITY);

        // Check str conversion.
        assert_eq!(BundleId::from_str("hello").as_str(), "hello");
    }

    #[test]
    fn test_pkg_mgmt() {
        let fake = tests::FakeManager::new();
        let mut mgr = ProcessManager::new(fake);

        // Not installed, should fail.
        assert_eq!(mgr.uninstall("foo").err(), Some(pme::BundleNotFound));

        // Install the bundle.
        let pkg_buffer = [0u8; 1024];
        let result = mgr.install(pkg_buffer.as_ptr(), pkg_buffer.len());
        assert!(result.is_ok());
        let bundle_id = result.unwrap();

        // Re-install the same bundle should fail.
        assert_eq!(
            mgr.install(pkg_buffer.as_ptr(), pkg_buffer.len()).err(),
            Some(pme::BundleFound)
        );

        // Verify you cannot uninstall a running bundle.
        assert!(mgr.start(&bundle_id).is_ok());
        assert_eq!(mgr.uninstall(&bundle_id).err(), Some(pme::BundleRunning));
        assert!(mgr.stop(&bundle_id).is_ok());

        // Now uninstalling the bundle should work.
        assert!(mgr.uninstall(&bundle_id).is_ok());
    }

    #[test]
    fn test_spill() {
        let fake = tests::FakeManager::new();
        let mut mgr = ProcessManager::new(fake);
        let pkg_buffer = [0u8; 1024];

        for i in 0..=mgr.capacity() {
            let slice = &pkg_buffer[i..];
            assert!(mgr.install(slice.as_ptr(), slice.len()).is_ok());
        }
    }

    #[test]
    fn test_proc_ctrl() {
        let fake = tests::FakeManager::new();
        let mut mgr = ProcessManager::new(fake);

        fn is_running(running: &BundleIdArray, id: &str) -> bool {
            running.as_slice().iter().find(|&x| *x == id).is_some()
        }

        let pkg_buffer2 = [0u8; 1024];
        let result2 = mgr.install(pkg_buffer2.as_ptr(), pkg_buffer2.len());
        assert!(result2.is_ok());
        let bid2 = result2.unwrap();

        let pkg_buffer9 = [0u8; 1024];
        let result9 = mgr.install(pkg_buffer9.as_ptr(), pkg_buffer9.len());
        assert!(result9.is_ok());
        let bid9 = result9.unwrap();

        assert!(mgr.stop(&bid2).is_ok());
        assert!(mgr.start(&bid2).is_ok());
        assert!(mgr.start(&bid9).is_ok());

        let running = mgr.get_running_bundles().unwrap();
        assert_eq!(running.len(), 2);
        assert!(is_running(&running, &bid2));
        assert!(is_running(&running, &bid9));

        assert!(mgr.stop(&bid2).is_ok());
        // After stopping the bundle we should see nothing running.
        let running = mgr.get_running_bundles().unwrap();
        assert_eq!(running.len(), 1);
        assert!(is_running(&running, &bid9));

        assert!(mgr.stop(&bid9).is_ok());
        // After stopping the bundle we should see nothing running.
        let running = mgr.get_running_bundles().unwrap();
        assert_eq!(running.len(), 0);
    }
}
<commit_msg>kata-proc-manager: fix unit tests<commit_after>//! Kata OS process management support

extern crate alloc;
use alloc::boxed::Box;
use alloc::string::String;
use core::convert::TryFrom;
use core::marker::Sync;
use hashbrown::HashMap;
use kata_proc_common::{Bundle, DEFAULT_BUNDLE_ID_CAPACITY};
use log::trace;
use smallstr::SmallString;

use kata_proc_common as proc;
use proc::*;

pub type BundleId = SmallString<[u8; DEFAULT_BUNDLE_ID_CAPACITY]>;

// Bundle capacity before spillover to the heap.
pub const DEFAULT_BUNDLES_CAPACITY: usize = 10;

// Bundle state tracks start/stop operations.
#[derive(Debug, Eq, PartialEq)]
enum BundleState {
    Stopped,
    Running,
}

// We track the Bundle & ProcessControlInterface state.
struct BundleData {
    state: BundleState,
    bundle: Box<Bundle>,
    // TODO(sleffler): seL4 capability (minted from bundle.app_token)?
    // TODO(sleffler): seL4 capability for bundle.app_memory_address?
}

impl BundleData {
    fn new(bundle: &Bundle) -> Self {
        BundleData {
            state: BundleState::Stopped,
            bundle: Box::new(bundle.clone()),
        }
    }
}

// The ProcessManager presents the PackageManagementInterface (for loading
// applications from storage) and the ProcessControlInterface (for starting
// and stopping associated applications). The interface to the underlying
// system(s) are abstracted through the ProcessManagerInterface. One instance
// of the ProcessManager is created at start and accessed through SeL4 RPC's
// (from other components).
pub struct ProcessManager {
    manager: Box<dyn ProcessManagerInterface + Sync>,
    bundles: HashMap<BundleId, BundleData>,
}

impl ProcessManager {
    // Creates a new ProcessManager instance.
    pub fn new(manager: impl ProcessManagerInterface + Sync + 'static) -> ProcessManager {
        ProcessManager {
            manager: Box::new(manager),
            bundles: HashMap::with_capacity(DEFAULT_BUNDLES_CAPACITY),
        }
    }

    pub fn capacity(&self) -> usize {
        self.bundles.capacity()
    }
}

impl PackageManagementInterface for ProcessManager {
    // NB: doc says a bundle may have multiple apps; support one for now
    //   (assume a fixed pathname to the app is used)
    fn install(
        &mut self,
        pkg_buffer: *const u8,
        pkg_buffer_len: usize,
    ) -> Result<String, ProcessManagerError> {
        let pkg_buffer_size = match u32::try_from(pkg_buffer_len) {
            Ok(v) => v,
            Err(_) => return Err(ProcessManagerError::PackageBufferLenInvalid),
        };

        // We assume the seL4 capability for the memory associated with
        // pkg_buffer has been setup for us so we can pass it along (as needed)
        // to the Security Core.
        //
        // NB: defer to StorageManager for handling an install of a previously
        // installed app. We do not have the app_id to check locally so if the
        // StorageManager disallows re-install then we'll return it's error;
        // otherwise we update the returned Bundle state.
        // TODO(sleffler): owner's public key?
        let bundle_id = self.manager.install(pkg_buffer, pkg_buffer_size)?;
        trace!(
            "install pkg {:p}:{} => bundle_id:{}",
            pkg_buffer,
            pkg_buffer_size,
            bundle_id
        );

        let mut bundle = Bundle::new();
        bundle.app_id = bundle_id;
        assert!(self
            .bundles
            .insert(BundleId::from_str(&bundle.app_id), BundleData::new(&bundle))
            .is_none());

        Ok(bundle.app_id)
    }

    fn uninstall(&mut self, bundle_id: &str) -> Result<(), ProcessManagerError> {
        trace!("uninstall bundle_id:{}", bundle_id);
        let bid = BundleId::from_str(bundle_id);
        match self.bundles.get(&bid) {
            Some(bundle) => {
                trace!(
                    "uninstall bundle_id:{}: state {:?}",
                    bundle_id,
                    bundle.state
                );
                if bundle.state == BundleState::Running {
                    return Err(ProcessManagerError::BundleRunning);
                }
                let _ = self.bundles.remove(&bid);
            }
            None => {}
        }
        // NB: the hashmap is ephemeral so always call through to the manager
        self.manager.uninstall(bundle_id)
    }
}

impl ProcessControlInterface for ProcessManager {
    fn start(&mut self, bundle_id: &str) -> Result<(), ProcessManagerError> {
        let bid = BundleId::from_str(bundle_id);
        match self.bundles.get_mut(&bid) {
            Some(bundle) => {
                trace!("start bundle_id:{}: state {:?}", bundle_id, bundle.state);
                if bundle.state == BundleState::Stopped {
                    self.manager.start(&bundle.bundle)?;
                }
                bundle.state = BundleState::Running;
                Ok(())
            }
            None => {
                // We depend on the hashmap contents since we need the Bundle
                // to setup/start the application. To that end we pre-populate
                // the hashmap at start by querying the StorageManager for
                // previously installed applications.
                trace!("start bundle_id:{}: not found", bundle_id);
                Err(ProcessManagerError::BundleNotFound)
            }
        }
    }

    fn stop(&mut self, bundle_id: &str) -> Result<(), ProcessManagerError> {
        let bid = BundleId::from_str(bundle_id);
        match self.bundles.get_mut(&bid) {
            Some(bundle) => {
                trace!("stop bundle_id:{}: state {:?}", bundle_id, bundle.state);
                if bundle.state == BundleState::Running {
                    self.manager.stop(&bundle.bundle)?;
                }
                bundle.state = BundleState::Stopped;
                Ok(())
            }
            None => {
                trace!("stop bundle_id:{}: not found", bundle_id);
                Err(ProcessManagerError::BundleNotFound)
            }
        }
    }

    fn get_running_bundles(&self) -> Result<BundleIdArray, ProcessManagerError> {
        trace!("get_running_bundles");
        let mut result = BundleIdArray::new();
        for (bundle_id, _bundle) in self
            .bundles
            .iter()
            .filter(|(_, bundle)| matches!(bundle.state, BundleState::Running))
        {
            result.push(String::from(bundle_id.as_str()));
        }
        Ok(result)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use proc::ProcessManagerError as pme;

    // NB: just enough state to track install'd bundles
    struct FakeManager {
        bundles: HashMap<String, u32>, // pkg_buffer:pkg_buffer_size
    }
    impl FakeManager {
        pub fn new() -> Self {
            FakeManager {
                bundles: HashMap::new(),
            }
        }
    }
    impl ProcessManagerInterface for FakeManager {
        fn install(&mut self, pkg_buffer: *const u8, pkg_buffer_size: u32) -> Result<String, pme> {
            let str = (pkg_buffer as usize).to_string();
            if self.bundles.contains_key(&str) {
                return Err(ProcessManagerError::BundleFound);
            }
            assert!(self.bundles.insert(str, pkg_buffer_size).is_none());
            Ok((pkg_buffer as usize).to_string())
        }
        fn uninstall(&mut self, bundle_id: &str) -> Result<(), pme> {
            match self.bundles.remove(bundle_id) {
                Some(_) => Ok(()),
                None => Err(ProcessManagerError::BundleNotFound),
            }
        }
        fn start(&mut self, bundle: &Bundle) -> Result<(), pme> {
            assert!(self.bundles.contains_key(&bundle.app_id));
            Ok(())
        }
        fn stop(&mut self, bundle: &Bundle) -> Result<(), pme> {
            assert!(self.bundles.contains_key(&bundle.app_id));
            Ok(())
        }
    }

    #[test]
    fn test_bundle_id_basics() {
        let bundle_id = BundleId::new();
        assert_eq!(bundle_id.len(), 0);
        assert_eq!(bundle_id.inline_size(), DEFAULT_BUNDLE_ID_CAPACITY);

        // Check str conversion.
        assert_eq!(BundleId::from_str("hello").as_str(), "hello");
    }

    #[test]
    fn test_pkg_mgmt() {
        let fake = tests::FakeManager::new();
        let mut mgr = ProcessManager::new(fake);

        // Not installed, should fail.
        assert_eq!(mgr.uninstall("foo").err(), Some(pme::BundleNotFound));

        // Install the bundle.
        let pkg_buffer = [0u8; 1024];
        let result = mgr.install(pkg_buffer.as_ptr(), pkg_buffer.len());
        assert!(result.is_ok());
        let bundle_id = result.unwrap();

        // Re-install the same bundle should fail.
        assert_eq!(
            mgr.install(pkg_buffer.as_ptr(), pkg_buffer.len()).err(),
            Some(pme::BundleFound)
        );

        // Verify you cannot uninstall a running bundle.
        assert!(mgr.start(&bundle_id).is_ok());
        assert_eq!(mgr.uninstall(&bundle_id).err(), Some(pme::BundleRunning));
        assert!(mgr.stop(&bundle_id).is_ok());

        // Now uninstalling the bundle should work.
        assert!(mgr.uninstall(&bundle_id).is_ok());
    }

    #[test]
    fn test_spill() {
        let fake = tests::FakeManager::new();
        let mut mgr = ProcessManager::new(fake);
        let pkg_buffer = [0u8; 1024];

        for i in 0..=mgr.capacity() {
            let slice = &pkg_buffer[i..];
            assert!(mgr.install(slice.as_ptr(), slice.len()).is_ok());
        }
    }

    #[test]
    fn test_proc_ctrl() {
        let fake = tests::FakeManager::new();
        let mut mgr = ProcessManager::new(fake);

        fn is_running(running: &BundleIdArray, id: &str) -> bool {
            running.as_slice().iter().find(|&x| *x == id).is_some()
        }

        let pkg_buffer2 = [0u8; 1024];
        let result2 = mgr.install(pkg_buffer2.as_ptr(), pkg_buffer2.len());
        assert!(result2.is_ok());
        let bid2 = result2.unwrap();

        let pkg_buffer9 = [0u8; 1024];
        let result9 = mgr.install(pkg_buffer9.as_ptr(), pkg_buffer9.len());
        assert!(result9.is_ok());
        let bid9 = result9.unwrap();

        assert!(mgr.stop(&bid2).is_ok());
        assert!(mgr.start(&bid2).is_ok());
        assert!(mgr.start(&bid9).is_ok());

        let running = mgr.get_running_bundles().unwrap();
        assert_eq!(running.len(), 2);
        assert!(is_running(&running, &bid2));
        assert!(is_running(&running, &bid9));

        assert!(mgr.stop(&bid2).is_ok());
        // After stopping the bundle we should see nothing running.
        let running = mgr.get_running_bundles().unwrap();
        assert_eq!(running.len(), 1);
        assert!(is_running(&running, &bid9));

        assert!(mgr.stop(&bid9).is_ok());
        // After stopping the bundle we should see nothing running.
        let running = mgr.get_running_bundles().unwrap();
        assert_eq!(running.len(), 0);
    }
}
<|endoftext|>


<commit_before>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;
use conduit::Request;
use std::fmt;
use std::time::Instant;

#[allow(missing_debug_implementations)] // We can't
#[derive(Default)]
pub struct LogRequests {
    handler: Option<Box<dyn Handler>>,
}

impl AroundMiddleware for LogRequests {
    fn with_handler(&mut self, handler: Box<dyn Handler>) {
        self.handler = Some(handler);
    }
}

impl Handler for LogRequests {
    fn call(&self, req: &mut dyn Request) -> Result<Response, Box<dyn Error + Send>> {
        let request_start = Instant::now();
        let res = self.handler.as_ref().unwrap().call(req);
        let (level, response_code) = match res {
            Ok(ref r) => ("info", r.status.0),
            Err(_) => ("error", 500),
        };
        let response_time = request_start.elapsed();
        let response_time =
            response_time.as_secs() * 1000 + u64::from(response_time.subsec_nanos()) / 1_000_000;

        let metadata_length = req
            .extensions()
            .find::<u64>()
            .map_or(String::new(), |l| format!(" metadata_length={}", l));

        print!(
            "at={level} method={method} path=\"{path}\" \
             request_id={request_id} fwd=\"{ip}\" service={time_ms}ms \
             status={status} user_agent=\"{user_agent}\"\
             {metadata_length}",
            level = level,
            method = req.method(),
            path = FullPath(req),
            ip = request_header(req, "X-Real-Ip"),
            time_ms = response_time,
            user_agent = request_header(req, "User-Agent"),
            request_id = request_header(req, "X-Request-Id"),
            status = response_code,
            metadata_length = metadata_length,
        );

        if let Err(ref e) = res {
            print!(" error=\"{}\"", e.to_string());
        }

        if response_time > 1000 {
            print!(" SLOW REQUEST");
        }

        println!();

        res
    }
}

struct FullPath<'a>(&'a dyn Request);

impl<'a> fmt::Display for FullPath<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0.path())?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}
<commit_msg>Auto merge of #2064 - jtgeibel:prod/interlaced-logs, r=carols10cents<commit_after>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;
use conduit::Request;
use std::fmt;
use std::time::Instant;

#[allow(missing_debug_implementations)] // We can't
#[derive(Default)]
pub struct LogRequests {
    handler: Option<Box<dyn Handler>>,
}

impl AroundMiddleware for LogRequests {
    fn with_handler(&mut self, handler: Box<dyn Handler>) {
        self.handler = Some(handler);
    }
}

impl Handler for LogRequests {
    fn call(&self, req: &mut dyn Request) -> Result<Response, Box<dyn Error + Send>> {
        let request_start = Instant::now();
        let res = self.handler.as_ref().unwrap().call(req);
        let (level, response_code) = match res {
            Ok(ref r) => ("info", r.status.0),
            Err(_) => ("error", 500),
        };
        let response_time = request_start.elapsed();
        let response_time =
            response_time.as_secs() * 1000 + u64::from(response_time.subsec_nanos()) / 1_000_000;

        let metadata_length = req
            .extensions()
            .find::<u64>()
            .map_or(String::new(), |l| format!(" metadata_length={}", l));

        let slow_request = if response_time > 1000 {
            " SLOW REQUEST"
        } else {
            ""
        };

        let error = if let Err(ref e) = res {
            format!(" error=\"{}\"", e)
        } else {
            String::new()
        };

        println!(
            "at={level} method={method} path=\"{path}\" \
             request_id={request_id} fwd=\"{ip}\" service={time_ms}ms \
             status={status} user_agent=\"{user_agent}\"\
             {metadata_length}{error}{slow_request}",
            level = level,
            method = req.method(),
            path = FullPath(req),
            ip = request_header(req, "X-Real-Ip"),
            time_ms = response_time,
            user_agent = request_header(req, "User-Agent"),
            request_id = request_header(req, "X-Request-Id"),
            status = response_code,
            metadata_length = metadata_length,
            error = error,
            slow_request = slow_request,
        );

        res
    }
}

struct FullPath<'a>(&'a dyn Request);

impl<'a> fmt::Display for FullPath<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0.path())?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use game::simpleboard::SimpleBoard;
use game::board::*;

pub trait Evaluation {
    fn evaluate(&self) -> f64;
}

impl Evaluation for SimpleBoard {
    fn evaluate(&self) -> f64 {
        // For now just count the difference between black and white stones
        let mut difference: f64 = 0.0;

        for state in self.intersections.iter() {
            if *state == State::White {
                difference -= 1.0;
            }
            else if *state == State::Black {
                difference += 1.0;
            }
        }
        difference
    }
}

#[cfg(test)]
mod tests {
    use game::simpleboard::*;
    use game::board::*;
    use search::evaluation::Evaluation;

    #[test]
    fn evaluate() {
        let mut game_board = SimpleBoard::new(3, 3);

        let mv1 = GoMove::Move{x: 0, y: 0, player: State::White};
        game_board.play_move(mv1);
        assert_eq!(game_board.evaluate(), -1);
        let mv2 = GoMove::Move{x: 1, y: 0, player: State::Black};
        game_board.play_move(mv2);
        let mv3 = GoMove::Move{x: 1, y: 1, player: State::Black};
        game_board.play_move(mv3);
        assert_eq!(game_board.evaluate(), 1);
    }
}
<commit_msg>Fixed evaluation test<commit_after>use game::simpleboard::SimpleBoard;
use game::board::*;

pub trait Evaluation {
    fn evaluate(&self) -> f64;
}

impl Evaluation for SimpleBoard {
    fn evaluate(&self) -> f64 {
        // For now just count the difference between black and white stones
        let mut difference: f64 = 0.0;

        for state in self.intersections.iter() {
            if *state == State::White {
                difference -= 1.0;
            }
            else if *state == State::Black {
                difference += 1.0;
            }
        }
        difference
    }
}

#[cfg(test)]
mod tests {
    use game::simpleboard::*;
    use game::board::*;
    use search::evaluation::Evaluation;

    #[test]
    fn evaluate() {
        let mut game_board = SimpleBoard::new(3, 3);

        let mv1 = GoMove::Move{x: 0, y: 0, player: State::White};
        game_board.play_move(mv1);
        assert_eq!(game_board.evaluate(), -1.0);
        let mv2 = GoMove::Move{x: 1, y: 0, player: State::Black};
        game_board.play_move(mv2);
        let mv3 = GoMove::Move{x: 1, y: 1, player: State::Black};
        game_board.play_move(mv3);
        assert_eq!(game_board.evaluate(), 1.0);
    }
}
<|endoftext|>