<commit_before>//! Implementation of `std::os` functionality for Windows.

#![allow(nonstandard_style)]

#[cfg(test)]
mod tests;

use crate::os::windows::prelude::*;

use crate::error::Error as StdError;
use crate::ffi::{OsStr, OsString};
use crate::fmt;
use crate::io;
use crate::os::windows::ffi::EncodeWide;
use crate::path::{self, PathBuf};
use crate::ptr;
use crate::slice;
use crate::sys::{c, cvt};

use super::to_u16s;

pub fn errno() -> i32 {
    unsafe { c::GetLastError() as i32 }
}

/// Gets a detailed string description for the given error number.
pub fn error_string(mut errnum: i32) -> String {
    // This value is calculated from the macro
    // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
    let langId = 0x0800 as c::DWORD;

    let mut buf = [0 as c::WCHAR; 2048];

    unsafe {
        let mut module = ptr::null_mut();
        let mut flags = 0;

        // NTSTATUS errors may be encoded as HRESULT, which may returned from
        // GetLastError. For more information about Windows error codes, see
        // `[MS-ERREF]`: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a
        if (errnum & c::FACILITY_NT_BIT as i32) != 0 {
            // format according to https://support.microsoft.com/en-us/help/259693
            const NTDLL_DLL: &[u16] = &[
                'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _,
                'L' as _, 0,
            ];
            module = c::GetModuleHandleW(NTDLL_DLL.as_ptr());

            if !module.is_null() {
                errnum ^= c::FACILITY_NT_BIT as i32;
                flags = c::FORMAT_MESSAGE_FROM_HMODULE;
            }
        }

        let res = c::FormatMessageW(
            flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS,
            module,
            errnum as c::DWORD,
            langId,
            buf.as_mut_ptr(),
            buf.len() as c::DWORD,
            ptr::null(),
        ) as usize;
        if res == 0 {
            // Sometimes FormatMessageW can fail e.g., system doesn't like langId,
            let fm_err = errno();
            return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
        }

        match String::from_utf16(&buf[..res]) {
            Ok(mut msg) => {
                // Trim trailing CRLF inserted by FormatMessageW
                let len = msg.trim_end().len();
                msg.truncate(len);
                msg
            }
            Err(..) => format!(
                "OS Error {} (FormatMessageW() returned \
                 invalid UTF-16)",
                errnum
            ),
        }
    }
}

pub struct Env {
    base: c::LPWCH,
    cur: c::LPWCH,
}

impl Iterator for Env {
    type Item = (OsString, OsString);

    fn next(&mut self) -> Option<(OsString, OsString)> {
        loop {
            unsafe {
                if *self.cur == 0 {
                    return None;
                }
                let p = self.cur as *const u16;
                let mut len = 0;
                while *p.offset(len) != 0 {
                    len += 1;
                }
                let s = slice::from_raw_parts(p, len as usize);
                self.cur = self.cur.offset(len + 1);

                // Windows allows environment variables to start with an equals
                // symbol (in any other position, this is the separator between
                // variable name and value). Since`s` has at least length 1 at
                // this point (because the empty string terminates the array of
                // environment variables), we can safely slice.
                let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) {
                    Some(p) => p,
                    None => continue,
                };
                return Some((
                    OsStringExt::from_wide(&s[..pos]),
                    OsStringExt::from_wide(&s[pos + 1..]),
                ));
            }
        }
    }
}

impl Drop for Env {
    fn drop(&mut self) {
        unsafe {
            c::FreeEnvironmentStringsW(self.base);
        }
    }
}

pub fn env() -> Env {
    unsafe {
        let ch = c::GetEnvironmentStringsW();
        if ch as usize == 0 {
            panic!("failure getting env string from OS: {}", io::Error::last_os_error());
        }
        Env { base: ch, cur: ch }
    }
}

pub struct SplitPaths<'a> {
    data: EncodeWide<'a>,
    must_yield: bool,
}

pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
    SplitPaths { data: unparsed.encode_wide(), must_yield: true }
}

impl<'a> Iterator for SplitPaths<'a> {
    type Item = PathBuf;
    fn next(&mut self) -> Option<PathBuf> {
        // On Windows, the PATH environment variable is semicolon separated.
        // Double quotes are used as a way of introducing literal semicolons
        // (since c:\some;dir is a valid Windows path). Double quotes are not
        // themselves permitted in path names, so there is no way to escape a
        // double quote.  Quoted regions can appear in arbitrary locations, so
        //
        //   c:\foo;c:\som"e;di"r;c:\bar
        //
        // Should parse as [c:\foo, c:\some;dir, c:\bar].
        //
        // (The above is based on testing; there is no clear reference available
        // for the grammar.)

        let must_yield = self.must_yield;
        self.must_yield = false;

        let mut in_progress = Vec::new();
        let mut in_quote = false;
        for b in self.data.by_ref() {
            if b == '"' as u16 {
                in_quote = !in_quote;
            } else if b == ';' as u16 && !in_quote {
                self.must_yield = true;
                break;
            } else {
                in_progress.push(b)
            }
        }

        if !must_yield && in_progress.is_empty() {
            None
        } else {
            Some(super::os2path(&in_progress))
        }
    }
}

#[derive(Debug)]
pub struct JoinPathsError;

pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
where
    I: Iterator<Item = T>,
    T: AsRef<OsStr>,
{
    let mut joined = Vec::new();
    let sep = b';' as u16;

    for (i, path) in paths.enumerate() {
        let path = path.as_ref();
        if i > 0 {
            joined.push(sep)
        }
        let v = path.encode_wide().collect::<Vec<u16>>();
        if v.contains(&(b'"' as u16)) {
            return Err(JoinPathsError);
        } else if v.contains(&sep) {
            joined.push(b'"' as u16);
            joined.extend_from_slice(&v[..]);
            joined.push(b'"' as u16);
        } else {
            joined.extend_from_slice(&v[..]);
        }
    }

    Ok(OsStringExt::from_wide(&joined[..]))
}

impl fmt::Display for JoinPathsError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "path segment contains `\"`".fmt(f)
    }
}

impl StdError for JoinPathsError {
    #[allow(deprecated)]
    fn description(&self) -> &str {
        "failed to join paths"
    }
}

pub fn current_exe() -> io::Result<PathBuf> {
    super::fill_utf16_buf(
        |buf, sz| unsafe { c::GetModuleFileNameW(ptr::null_mut(), buf, sz) },
        super::os2path,
    )
}

pub fn getcwd() -> io::Result<PathBuf> {
    super::fill_utf16_buf(|buf, sz| unsafe { c::GetCurrentDirectoryW(sz, buf) }, super::os2path)
}

pub fn chdir(p: &path::Path) -> io::Result<()> {
    let p: &OsStr = p.as_ref();
    let mut p = p.encode_wide().collect::<Vec<_>>();
    p.push(0);

    cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(drop)
}

pub fn getenv(k: &OsStr) -> Option<OsString> {
    let k = to_u16s(k).ok()?;
    super::fill_utf16_buf(
        |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) },
        |buf| OsStringExt::from_wide(buf),
    )
    .ok()
}

pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
    let k = to_u16s(k)?;
    let v = to_u16s(v)?;

    cvt(unsafe { c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr()) }).map(drop)
}

pub fn unsetenv(n: &OsStr) -> io::Result<()> {
    let v = to_u16s(n)?;
    cvt(unsafe { c::SetEnvironmentVariableW(v.as_ptr(), ptr::null()) }).map(drop)
}

pub fn temp_dir() -> PathBuf {
    super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) }, super::os2path).unwrap()
}

#[cfg(not(target_vendor = "uwp"))]
fn home_dir_crt() -> Option<PathBuf> {
    unsafe {
        use crate::sys::handle::Handle;

        let me = c::GetCurrentProcess();
        let mut token = ptr::null_mut();
        if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
            return None;
        }
        let _handle = Handle::from_raw_handle(token);
        super::fill_utf16_buf(
            |buf, mut sz| {
                match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
                    0 if c::GetLastError() != c::ERROR_INSUFFICIENT_BUFFER => 0,
                    0 => sz,
                    _ => sz - 1, // sz includes the null terminator
                }
            },
            super::os2path,
        )
        .ok()
    }
}

#[cfg(target_vendor = "uwp")]
fn home_dir_crt() -> Option<PathBuf> {
    None
}

pub fn home_dir() -> Option<PathBuf> {
    crate::env::var_os("HOME")
        .or_else(|| crate::env::var_os("USERPROFILE"))
        .map(PathBuf::from)
        .or_else(|| home_dir_crt())
}

pub fn exit(code: i32) -> ! {
    unsafe { c::ExitProcess(code as c::UINT) }
}

pub fn getpid() -> u32 {
    unsafe { c::GetCurrentProcessId() as u32 }
}
<commit_msg>Rollup merge of #90166 - smmalis37:patch-1, r=joshtriplett<commit_after>//! Implementation of `std::os` functionality for Windows.

#![allow(nonstandard_style)]

#[cfg(test)]
mod tests;

use crate::os::windows::prelude::*;

use crate::error::Error as StdError;
use crate::ffi::{OsStr, OsString};
use crate::fmt;
use crate::io;
use crate::os::windows::ffi::EncodeWide;
use crate::path::{self, PathBuf};
use crate::ptr;
use crate::slice;
use crate::sys::{c, cvt};

use super::to_u16s;

pub fn errno() -> i32 {
    unsafe { c::GetLastError() as i32 }
}

/// Gets a detailed string description for the given error number.
pub fn error_string(mut errnum: i32) -> String {
    // This value is calculated from the macro
    // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
    let langId = 0x0800 as c::DWORD;

    let mut buf = [0 as c::WCHAR; 2048];

    unsafe {
        let mut module = ptr::null_mut();
        let mut flags = 0;

        // NTSTATUS errors may be encoded as HRESULT, which may returned from
        // GetLastError. For more information about Windows error codes, see
        // `[MS-ERREF]`: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a
        if (errnum & c::FACILITY_NT_BIT as i32) != 0 {
            // format according to https://support.microsoft.com/en-us/help/259693
            const NTDLL_DLL: &[u16] = &[
                'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _,
                'L' as _, 0,
            ];
            module = c::GetModuleHandleW(NTDLL_DLL.as_ptr());

            if !module.is_null() {
                errnum ^= c::FACILITY_NT_BIT as i32;
                flags = c::FORMAT_MESSAGE_FROM_HMODULE;
            }
        }

        let res = c::FormatMessageW(
            flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS,
            module,
            errnum as c::DWORD,
            langId,
            buf.as_mut_ptr(),
            buf.len() as c::DWORD,
            ptr::null(),
        ) as usize;
        if res == 0 {
            // Sometimes FormatMessageW can fail e.g., system doesn't like langId,
            let fm_err = errno();
            return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
        }

        match String::from_utf16(&buf[..res]) {
            Ok(mut msg) => {
                // Trim trailing CRLF inserted by FormatMessageW
                let len = msg.trim_end().len();
                msg.truncate(len);
                msg
            }
            Err(..) => format!(
                "OS Error {} (FormatMessageW() returned \
                 invalid UTF-16)",
                errnum
            ),
        }
    }
}

pub struct Env {
    base: c::LPWCH,
    cur: c::LPWCH,
}

impl Iterator for Env {
    type Item = (OsString, OsString);

    fn next(&mut self) -> Option<(OsString, OsString)> {
        loop {
            unsafe {
                if *self.cur == 0 {
                    return None;
                }
                let p = self.cur as *const u16;
                let mut len = 0;
                while *p.offset(len) != 0 {
                    len += 1;
                }
                let s = slice::from_raw_parts(p, len as usize);
                self.cur = self.cur.offset(len + 1);

                // Windows allows environment variables to start with an equals
                // symbol (in any other position, this is the separator between
                // variable name and value). Since`s` has at least length 1 at
                // this point (because the empty string terminates the array of
                // environment variables), we can safely slice.
                let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) {
                    Some(p) => p,
                    None => continue,
                };
                return Some((
                    OsStringExt::from_wide(&s[..pos]),
                    OsStringExt::from_wide(&s[pos + 1..]),
                ));
            }
        }
    }
}

impl Drop for Env {
    fn drop(&mut self) {
        unsafe {
            c::FreeEnvironmentStringsW(self.base);
        }
    }
}

pub fn env() -> Env {
    unsafe {
        let ch = c::GetEnvironmentStringsW();
        if ch as usize == 0 {
            panic!("failure getting env string from OS: {}", io::Error::last_os_error());
        }
        Env { base: ch, cur: ch }
    }
}

pub struct SplitPaths<'a> {
    data: EncodeWide<'a>,
    must_yield: bool,
}

pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
    SplitPaths { data: unparsed.encode_wide(), must_yield: true }
}

impl<'a> Iterator for SplitPaths<'a> {
    type Item = PathBuf;
    fn next(&mut self) -> Option<PathBuf> {
        // On Windows, the PATH environment variable is semicolon separated.
        // Double quotes are used as a way of introducing literal semicolons
        // (since c:\some;dir is a valid Windows path). Double quotes are not
        // themselves permitted in path names, so there is no way to escape a
        // double quote.  Quoted regions can appear in arbitrary locations, so
        //
        //   c:\foo;c:\som"e;di"r;c:\bar
        //
        // Should parse as [c:\foo, c:\some;dir, c:\bar].
        //
        // (The above is based on testing; there is no clear reference available
        // for the grammar.)

        let must_yield = self.must_yield;
        self.must_yield = false;

        let mut in_progress = Vec::new();
        let mut in_quote = false;
        for b in self.data.by_ref() {
            if b == '"' as u16 {
                in_quote = !in_quote;
            } else if b == ';' as u16 && !in_quote {
                self.must_yield = true;
                break;
            } else {
                in_progress.push(b)
            }
        }

        if !must_yield && in_progress.is_empty() {
            None
        } else {
            Some(super::os2path(&in_progress))
        }
    }
}

#[derive(Debug)]
pub struct JoinPathsError;

pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
where
    I: Iterator<Item = T>,
    T: AsRef<OsStr>,
{
    let mut joined = Vec::new();
    let sep = b';' as u16;

    for (i, path) in paths.enumerate() {
        let path = path.as_ref();
        if i > 0 {
            joined.push(sep)
        }
        let v = path.encode_wide().collect::<Vec<u16>>();
        if v.contains(&(b'"' as u16)) {
            return Err(JoinPathsError);
        } else if v.contains(&sep) {
            joined.push(b'"' as u16);
            joined.extend_from_slice(&v[..]);
            joined.push(b'"' as u16);
        } else {
            joined.extend_from_slice(&v[..]);
        }
    }

    Ok(OsStringExt::from_wide(&joined[..]))
}

impl fmt::Display for JoinPathsError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "path segment contains `\"`".fmt(f)
    }
}

impl StdError for JoinPathsError {
    #[allow(deprecated)]
    fn description(&self) -> &str {
        "failed to join paths"
    }
}

pub fn current_exe() -> io::Result<PathBuf> {
    super::fill_utf16_buf(
        |buf, sz| unsafe { c::GetModuleFileNameW(ptr::null_mut(), buf, sz) },
        super::os2path,
    )
}

pub fn getcwd() -> io::Result<PathBuf> {
    super::fill_utf16_buf(|buf, sz| unsafe { c::GetCurrentDirectoryW(sz, buf) }, super::os2path)
}

pub fn chdir(p: &path::Path) -> io::Result<()> {
    let p: &OsStr = p.as_ref();
    let mut p = p.encode_wide().collect::<Vec<_>>();
    p.push(0);

    cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(drop)
}

pub fn getenv(k: &OsStr) -> Option<OsString> {
    let k = to_u16s(k).ok()?;
    super::fill_utf16_buf(
        |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) },
        |buf| OsStringExt::from_wide(buf),
    )
    .ok()
}

pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
    let k = to_u16s(k)?;
    let v = to_u16s(v)?;

    cvt(unsafe { c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr()) }).map(drop)
}

pub fn unsetenv(n: &OsStr) -> io::Result<()> {
    let v = to_u16s(n)?;
    cvt(unsafe { c::SetEnvironmentVariableW(v.as_ptr(), ptr::null()) }).map(drop)
}

pub fn temp_dir() -> PathBuf {
    super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) }, super::os2path).unwrap()
}

#[cfg(not(target_vendor = "uwp"))]
fn home_dir_crt() -> Option<PathBuf> {
    unsafe {
        // The magic constant -4 can be used as the token passed to GetUserProfileDirectoryW below
        // instead of us having to go through these multiple steps to get a token. However this is
        // not implemented on Windows 7, only Windows 8 and up. When we drop support for Windows 7
        // we can simplify this code. See #90144 for details.
        use crate::sys::handle::Handle;

        let me = c::GetCurrentProcess();
        let mut token = ptr::null_mut();
        if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
            return None;
        }
        let _handle = Handle::from_raw_handle(token);
        super::fill_utf16_buf(
            |buf, mut sz| {
                match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
                    0 if c::GetLastError() != c::ERROR_INSUFFICIENT_BUFFER => 0,
                    0 => sz,
                    _ => sz - 1, // sz includes the null terminator
                }
            },
            super::os2path,
        )
        .ok()
    }
}

#[cfg(target_vendor = "uwp")]
fn home_dir_crt() -> Option<PathBuf> {
    None
}

pub fn home_dir() -> Option<PathBuf> {
    crate::env::var_os("HOME")
        .or_else(|| crate::env::var_os("USERPROFILE"))
        .map(PathBuf::from)
        .or_else(|| home_dir_crt())
}

pub fn exit(code: i32) -> ! {
    unsafe { c::ExitProcess(code as c::UINT) }
}

pub fn getpid() -> u32 {
    unsafe { c::GetCurrentProcessId() as u32 }
}
<|endoftext|>


<commit_before>extern crate webrender;
extern crate glutin;
extern crate gleam;
extern crate webrender_traits;
extern crate euclid;

use euclid::{Size2D, Point2D, Rect, Matrix4D};
use gleam::gl;
use std::path::PathBuf;
use std::ffi::CStr;
use webrender_traits::{AuxiliaryListsBuilder, ColorF, Epoch, GlyphInstance};
use webrender_traits::{ImageData, ImageFormat, PipelineId, RendererKind};
use std::fs::File;
use std::io::Read;
use std::env;

fn _load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

pub struct WebRenderFrameBuilder {
    pub root_pipeline_id: PipelineId,
    pub next_scroll_layer_id: usize,
}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        self.window_proxy.wakeup_event_loop();
    }

    fn pipeline_size_changed(&mut self,
                             _: PipelineId,
                             _: Option<Size2D<f32>>) {
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let res_path = if args.len() > 1 {
        Some(PathBuf::from(&args[1]))
    } else {
        None
    };

    let window = glutin::WindowBuilder::new()
                .with_title("WebRender Sample")
                .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
        gl::clear_color(0.3, 0.0, 0.0, 1.0);
    }

    let version = unsafe {
        let data = CStr::from_ptr(gl::GetString(gl::VERSION) as *const _).to_bytes().to_vec();
        String::from_utf8(data).unwrap()
    };

    println!("OpenGL version {}", version);
    println!("Shader resource path: {:?}", res_path);

    let (width, height) = window.get_inner_size().unwrap();

    let opts = webrender::RendererOptions {
        device_pixel_ratio: 1.0,
        resource_override_path: res_path,
        enable_aa: false,
        enable_msaa: false,
        enable_profiler: false,
        enable_recording: false,
        enable_scrollbars: false,
        debug: true,
        precache_shaders: true,
        renderer_kind: RendererKind::Native,
        enable_subpixel_aa: false,
    };

    let (mut renderer, sender) = webrender::renderer::Renderer::new(opts);
    let api = sender.create_api();

//     let font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf";
//     let font_bytes = load_file(font_path);
//     let font_key = api.add_raw_font(font_bytes);

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let pipeline_id = PipelineId(0, 0);
    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

    let mut auxiliary_lists_builder = AuxiliaryListsBuilder::new();
    let mut builder = webrender_traits::DisplayListBuilder::new();

    let bounds = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(width as f32, height as f32));
    builder.push_stacking_context(
        webrender_traits::StackingContext::new(webrender_traits::ScrollPolicy::Scrollable,
                                               bounds,
                                               bounds,
                                               0,
                                               &Matrix4D::identity(),
                                               &Matrix4D::identity(),
                                               webrender_traits::MixBlendMode::Normal,
                                               Vec::new(),
                                               &mut auxiliary_lists_builder));

    let clip_region = {
        let mask = webrender_traits::ImageMask {
            image: api.add_image(2, 2, None, ImageFormat::A8, ImageData::new(vec![0,80, 180, 255])),
            rect: Rect::new(Point2D::new(75.0, 75.0), Size2D::new(100.0, 100.0)),
            repeat: false,
        };
        let radius = webrender_traits::BorderRadius::uniform(20.0);
        let complex = webrender_traits::ComplexClipRegion::new(
            Rect::new(Point2D::new(50.0, 50.0), Size2D::new(100.0, 100.0)),
            radius);

        webrender_traits::ClipRegion::new(&bounds,
                                          vec![complex],
                                          Some(mask),
                                          &mut auxiliary_lists_builder)
    };

    builder.push_rect(Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0)),
                      clip_region,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));

    let _text_bounds = Rect::new(Point2D::new(100.0, 200.0), Size2D::new(700.0, 300.0));

    let _glyphs = vec![
        GlyphInstance {
            index: 48,
            x: 100.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 68,
            x: 150.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 80,
            x: 200.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 82,
            x: 250.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 81,
            x: 300.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 3,
            x: 350.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 86,
            x: 400.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 79,
            x: 450.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 72,
            x: 500.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 83,
            x: 550.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 87,
            x: 600.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 17,
            x: 650.0,
            y: 100.0,
        },
    ];

//     builder.push_text(text_bounds,
//                       clip_region,
//                       glyphs,
//                       font_key,
//                       ColorF::new(1.0, 1.0, 0.0, 1.0),
//                       Au::from_px(32),
//                       Au::from_px(0),
//                       &mut frame_builder.auxiliary_lists_builder);

    builder.pop_stacking_context();

    api.set_root_display_list(
        root_background_color,
        epoch,
        pipeline_id,
        Size2D::new(width as f32, height as f32),
        builder.finalize(),
        auxiliary_lists_builder.finalize());
    api.set_root_pipeline(pipeline_id);

    for event in window.wait_events() {
        gl::clear(gl::COLOR_BUFFER_BIT);
        renderer.update();

        renderer.render(Size2D::new(width, height));

        window.swap_buffers().ok();

        match event {
            glutin::Event::Closed => break,
            glutin::Event::KeyboardInput(_element_state, scan_code, _virtual_key_code) => {
                if scan_code == 9 {
                    break;
                }
            }
            _ => ()
        }
    }
}
<commit_msg>Use safe function for GL `GetString`.<commit_after>extern crate webrender;
extern crate glutin;
extern crate gleam;
extern crate webrender_traits;
extern crate euclid;

use euclid::{Size2D, Point2D, Rect, Matrix4D};
use gleam::gl;
use std::path::PathBuf;
use std::ffi::CStr;
use webrender_traits::{AuxiliaryListsBuilder, ColorF, Epoch, GlyphInstance};
use webrender_traits::{ImageData, ImageFormat, PipelineId, RendererKind};
use std::fs::File;
use std::io::Read;
use std::env;

fn _load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

pub struct WebRenderFrameBuilder {
    pub root_pipeline_id: PipelineId,
    pub next_scroll_layer_id: usize,
}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        self.window_proxy.wakeup_event_loop();
    }

    fn pipeline_size_changed(&mut self,
                             _: PipelineId,
                             _: Option<Size2D<f32>>) {
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let res_path = if args.len() > 1 {
        Some(PathBuf::from(&args[1]))
    } else {
        None
    };

    let window = glutin::WindowBuilder::new()
                .with_title("WebRender Sample")
                .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
        gl::clear_color(0.3, 0.0, 0.0, 1.0);
    }

    println!("OpenGL version {}", gl::get_string(gl::VERSION));
    println!("Shader resource path: {:?}", res_path);

    let (width, height) = window.get_inner_size().unwrap();

    let opts = webrender::RendererOptions {
        device_pixel_ratio: 1.0,
        resource_override_path: res_path,
        enable_aa: false,
        enable_msaa: false,
        enable_profiler: false,
        enable_recording: false,
        enable_scrollbars: false,
        debug: true,
        precache_shaders: true,
        renderer_kind: RendererKind::Native,
        enable_subpixel_aa: false,
    };

    let (mut renderer, sender) = webrender::renderer::Renderer::new(opts);
    let api = sender.create_api();

//     let font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf";
//     let font_bytes = load_file(font_path);
//     let font_key = api.add_raw_font(font_bytes);

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let pipeline_id = PipelineId(0, 0);
    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

    let mut auxiliary_lists_builder = AuxiliaryListsBuilder::new();
    let mut builder = webrender_traits::DisplayListBuilder::new();

    let bounds = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(width as f32, height as f32));
    builder.push_stacking_context(
        webrender_traits::StackingContext::new(webrender_traits::ScrollPolicy::Scrollable,
                                               bounds,
                                               bounds,
                                               0,
                                               &Matrix4D::identity(),
                                               &Matrix4D::identity(),
                                               webrender_traits::MixBlendMode::Normal,
                                               Vec::new(),
                                               &mut auxiliary_lists_builder));

    let clip_region = {
        let mask = webrender_traits::ImageMask {
            image: api.add_image(2, 2, None, ImageFormat::A8, ImageData::new(vec![0,80, 180, 255])),
            rect: Rect::new(Point2D::new(75.0, 75.0), Size2D::new(100.0, 100.0)),
            repeat: false,
        };
        let radius = webrender_traits::BorderRadius::uniform(20.0);
        let complex = webrender_traits::ComplexClipRegion::new(
            Rect::new(Point2D::new(50.0, 50.0), Size2D::new(100.0, 100.0)),
            radius);

        webrender_traits::ClipRegion::new(&bounds,
                                          vec![complex],
                                          Some(mask),
                                          &mut auxiliary_lists_builder)
    };

    builder.push_rect(Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0)),
                      clip_region,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));

    let _text_bounds = Rect::new(Point2D::new(100.0, 200.0), Size2D::new(700.0, 300.0));

    let _glyphs = vec![
        GlyphInstance {
            index: 48,
            x: 100.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 68,
            x: 150.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 80,
            x: 200.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 82,
            x: 250.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 81,
            x: 300.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 3,
            x: 350.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 86,
            x: 400.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 79,
            x: 450.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 72,
            x: 500.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 83,
            x: 550.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 87,
            x: 600.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 17,
            x: 650.0,
            y: 100.0,
        },
    ];

//     builder.push_text(text_bounds,
//                       clip_region,
//                       glyphs,
//                       font_key,
//                       ColorF::new(1.0, 1.0, 0.0, 1.0),
//                       Au::from_px(32),
//                       Au::from_px(0),
//                       &mut frame_builder.auxiliary_lists_builder);

    builder.pop_stacking_context();

    api.set_root_display_list(
        root_background_color,
        epoch,
        pipeline_id,
        Size2D::new(width as f32, height as f32),
        builder.finalize(),
        auxiliary_lists_builder.finalize());
    api.set_root_pipeline(pipeline_id);

    for event in window.wait_events() {
        gl::clear(gl::COLOR_BUFFER_BIT);
        renderer.update();

        renderer.render(Size2D::new(width, height));

        window.swap_buffers().ok();

        match event {
            glutin::Event::Closed => break,
            glutin::Event::KeyboardInput(_element_state, scan_code, _virtual_key_code) => {
                if scan_code == 9 {
                    break;
                }
            }
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::convert::TryFrom;
use std::collections::HashMap;
use std::cell::RefCell;
use std::mem;
use gc::{Gc, GcCell};
use libloading::Library;
use libffi::high;
use libffi::middle::{Cif, Type, Arg};
use libffi::low::ffi_type;

use code::Instr;

#[derive(Debug)]
pub enum VMError {
    OutOfInstrs,
    Uninitialized,
    Reinitialization,
    Type,
    Bounds,
    ForeignLoad(io::Error)
}

#[derive(Debug, Trace, Finalize)]
pub struct Program {
    pub register_demand: usize,
    pub procs: Vec<Gc<Proc>>,
    pub entry: usize
}

#[derive(Debug, Trace, Finalize)]
pub struct Proc {
    pub name: String,
    pub consts: Vec<ValueRef>,
    #[unsafe_ignore_trace]
    pub instrs: Vec<Instr>
}

pub type ValueRef = Gc<Value>;

#[derive(Debug, Trace, Finalize)]
pub struct Tuple { pub fields: GcCell<Vec<ValueRef>> }

#[derive(Debug, Trace, Finalize)]
pub struct VMBox { pub value: GcCell<ValueRef> }

#[derive(Debug, Trace, Finalize)]
pub struct CodePtr {
    pub cob: Gc<Proc>,
    pub pc: usize
}

#[derive(Debug, Trace, Finalize)]
pub struct Closure {
    pub code: GcCell<Gc<Value>>,
    pub env: GcCell<Vec<ValueRef>>
}

#[derive(Debug, Trace, Finalize)]
pub struct ForeignPtr {
    #[unsafe_ignore_trace]
    pub ptr: *mut (),
    lib: ValueRef
}

#[derive(Debug)]
pub struct ForeignFn {
    pub fn_ptr: high::CodePtr,
    pub cif: RefCell<Option<Cif>>
}

#[derive(Debug, Trace, Finalize)]
pub struct Record {
    pub typ: GcCell<Gc<Value>>,
    pub fields: GcCell<Vec<ValueRef>>
}

#[derive(Debug, Trace, Finalize)]
pub enum Value {
    Int(isize),
    Char(char),
    Bool(bool),

    Symbol(String),
    String(String),

    Tuple(Tuple),

    Null,
    Box(VMBox),

    CodePtr(CodePtr),
    Fn(Closure),
    Cont(Closure),

    Denv(HashMap<String, ValueRef>),

    ForeignLib(#[unsafe_ignore_trace] Library),
    ForeignPtr(ForeignPtr),
    ForeignFn(#[unsafe_ignore_trace] ForeignFn),

    Record(Record)
}

impl Value {
    pub fn new_tuple(len: usize) -> Value {
        Value::Tuple(Tuple { fields: GcCell::new(vec![Gc::new(Value::Null); len]) })
    }

    pub fn new_box() -> Value {
        Value::Box(VMBox { value: GcCell::new(Gc::new(Value::Null)) })
    }

    pub fn new_code_ptr(cob: Gc<Proc>, pc: usize) -> Value {
        Value::CodePtr(CodePtr {
            cob: cob,
            pc: pc
        })
    }

    pub fn new_fn(len: usize) -> Value {
        Value::Cont(Closure {
            code: GcCell::new(Gc::new(Value::Null)),
            env: GcCell::new(vec![Gc::new(Value::Null); len])
        })
    }

    pub fn new_cont(len: usize) -> Value {
        Value::Cont(Closure {
            code: GcCell::new(Gc::new(Value::Null)),
            env: GcCell::new(vec![Gc::new(Value::Null); len])
        })
    }

    pub fn new_denv() -> Value {
        Value::Denv(HashMap::new())
    }

    pub fn new_foreign_lib(path: &str) -> Result<Value, VMError> {
        match Library::new(path) {
            Ok(lib) => Ok(Value::ForeignLib(lib)),
            Err(err) => Err(VMError::ForeignLoad(err))
        }
    }

    pub fn new_ptr(lib: ValueRef, ptr: *mut ()) -> Value {
        Value::ForeignPtr(ForeignPtr { ptr: ptr, lib: lib })
    }

    pub fn new_ffn(ptr: *mut ()) -> Value {
        Value::ForeignFn(ForeignFn {
            fn_ptr: high::CodePtr(ptr as _),
            cif: RefCell::new(None)
        })
    }

    pub fn new_record(len: usize) -> Value {
        Value::Record(Record {
            typ: GcCell::new(Gc::new(Value::Null)),
            fields: GcCell::new(vec![Gc::new(Value::Null); len])
        })
    }
}

impl<'a> TryFrom<&'a Value> for isize {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<isize, VMError> {
        if let &Value::Int(i) = v { Ok(i) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for usize {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<usize, VMError> {
        if let &Value::Int(i) = v { Ok(i as usize) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for bool {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<bool, VMError> {
        if let &Value::Bool(b) = v { Ok(b) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a str {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&str, VMError> {
        if let &Value::String(ref s) = v { Ok(s) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a Tuple {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&Tuple, VMError> {
        if let &Value::Tuple(ref tuple) = v { Ok(tuple) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a VMBox {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&VMBox, VMError> {
        if let &Value::Box(ref b) = v { Ok(b) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a CodePtr {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&CodePtr, VMError> {
        if let &Value::CodePtr(ref f) = v { Ok(f) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a Closure {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&Closure, VMError> {
        if let &Value::Cont(ref k) = v { Ok(k) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a Library {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&Library, VMError> {
        if let &Value::ForeignLib(ref lib) = v { Ok(lib) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a ForeignPtr {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&ForeignPtr, VMError> {
        if let &Value::ForeignPtr(ref ptr) = v { Ok(ptr) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a ForeignFn {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&ForeignFn, VMError> {
        if let &Value::ForeignFn(ref f) = v { Ok(f) } else { Err(VMError::Type) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a Record {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&Record, VMError> {
        if let &Value::Record(ref r) = v { Ok(r) } else { Err(VMError::Type) }
    }
}

pub fn as_ffi_type(value: &ValueRef) -> Result<Type, VMError> {
    match &**value {
        &Value::Int(0) => Ok(Type::isize()),
        &Value::Int(2) => Ok(Type::u32()),
        _ => Err(VMError::Type)
    }
}

pub fn as_arg(typ: *mut ffi_type, value: &ValueRef) -> Result<Arg, VMError> {
    if typ == Type::isize().as_raw_ptr() {
        if let &Value::Int(ref i) = &**value {
            Ok(Arg::new(i))
        } else if let &Value::Char(ref c) = &**value {
            Ok(Arg::new(c))
        } else {
            unimplemented!()
        }
    } else {
        unimplemented!()
    }
}

#[cfg(target_pointer_width="64")]
pub fn inject(typ: *mut ffi_type, value: u64) -> Result<Value, VMError> {
    if typ == Type::isize().as_raw_ptr() {
        Ok(Value::Int(value as _))
    } else if typ == Type::u32().as_raw_ptr() {
        Ok(Value::Char(unsafe { mem::transmute(value as u32) }))
    } else {
        unimplemented!()
    }
}
<commit_msg>Add type tag to VM type errors.<commit_after>use std::io;
use std::convert::TryFrom;
use std::collections::HashMap;
use std::cell::RefCell;
use std::mem;
use gc::{Gc, GcCell};
use libloading::Library;
use libffi::high;
use libffi::middle::{Cif, Type, Arg};
use libffi::low::ffi_type;

use code::Instr;

#[derive(Debug)]
pub enum VMError {
    OutOfInstrs,
    Uninitialized,
    Reinitialization,
    Type(TypeTag),
    Bounds,
    ForeignLoad(io::Error)
}

#[derive(Debug)]
pub enum TypeTag {
    Int, Char, Bool,
    Symbol, String,
    Tuple,
    Null, Box,
    CodePtr, Fn, Cont,
    Denv,
    ForeignLib, ForeignPtr, ForeignFn,
    Record
}

#[derive(Debug, Trace, Finalize)]
pub struct Program {
    pub register_demand: usize,
    pub procs: Vec<Gc<Proc>>,
    pub entry: usize
}

#[derive(Debug, Trace, Finalize)]
pub struct Proc {
    pub name: String,
    pub consts: Vec<ValueRef>,
    #[unsafe_ignore_trace]
    pub instrs: Vec<Instr>
}

pub type ValueRef = Gc<Value>;

#[derive(Debug, Trace, Finalize)]
pub struct Tuple { pub fields: GcCell<Vec<ValueRef>> }

#[derive(Debug, Trace, Finalize)]
pub struct VMBox { pub value: GcCell<ValueRef> }

#[derive(Debug, Trace, Finalize)]
pub struct CodePtr {
    pub cob: Gc<Proc>,
    pub pc: usize
}

#[derive(Debug, Trace, Finalize)]
pub struct Closure {
    pub code: GcCell<Gc<Value>>,
    pub env: GcCell<Vec<ValueRef>>
}

#[derive(Debug, Trace, Finalize)]
pub struct ForeignPtr {
    #[unsafe_ignore_trace]
    pub ptr: *mut (),
    lib: ValueRef
}

#[derive(Debug)]
pub struct ForeignFn {
    pub fn_ptr: high::CodePtr,
    pub cif: RefCell<Option<Cif>>
}

#[derive(Debug, Trace, Finalize)]
pub struct Record {
    pub typ: GcCell<Gc<Value>>,
    pub fields: GcCell<Vec<ValueRef>>
}

#[derive(Debug, Trace, Finalize)]
pub enum Value {
    Int(isize),
    Char(char),
    Bool(bool),

    Symbol(String),
    String(String),

    Tuple(Tuple),

    Null,
    Box(VMBox),

    CodePtr(CodePtr),
    Fn(Closure),
    Cont(Closure),

    Denv(HashMap<String, ValueRef>),

    ForeignLib(#[unsafe_ignore_trace] Library),
    ForeignPtr(ForeignPtr),
    ForeignFn(#[unsafe_ignore_trace] ForeignFn),

    Record(Record)
}

impl Value {
    pub fn new_tuple(len: usize) -> Value {
        Value::Tuple(Tuple { fields: GcCell::new(vec![Gc::new(Value::Null); len]) })
    }

    pub fn new_box() -> Value {
        Value::Box(VMBox { value: GcCell::new(Gc::new(Value::Null)) })
    }

    pub fn new_code_ptr(cob: Gc<Proc>, pc: usize) -> Value {
        Value::CodePtr(CodePtr {
            cob: cob,
            pc: pc
        })
    }

    pub fn new_fn(len: usize) -> Value {
        Value::Cont(Closure {
            code: GcCell::new(Gc::new(Value::Null)),
            env: GcCell::new(vec![Gc::new(Value::Null); len])
        })
    }

    pub fn new_cont(len: usize) -> Value {
        Value::Cont(Closure {
            code: GcCell::new(Gc::new(Value::Null)),
            env: GcCell::new(vec![Gc::new(Value::Null); len])
        })
    }

    pub fn new_denv() -> Value {
        Value::Denv(HashMap::new())
    }

    pub fn new_foreign_lib(path: &str) -> Result<Value, VMError> {
        match Library::new(path) {
            Ok(lib) => Ok(Value::ForeignLib(lib)),
            Err(err) => Err(VMError::ForeignLoad(err))
        }
    }

    pub fn new_ptr(lib: ValueRef, ptr: *mut ()) -> Value {
        Value::ForeignPtr(ForeignPtr { ptr: ptr, lib: lib })
    }

    pub fn new_ffn(ptr: *mut ()) -> Value {
        Value::ForeignFn(ForeignFn {
            fn_ptr: high::CodePtr(ptr as _),
            cif: RefCell::new(None)
        })
    }

    pub fn new_record(len: usize) -> Value {
        Value::Record(Record {
            typ: GcCell::new(Gc::new(Value::Null)),
            fields: GcCell::new(vec![Gc::new(Value::Null); len])
        })
    }
}

impl<'a> TryFrom<&'a Value> for isize {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<isize, VMError> {
        if let &Value::Int(i) = v { Ok(i) } else { Err(VMError::Type(TypeTag::Int)) }
    }
}

impl<'a> TryFrom<&'a Value> for usize {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<usize, VMError> {
        if let &Value::Int(i) = v { Ok(i as usize) } else { Err(VMError::Type(TypeTag::Int)) }
    }
}

impl<'a> TryFrom<&'a Value> for bool {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<bool, VMError> {
        if let &Value::Bool(b) = v { Ok(b) } else { Err(VMError::Type(TypeTag::Bool)) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a str {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&str, VMError> {
        if let &Value::String(ref s) = v { Ok(s) } else { Err(VMError::Type(TypeTag::String)) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a Tuple {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&Tuple, VMError> {
        if let &Value::Tuple(ref tuple) = v {
            Ok(tuple)
        } else {
            Err(VMError::Type(TypeTag::Tuple))
        }
    }
}

impl<'a> TryFrom<&'a Value> for &'a VMBox {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&VMBox, VMError> {
        if let &Value::Box(ref b) = v { Ok(b) } else { Err(VMError::Type(TypeTag::Box)) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a CodePtr {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&CodePtr, VMError> {
        if let &Value::CodePtr(ref f) = v { Ok(f) } else { Err(VMError::Type(TypeTag::CodePtr)) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a Closure {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&Closure, VMError> {
        if let &Value::Cont(ref k) = v { Ok(k) } else { Err(VMError::Type(TypeTag::Cont)) }
    }
}

impl<'a> TryFrom<&'a Value> for &'a Library {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&Library, VMError> {
        if let &Value::ForeignLib(ref lib) = v {
            Ok(lib)
        } else {
            Err(VMError::Type(TypeTag::ForeignLib))
        }
    }
}

impl<'a> TryFrom<&'a Value> for &'a ForeignPtr {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&ForeignPtr, VMError> {
        if let &Value::ForeignPtr(ref ptr) = v {
            Ok(ptr)
        } else {
            Err(VMError::Type(TypeTag::ForeignPtr))
        }
    }
}

impl<'a> TryFrom<&'a Value> for &'a ForeignFn {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&ForeignFn, VMError> {
        if let &Value::ForeignFn(ref f) = v {
            Ok(f)
        } else {
            Err(VMError::Type(TypeTag::ForeignFn))
        }
    }
}

impl<'a> TryFrom<&'a Value> for &'a Record {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<&Record, VMError> {
        if let &Value::Record(ref r) = v { Ok(r) } else { Err(VMError::Type(TypeTag::Record)) }
    }
}

pub fn as_ffi_type(value: &ValueRef) -> Result<Type, VMError> {
    match &**value {
        &Value::Int(0) => Ok(Type::isize()),
        &Value::Int(2) => Ok(Type::u32()),
        _ => Err(VMError::Type(TypeTag::Int))
    }
}

pub fn as_arg(typ: *mut ffi_type, value: &ValueRef) -> Result<Arg, VMError> {
    if typ == Type::isize().as_raw_ptr() {
        if let &Value::Int(ref i) = &**value {
            Ok(Arg::new(i))
        } else if let &Value::Char(ref c) = &**value {
            Ok(Arg::new(c))
        } else {
            unimplemented!()
        }
    } else {
        unimplemented!()
    }
}

#[cfg(target_pointer_width="64")]
pub fn inject(typ: *mut ffi_type, value: u64) -> Result<Value, VMError> {
    if typ == Type::isize().as_raw_ptr() {
        Ok(Value::Int(value as _))
    } else if typ == Type::u32().as_raw_ptr() {
        Ok(Value::Char(unsafe { mem::transmute(value as u32) }))
    } else {
        unimplemented!()
    }
}
<|endoftext|>


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

//! The `Finite<T>` struct.

use core::nonzero::Zeroable;
use num::Float;
use std::ops::Deref;

/// Encapsulates the IDL restricted float type.
#[derive(JSTraceable, Clone, Copy, Eq, PartialEq)]
pub struct Finite<T: Float>(T);

unsafe impl<T: Float> Zeroable for Finite<T> {}

impl<T: Float> Finite<T> {
    /// Create a new `Finite<T: Float>` safely.
    pub fn new(value: T) -> Option<Finite<T>> {
        if value.is_finite() {
            Some(Finite(value))
        } else {
            None
        }
    }

    /// Create a new `Finite<T: Float>`.
    #[inline]
    pub fn wrap(value: T) -> Finite<T> {
        assert!(value.is_finite(), "Finite<T> doesn't encapsulate unrestricted value.");
        Finite(value)
    }
}

impl<T: Float> Deref for Finite<T> {
    type Target = T;

    fn deref(&self) -> &T {
        let &Finite(ref value) = self;
        value
    }
}
<commit_msg>Remove the Zeroable definition for Finite<T>.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The `Finite<T>` struct.

use num::Float;
use std::ops::Deref;

/// Encapsulates the IDL restricted float type.
#[derive(JSTraceable, Clone, Copy, Eq, PartialEq)]
pub struct Finite<T: Float>(T);

impl<T: Float> Finite<T> {
    /// Create a new `Finite<T: Float>` safely.
    pub fn new(value: T) -> Option<Finite<T>> {
        if value.is_finite() {
            Some(Finite(value))
        } else {
            None
        }
    }

    /// Create a new `Finite<T: Float>`.
    #[inline]
    pub fn wrap(value: T) -> Finite<T> {
        assert!(value.is_finite(), "Finite<T> doesn't encapsulate unrestricted value.");
        Finite(value)
    }
}

impl<T: Float> Deref for Finite<T> {
    type Target = T;

    fn deref(&self) -> &T {
        let &Finite(ref value) = self;
        value
    }
}
<|endoftext|>


<commit_before>//! A library providing a generic connection pool.
#![warn(missing_docs)]
#![doc(html_root_url="https://sfackler.github.io/r2d2/doc/v0.5.8")]

#[macro_use]
extern crate log;
extern crate time;
extern crate debug_builders;

use debug_builders::DebugStruct;
use std::collections::VecDeque;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, MutexGuard, Condvar};
use time::{Duration, SteadyTime};

#[doc(inline)]
pub use config::Config;

use task::ScheduledThreadPool;

pub mod config;
mod task;
mod thunk;

/// A trait which provides connection-specific functionality.
pub trait ManageConnection: Send + Sync + 'static {
    /// The connection type this manager deals with.
    type Connection: Send + 'static;

    /// The error type returned by `Connection`s.
    type Error: 'static;

    /// Attempts to create a new connection.
    fn connect(&self) -> Result<Self::Connection, Self::Error>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut Self::Connection) -> bool;
}

/// A trait which handles errors reported by the `ManageConnection`.
pub trait HandleError<E>: Send+Sync+'static {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

/// A `HandleError` implementation which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NoopErrorHandler;

impl<E> HandleError<E> for NoopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// A `HandleError` implementation which logs at the error level.
#[derive(Copy, Clone, Debug)]
pub struct LoggingErrorHandler;

impl<E> HandleError<E> for LoggingErrorHandler where E: Error {
    fn handle_error(&self, error: E) {
        error!("{}", error);
    }
}

/// A trait which allows for customization of connections.
pub trait CustomizeConnection<C, E>: Send+Sync+'static {
    /// Called with connections immediately after they are returned from
    /// `ManageConnection::connect`.
    ///
    /// The default implementation simply returns `Ok(())`.
    ///
    /// # Errors
    ///
    /// If this method returns an error, the connection will be discarded.
    #[allow(unused_variables)]
    fn on_acquire(&self, conn: &mut C) -> Result<(), E> {
        Ok(())
    }
}

/// A `CustomizeConnection` which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NoopConnectionCustomizer;

impl<C, E> CustomizeConnection<C, E> for NoopConnectionCustomizer {}

struct PoolInternals<C> {
    conns: VecDeque<C>,
    num_conns: u32,
}

struct SharedPool<M> where M: ManageConnection {
    config: Config<M::Connection, M::Error>,
    manager: M,
    internals: Mutex<PoolInternals<M::Connection>>,
    cond: Condvar,
    thread_pool: ScheduledThreadPool,
}

fn add_connection<M>(delay: Duration, shared: &Arc<SharedPool<M>>) where M: ManageConnection {
    let new_shared = shared.clone();
    shared.thread_pool.run_after(delay, move || {
        let shared = new_shared;
        let conn = shared.manager.connect().and_then(|mut conn| {
            shared.config.connection_customizer().on_acquire(&mut conn).map(|_| conn)
        });
        match conn {
            Ok(conn) => {
                let mut internals = shared.internals.lock().unwrap();
                internals.conns.push_back(conn);
                internals.num_conns += 1;
                shared.cond.notify_one();
            }
            Err(err) => {
                shared.config.error_handler().handle_error(err);
                add_connection(Duration::seconds(1), &shared);
            },
        }
    });
}

/// A generic connection pool.
pub struct Pool<M> where M: ManageConnection {
    shared: Arc<SharedPool<M>>,
}

impl<M> Drop for Pool<M> where M: ManageConnection {
    fn drop(&mut self) {
        self.shared.thread_pool.clear();
    }
}

/// Returns a new `Pool` referencing the same state as `self`.
impl<M> Clone for Pool<M> where M: ManageConnection {
    fn clone(&self) -> Pool<M> {
        Pool {
            shared: self.shared.clone(),
        }
    }
}

impl<M> fmt::Debug for Pool<M> where M: ManageConnection + fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        DebugStruct::new(fmt, "Pool")
            .field("idle_connections", &self.shared.internals.lock().unwrap().conns.len())
            .field("config", &self.shared.config)
            .field("manager", &self.shared.manager)
            .finish()
    }
}

/// An error returned by `Pool::new` if it fails to initialize connections.
#[derive(Debug)]
pub struct InitializationError(());

impl fmt::Display for InitializationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for InitializationError {
    fn description(&self) -> &str {
        "Unable to initialize connections"
    }
}

/// An error returned by `Pool::get` if it times out without retrieving a connection.
#[derive(Debug)]
pub struct GetTimeout(());

impl fmt::Display for GetTimeout {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for GetTimeout {
    fn description(&self) -> &str {
        "Timed out while waiting for a connection"
    }
}

impl<M> Pool<M> where M: ManageConnection {
    /// Creates a new connection pool.
    ///
    /// Returns an `Err` value if `initialization_fail_fast` is set to true in
    /// the configuration and the pool is unable to open all of its
    /// connections.
    pub fn new(config: Config<M::Connection, M::Error>, manager: M)
               -> Result<Pool<M>, InitializationError> {
        let internals = PoolInternals {
            conns: VecDeque::new(),
            num_conns: 0,
        };

        let shared = Arc::new(SharedPool {
            thread_pool: ScheduledThreadPool::new(config.helper_threads() as usize),
            config: config,
            manager: manager,
            internals: Mutex::new(internals),
            cond: Condvar::new(),
        });

        for _ in 0..shared.config.pool_size() {
            add_connection(Duration::zero(), &shared);
        }

        if shared.config.initialization_fail_fast() {
            let end = SteadyTime::now() +
                Duration::milliseconds(shared.config.connection_timeout_ms() as i64);
            let mut internals = shared.internals.lock().unwrap();

            while internals.num_conns != shared.config.pool_size() {
                let wait = end - SteadyTime::now();
                if wait <= Duration::zero() {
                    return Err(InitializationError(()));
                }
                internals = shared.cond.wait_timeout_ms(internals,
                                                        wait.num_milliseconds() as u32)
                    .unwrap().0;
            }
        }

        Ok(Pool {
            shared: shared,
        })
    }

    fn get_inner(&self) -> Result<M::Connection, GetTimeout> {
        let end = SteadyTime::now() +
            Duration::milliseconds(self.shared.config.connection_timeout_ms() as i64);
        let mut internals = self.shared.internals.lock().unwrap();

        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.shared.config.test_on_check_out() {
                        if let Err(e) = self.shared.manager.is_valid(&mut conn) {
                            self.shared.config.error_handler().handle_error(e);
                            internals = self.shared.internals.lock().unwrap();
                            self.handle_broken(&mut internals);
                            continue
                        }
                    }

                    return Ok(conn);
                }
                None => {
                    let now = SteadyTime::now();
                    let mut timeout = (end - now).num_milliseconds();
                    if timeout < 0 {
                        timeout = 0
                    };
                    let (new_internals, no_timeout) =
                        self.shared.cond.wait_timeout_ms(internals, timeout as u32).unwrap();
                    internals = new_internals;

                    if !no_timeout {
                        return Err(GetTimeout(()));
                    }
                }
            }
        }
    }

    /// Retrieves a connection from the pool.
    ///
    /// Waits for at most `Config::connection_timeout` before returning an
    /// error.
    pub fn get(&self) -> Result<PooledConnection<M>, GetTimeout> {
        Ok(PooledConnection {
            pool: self.clone(),
            conn: Some(try!(self.get_inner())),
        })
    }

    fn handle_broken(&self, internals: &mut MutexGuard<PoolInternals<M::Connection>>) {
        internals.num_conns -= 1;
        add_connection(Duration::zero(), &self.shared);
    }

    fn put_back(&self, mut conn: M::Connection) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.shared.manager.has_broken(&mut conn);

        let mut internals = self.shared.internals.lock().unwrap();
        if broken {
            self.handle_broken(&mut internals);
        } else {
            internals.conns.push_back(conn);
            self.shared.cond.notify_one();
        }
    }
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<M> where M: ManageConnection {
    pool: Pool<M>,
    conn: Option<M::Connection>,
}

impl<M> fmt::Debug for PooledConnection<M>
        where M: ManageConnection + fmt::Debug, M::Connection: fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        DebugStruct::new(fmt, "PooledConnection")
            .field("pool", &self.pool)
            .field("connection", self.conn.as_ref().unwrap())
            .finish()
    }
}

impl<M> Drop for PooledConnection<M> where M: ManageConnection {
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<M> Deref for PooledConnection<M> where M: ManageConnection {
    type Target = M::Connection;

    fn deref(&self) -> &M::Connection {
        self.conn.as_ref().unwrap()
    }
}

impl<M> DerefMut for PooledConnection<M> where M: ManageConnection {
    fn deref_mut(&mut self) -> &mut M::Connection {
        self.conn.as_mut().unwrap()
    }
}
<commit_msg>Add a crate level example.<commit_after>//! A generic connection pool.
//!
//! Opening a new database connection every time one is needed is both
//! inefficient and can lead to resource exhaustion under high traffic
//! conditions. A connection pool maintains a set of open connections to a
//! database, handing them out for repeated use.
//!
//! r2d2 is agnostic to the connection type it is managing. Implementors of the
//! `ManageConnection` trait provide the database-specific logic to create and
//! check the health of connections.
//!
//! # Example
//!
//! Using an imaginary "foodb" database.
//!
//! ```rust,ignore
//! use std::thread;
//!
//! extern crate r2d2;
//! extern crate r2d2_foodb;
//!
//! fn main() {
//!     let config = r2d2::Config::builder()
//!         .error_handler(Box::new(r2d2::LoggingErrorHandler))
//!         .build();
//!     let manager = r2d2_foodb::FooManageConnection::new("localhost:1234");
//!
//!     let pool = r2d2::Pool::new(config, manager).unwrap();
//!
//!     for _ in 0..20i32 {
//!         let pool = pool.clone();
//!         thread::spawn(move || {
//!             let conn = pool.get().unwrap();
//!             // use the connection
//!             // it will be returned to the pool when it falls out of scope.
//!         })
//!     }
//! }
//! ```
#![warn(missing_docs)]
#![doc(html_root_url="https://sfackler.github.io/r2d2/doc/v0.5.8")]

#[macro_use]
extern crate log;
extern crate time;
extern crate debug_builders;

use debug_builders::DebugStruct;
use std::collections::VecDeque;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, MutexGuard, Condvar};
use time::{Duration, SteadyTime};

#[doc(inline)]
pub use config::Config;

use task::ScheduledThreadPool;

pub mod config;
mod task;
mod thunk;

/// A trait which provides connection-specific functionality.
pub trait ManageConnection: Send + Sync + 'static {
    /// The connection type this manager deals with.
    type Connection: Send + 'static;

    /// The error type returned by `Connection`s.
    type Error: 'static;

    /// Attempts to create a new connection.
    fn connect(&self) -> Result<Self::Connection, Self::Error>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut Self::Connection) -> bool;
}

/// A trait which handles errors reported by the `ManageConnection`.
pub trait HandleError<E>: Send+Sync+'static {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

/// A `HandleError` implementation which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NoopErrorHandler;

impl<E> HandleError<E> for NoopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// A `HandleError` implementation which logs at the error level.
#[derive(Copy, Clone, Debug)]
pub struct LoggingErrorHandler;

impl<E> HandleError<E> for LoggingErrorHandler where E: Error {
    fn handle_error(&self, error: E) {
        error!("{}", error);
    }
}

/// A trait which allows for customization of connections.
pub trait CustomizeConnection<C, E>: Send+Sync+'static {
    /// Called with connections immediately after they are returned from
    /// `ManageConnection::connect`.
    ///
    /// The default implementation simply returns `Ok(())`.
    ///
    /// # Errors
    ///
    /// If this method returns an error, the connection will be discarded.
    #[allow(unused_variables)]
    fn on_acquire(&self, conn: &mut C) -> Result<(), E> {
        Ok(())
    }
}

/// A `CustomizeConnection` which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NoopConnectionCustomizer;

impl<C, E> CustomizeConnection<C, E> for NoopConnectionCustomizer {}

struct PoolInternals<C> {
    conns: VecDeque<C>,
    num_conns: u32,
}

struct SharedPool<M> where M: ManageConnection {
    config: Config<M::Connection, M::Error>,
    manager: M,
    internals: Mutex<PoolInternals<M::Connection>>,
    cond: Condvar,
    thread_pool: ScheduledThreadPool,
}

fn add_connection<M>(delay: Duration, shared: &Arc<SharedPool<M>>) where M: ManageConnection {
    let new_shared = shared.clone();
    shared.thread_pool.run_after(delay, move || {
        let shared = new_shared;
        let conn = shared.manager.connect().and_then(|mut conn| {
            shared.config.connection_customizer().on_acquire(&mut conn).map(|_| conn)
        });
        match conn {
            Ok(conn) => {
                let mut internals = shared.internals.lock().unwrap();
                internals.conns.push_back(conn);
                internals.num_conns += 1;
                shared.cond.notify_one();
            }
            Err(err) => {
                shared.config.error_handler().handle_error(err);
                add_connection(Duration::seconds(1), &shared);
            },
        }
    });
}

/// A generic connection pool.
pub struct Pool<M> where M: ManageConnection {
    shared: Arc<SharedPool<M>>,
}

impl<M> Drop for Pool<M> where M: ManageConnection {
    fn drop(&mut self) {
        self.shared.thread_pool.clear();
    }
}

/// Returns a new `Pool` referencing the same state as `self`.
impl<M> Clone for Pool<M> where M: ManageConnection {
    fn clone(&self) -> Pool<M> {
        Pool {
            shared: self.shared.clone(),
        }
    }
}

impl<M> fmt::Debug for Pool<M> where M: ManageConnection + fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        DebugStruct::new(fmt, "Pool")
            .field("idle_connections", &self.shared.internals.lock().unwrap().conns.len())
            .field("config", &self.shared.config)
            .field("manager", &self.shared.manager)
            .finish()
    }
}

/// An error returned by `Pool::new` if it fails to initialize connections.
#[derive(Debug)]
pub struct InitializationError(());

impl fmt::Display for InitializationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for InitializationError {
    fn description(&self) -> &str {
        "Unable to initialize connections"
    }
}

/// An error returned by `Pool::get` if it times out without retrieving a connection.
#[derive(Debug)]
pub struct GetTimeout(());

impl fmt::Display for GetTimeout {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for GetTimeout {
    fn description(&self) -> &str {
        "Timed out while waiting for a connection"
    }
}

impl<M> Pool<M> where M: ManageConnection {
    /// Creates a new connection pool.
    ///
    /// Returns an `Err` value if `initialization_fail_fast` is set to true in
    /// the configuration and the pool is unable to open all of its
    /// connections.
    pub fn new(config: Config<M::Connection, M::Error>, manager: M)
               -> Result<Pool<M>, InitializationError> {
        let internals = PoolInternals {
            conns: VecDeque::new(),
            num_conns: 0,
        };

        let shared = Arc::new(SharedPool {
            thread_pool: ScheduledThreadPool::new(config.helper_threads() as usize),
            config: config,
            manager: manager,
            internals: Mutex::new(internals),
            cond: Condvar::new(),
        });

        for _ in 0..shared.config.pool_size() {
            add_connection(Duration::zero(), &shared);
        }

        if shared.config.initialization_fail_fast() {
            let end = SteadyTime::now() +
                Duration::milliseconds(shared.config.connection_timeout_ms() as i64);
            let mut internals = shared.internals.lock().unwrap();

            while internals.num_conns != shared.config.pool_size() {
                let wait = end - SteadyTime::now();
                if wait <= Duration::zero() {
                    return Err(InitializationError(()));
                }
                internals = shared.cond.wait_timeout_ms(internals,
                                                        wait.num_milliseconds() as u32)
                    .unwrap().0;
            }
        }

        Ok(Pool {
            shared: shared,
        })
    }

    fn get_inner(&self) -> Result<M::Connection, GetTimeout> {
        let end = SteadyTime::now() +
            Duration::milliseconds(self.shared.config.connection_timeout_ms() as i64);
        let mut internals = self.shared.internals.lock().unwrap();

        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.shared.config.test_on_check_out() {
                        if let Err(e) = self.shared.manager.is_valid(&mut conn) {
                            self.shared.config.error_handler().handle_error(e);
                            internals = self.shared.internals.lock().unwrap();
                            self.handle_broken(&mut internals);
                            continue
                        }
                    }

                    return Ok(conn);
                }
                None => {
                    let now = SteadyTime::now();
                    let mut timeout = (end - now).num_milliseconds();
                    if timeout < 0 {
                        timeout = 0
                    };
                    let (new_internals, no_timeout) =
                        self.shared.cond.wait_timeout_ms(internals, timeout as u32).unwrap();
                    internals = new_internals;

                    if !no_timeout {
                        return Err(GetTimeout(()));
                    }
                }
            }
        }
    }

    /// Retrieves a connection from the pool.
    ///
    /// Waits for at most `Config::connection_timeout` before returning an
    /// error.
    pub fn get(&self) -> Result<PooledConnection<M>, GetTimeout> {
        Ok(PooledConnection {
            pool: self.clone(),
            conn: Some(try!(self.get_inner())),
        })
    }

    fn handle_broken(&self, internals: &mut MutexGuard<PoolInternals<M::Connection>>) {
        internals.num_conns -= 1;
        add_connection(Duration::zero(), &self.shared);
    }

    fn put_back(&self, mut conn: M::Connection) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.shared.manager.has_broken(&mut conn);

        let mut internals = self.shared.internals.lock().unwrap();
        if broken {
            self.handle_broken(&mut internals);
        } else {
            internals.conns.push_back(conn);
            self.shared.cond.notify_one();
        }
    }
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<M> where M: ManageConnection {
    pool: Pool<M>,
    conn: Option<M::Connection>,
}

impl<M> fmt::Debug for PooledConnection<M>
        where M: ManageConnection + fmt::Debug, M::Connection: fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        DebugStruct::new(fmt, "PooledConnection")
            .field("pool", &self.pool)
            .field("connection", self.conn.as_ref().unwrap())
            .finish()
    }
}

impl<M> Drop for PooledConnection<M> where M: ManageConnection {
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<M> Deref for PooledConnection<M> where M: ManageConnection {
    type Target = M::Connection;

    fn deref(&self) -> &M::Connection {
        self.conn.as_ref().unwrap()
    }
}

impl<M> DerefMut for PooledConnection<M> where M: ManageConnection {
    fn deref_mut(&mut self) -> &mut M::Connection {
        self.conn.as_mut().unwrap()
    }
}
<|endoftext|>


<commit_before>#![crate_id = "fragments#0.1-pre"]

#![comment = "A simple template library for Rust"]
#![license = "MIT"]
#![crate_type = "lib"]
#![crate_type = "rlib"]

#![doc(html_root_url = "http://www.rust-ci.org/Ogeon/fragments/doc/")]

extern crate collections;

use std::fmt;
use std::from_str::FromStr;
use std::vec::Vec;
use collections::hashmap::{HashMap, HashSet};

mod parser;

#[deriving(Eq, TotalEq, Show)]
enum Token {
	String(~str),
	Placeholder(~str),
	Conditional(~str, bool, Vec<Token>),
	ContentConditional(~str, bool, Vec<Token>),
	Generated(~str, Vec<~str>)
}

///A string template with placeholders and conditional content.
///
///Placeholders are written as `[[:label]]`, where `label` becomes the name of the placeholder.
///The label is then used to insert content: `my_template.insert("label", my_content);`.
///The assigned content for a placeholder can be anything that implements `Show`.
///Even other templates may be inserted, which allows a more atomic structure.
///
///Conditional segments are surrounded by `[[?label]]...[[/]]`, where `label` becomes the name of the condition,
///and they are used to display content depending on whether its label exists in the `conditions` set.
///`[[/]]` marks the end of a block and may contain other characters after the `/`, which may be useful for labeling the end mark.
///Conditions can be made negative by writing `[[?!label]]...[[/]]`, which makes the content visible if the label
///is missing from the `conditions` set. Conditional segments can also depend on whether a placeholder has an assgined value.
///Just write them like this: `[[?:label]]...[[/]]` or `[[?!:label]]...[[/]]`.
///
///Content can also be generated, using a generator token: `[[+label arg1 arg2 ...]]`. The label and the arguments are
///separated by one or more whitespaces. They can also be quoted to prevent special characters from being parsed:
///`[[+"my label" arg1 "[[arg2]]"]]`. The arguments will be passed to an instance of the `Generator` trait and the
///result will be inserted into the content.
///
///Any character can be escaped by writing `\` before it. It can be used like this: `\[[[:label1]], [[:label2]]]`
///which will result in `[content1, content2]`, since the first `[` will be ignored by the parser and added to the
///rest of the content.
pub struct Template {
	///Content for the placeholders
	pub content: HashMap<~str, Box<fmt::Show: Send>>,
	///Content generators
	pub generators: HashMap<~str, Box<Generator: Send>>,
	///Conditional switches
	pub conditions: HashSet<~str>,
	tokens: Vec<Token>
}

impl Template {
	///Create a new `Template` from a character iterator.
	#[inline]
	pub fn from_chars(b: &mut std::str::Chars) -> Result<Template, ~str> {
		let tokens = try!(parser::parse(&mut b.map(|r| Ok::<char, ~str>(r))));

		Ok(Template {
			content: HashMap::new(),
			generators: HashMap::new(),
			conditions: HashSet::new(),
			tokens: tokens
		})
	}

	///Create a new `Template` from a buffer.
	#[inline]
	pub fn from_buffer<T: Buffer>(b: &mut T) -> Result<Template, ~str> {
		let tokens = try!(parser::parse(&mut b.chars().map(|r| match r {
			Ok(c) => Ok(c),
			Err(e) => Err(format!("io error: {}", e))
		})));

		Ok(Template {
			content: HashMap::new(),
			generators: HashMap::new(),
			conditions: HashSet::new(),
			tokens: tokens
		})
	}

	///Convenience method for inserting content.
	#[inline]
	pub fn insert<T: fmt::Show + Send>(&mut self, label: &str, item: Box<T>) {
		self.content.insert(label.to_owned(), item as Box<fmt::Show: Send>);
	}

	///Convenience method for inserting generators.
	#[inline]
	pub fn insert_generator<T: Generator + Send>(&mut self, label: &str, gen: Box<T>) {
		self.generators.insert(label.to_owned(), gen as Box<Generator: Send>);
	}

	///Convenience method for setting a condition.
	#[inline]
	pub fn set(&mut self, label: &str, value: bool) {
		if value {
			self.conditions.insert(label.to_owned());
		} else {
			self.conditions.remove(&label.to_owned());
		}
	}

	fn format_tokens(&self, tokens: &Vec<Token>, f: &mut fmt::Formatter) -> fmt::Result {
		for token in tokens.iter() {
			let res = match token {
				&String(ref s) => f.buf.write_str(*s),

				&Placeholder(ref k) => {
					match self.content.find(k) {
						Some(value) => value.fmt(f),
						None => Ok(())
					}
				},

				&Conditional(ref k, expected, ref tokens) => {
					if self.conditions.contains(k) == expected {
						self.format_tokens(tokens, f)
					} else {
						Ok(())
					}
				},

				&ContentConditional(ref k, expected, ref tokens) => {
					if self.content.contains_key(k) == expected {
						self.format_tokens(tokens, f)
					} else {
						Ok(())
					}
				},

				&Generated(ref k, ref vars) => {
					match self.generators.find(k) {
						Some(gen) => gen.generate(vars.as_slice()).fmt(f),
						None => Ok(())
					}
				}
			};

			match res {
				Err(e) => return Err(e),
				_ => {}
			}
		}

		Ok(())
	}
}

impl FromStr for Template {
	///Creates a new `Template` from a string.
	fn from_str(s: &str) -> Option<Template> {
		match Template::from_chars(&mut s.chars()) {
			Ok(template) => Some(template),
			Err(_) => None
		}
	}
}

impl fmt::Show for Template {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.format_tokens(&self.tokens, f)
	}
}

///A trait for content generators.
pub trait Generator {
	fn generate(&self, args: &[~str]) -> Box<fmt::Show>;
}

impl Generator for fn(args: &[~str]) -> Box<fmt::Show> {
	fn generate(&self, args: &[~str]) -> Box<fmt::Show> {
		(*self)(args)
	}
}

#[cfg(test)]
mod test {
	use super::{Template, Placeholder, String};
	use std::fmt::Show;

	static peter: &'static str = "Peter";
	static nice: &'static str = "nice";

	fn monitored_from_str(s: &str) -> Template {
		match Template::from_chars(&mut s.chars()) {
			Ok(template) => template,
			Err(e) => fail!(e)
		}
	}

	fn echo(parts: &[~str]) -> Box<Show> {
		(box parts.connect(":")) as Box<Show>
	}

	#[test]
	fn basic_tokens() {
		let template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		assert_eq!(template.tokens.get(0), &String("Hello, ".to_owned()));
		assert_eq!(template.tokens.get(1), &Placeholder("name".to_owned()));
		assert_eq!(template.tokens.get(2), &String("! This is a ".to_owned()));
		assert_eq!(template.tokens.get(3), &Placeholder("something".to_owned()));
		assert_eq!(template.tokens.get(4), &String(" template.".to_owned()));
	}

	#[test]
	#[should_fail]
	fn strange_tokens() {
		let _: Template = from_str("Hello, [[[:name]]]! This is a [[[[:something]] template.").unwrap();
	}

	#[test]
	fn escaped_tokens() {
		let template = monitored_from_str("Hello, [[:name]]! Write placeholders like \\[[:this]] and escape them like \\\\\\[[:this]]");
		assert_eq!(template.tokens.get(0), &String("Hello, ".to_owned()));
		assert_eq!(template.tokens.get(1), &Placeholder("name".to_owned()));
		assert_eq!(template.tokens.get(2), &String("! Write placeholders like [[:this]] and escape them like \\[[:this]]".to_owned()));
	}

	#[test]
	fn replacement() {
		let mut template = monitored_from_str("Hello, [[:name]]! This is a [[:something]] template.");
		template.insert("name", box peter);
		template.insert("something", box nice);
		assert_eq!(template.to_str(), "Hello, Peter! This is a nice template.".to_owned());
	}

	#[test]
	fn templates_in_templates() {
		let mut template1 = monitored_from_str("Hello, [[:name]]! This is a [[:something]] template.");
		let mut template2 = box monitored_from_str("really [[:something]]");
		template1.insert("name", box peter);
		template2.insert("something", box nice);

		template1.insert("something", template2);

		assert_eq!(template1.to_str(), "Hello, Peter! This is a really nice template.".to_owned());
	}

	#[test]
	fn conditional() {
		let mut template = monitored_from_str("Hello, [[:name]]![[?condition]] The condition is true.[[/condition]]");
		template.insert("name", box peter);
		assert_eq!(template.to_str(), "Hello, Peter!".to_owned());
		template.set("condition", true);
		assert_eq!(template.to_str(), "Hello, Peter! The condition is true.".to_owned());
	}

	#[test]
	fn conditional_switch() {
		let mut template = monitored_from_str("Hello, [[:name]]! The condition is [[?condition]]true[[/condition]][[?!condition]]false[[/condition]].");
		template.insert("name", box peter);
		assert_eq!(template.to_str(), "Hello, Peter! The condition is false.".to_owned());
		template.set("condition", true);
		assert_eq!(template.to_str(), "Hello, Peter! The condition is true.".to_owned());
	}

	#[test]
	fn content_conditional() {
		let mut template = monitored_from_str("Hello[[?:name]], [[:name]][[/name]]![[?!:name]] I don't know you.[[/!name]]");
		assert_eq!(template.to_str(), "Hello! I don't know you.".to_owned());
		template.insert("name", box peter);
		assert_eq!(template.to_str(), "Hello, Peter!".to_owned());
	}

	#[test]
	fn generator() {
		let mut template = monitored_from_str("[[+\"say hello\" hello Peter    \"how are\" you?]]");
		template.insert_generator("say hello", box echo);

		assert_eq!(template.to_str(), "hello:Peter:how are:you?".to_owned());
	}
}<commit_msg>f.buf.write -> f.write<commit_after>#![crate_id = "fragments#0.1-pre"]

#![comment = "A simple template library for Rust"]
#![license = "MIT"]
#![crate_type = "lib"]
#![crate_type = "rlib"]

#![doc(html_root_url = "http://www.rust-ci.org/Ogeon/fragments/doc/")]

extern crate collections;

use std::fmt;
use std::from_str::FromStr;
use std::vec::Vec;
use collections::hashmap::{HashMap, HashSet};

mod parser;

#[deriving(Eq, TotalEq, Show)]
enum Token {
	String(~str),
	Placeholder(~str),
	Conditional(~str, bool, Vec<Token>),
	ContentConditional(~str, bool, Vec<Token>),
	Generated(~str, Vec<~str>)
}

///A string template with placeholders and conditional content.
///
///Placeholders are written as `[[:label]]`, where `label` becomes the name of the placeholder.
///The label is then used to insert content: `my_template.insert("label", my_content);`.
///The assigned content for a placeholder can be anything that implements `Show`.
///Even other templates may be inserted, which allows a more atomic structure.
///
///Conditional segments are surrounded by `[[?label]]...[[/]]`, where `label` becomes the name of the condition,
///and they are used to display content depending on whether its label exists in the `conditions` set.
///`[[/]]` marks the end of a block and may contain other characters after the `/`, which may be useful for labeling the end mark.
///Conditions can be made negative by writing `[[?!label]]...[[/]]`, which makes the content visible if the label
///is missing from the `conditions` set. Conditional segments can also depend on whether a placeholder has an assgined value.
///Just write them like this: `[[?:label]]...[[/]]` or `[[?!:label]]...[[/]]`.
///
///Content can also be generated, using a generator token: `[[+label arg1 arg2 ...]]`. The label and the arguments are
///separated by one or more whitespaces. They can also be quoted to prevent special characters from being parsed:
///`[[+"my label" arg1 "[[arg2]]"]]`. The arguments will be passed to an instance of the `Generator` trait and the
///result will be inserted into the content.
///
///Any character can be escaped by writing `\` before it. It can be used like this: `\[[[:label1]], [[:label2]]]`
///which will result in `[content1, content2]`, since the first `[` will be ignored by the parser and added to the
///rest of the content.
pub struct Template {
	///Content for the placeholders
	pub content: HashMap<~str, Box<fmt::Show: Send>>,
	///Content generators
	pub generators: HashMap<~str, Box<Generator: Send>>,
	///Conditional switches
	pub conditions: HashSet<~str>,
	tokens: Vec<Token>
}

impl Template {
	///Create a new `Template` from a character iterator.
	#[inline]
	pub fn from_chars(b: &mut std::str::Chars) -> Result<Template, ~str> {
		let tokens = try!(parser::parse(&mut b.map(|r| Ok::<char, ~str>(r))));

		Ok(Template {
			content: HashMap::new(),
			generators: HashMap::new(),
			conditions: HashSet::new(),
			tokens: tokens
		})
	}

	///Create a new `Template` from a buffer.
	#[inline]
	pub fn from_buffer<T: Buffer>(b: &mut T) -> Result<Template, ~str> {
		let tokens = try!(parser::parse(&mut b.chars().map(|r| match r {
			Ok(c) => Ok(c),
			Err(e) => Err(format!("io error: {}", e))
		})));

		Ok(Template {
			content: HashMap::new(),
			generators: HashMap::new(),
			conditions: HashSet::new(),
			tokens: tokens
		})
	}

	///Convenience method for inserting content.
	#[inline]
	pub fn insert<T: fmt::Show + Send>(&mut self, label: &str, item: Box<T>) {
		self.content.insert(label.to_owned(), item as Box<fmt::Show: Send>);
	}

	///Convenience method for inserting generators.
	#[inline]
	pub fn insert_generator<T: Generator + Send>(&mut self, label: &str, gen: Box<T>) {
		self.generators.insert(label.to_owned(), gen as Box<Generator: Send>);
	}

	///Convenience method for setting a condition.
	#[inline]
	pub fn set(&mut self, label: &str, value: bool) {
		if value {
			self.conditions.insert(label.to_owned());
		} else {
			self.conditions.remove(&label.to_owned());
		}
	}

	fn format_tokens(&self, tokens: &Vec<Token>, f: &mut fmt::Formatter) -> fmt::Result {
		for token in tokens.iter() {
			let res = match token {
				&String(ref s) => f.write(s.as_bytes()),

				&Placeholder(ref k) => {
					match self.content.find(k) {
						Some(value) => value.fmt(f),
						None => Ok(())
					}
				},

				&Conditional(ref k, expected, ref tokens) => {
					if self.conditions.contains(k) == expected {
						self.format_tokens(tokens, f)
					} else {
						Ok(())
					}
				},

				&ContentConditional(ref k, expected, ref tokens) => {
					if self.content.contains_key(k) == expected {
						self.format_tokens(tokens, f)
					} else {
						Ok(())
					}
				},

				&Generated(ref k, ref vars) => {
					match self.generators.find(k) {
						Some(gen) => gen.generate(vars.as_slice()).fmt(f),
						None => Ok(())
					}
				}
			};

			match res {
				Err(e) => return Err(e),
				_ => {}
			}
		}

		Ok(())
	}
}

impl FromStr for Template {
	///Creates a new `Template` from a string.
	fn from_str(s: &str) -> Option<Template> {
		match Template::from_chars(&mut s.chars()) {
			Ok(template) => Some(template),
			Err(_) => None
		}
	}
}

impl fmt::Show for Template {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.format_tokens(&self.tokens, f)
	}
}

///A trait for content generators.
pub trait Generator {
	fn generate(&self, args: &[~str]) -> Box<fmt::Show>;
}

impl Generator for fn(args: &[~str]) -> Box<fmt::Show> {
	fn generate(&self, args: &[~str]) -> Box<fmt::Show> {
		(*self)(args)
	}
}

#[cfg(test)]
mod test {
	use super::{Template, Placeholder, String};
	use std::fmt::Show;

	static peter: &'static str = "Peter";
	static nice: &'static str = "nice";

	fn monitored_from_str(s: &str) -> Template {
		match Template::from_chars(&mut s.chars()) {
			Ok(template) => template,
			Err(e) => fail!(e)
		}
	}

	fn echo(parts: &[~str]) -> Box<Show> {
		(box parts.connect(":")) as Box<Show>
	}

	#[test]
	fn basic_tokens() {
		let template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		assert_eq!(template.tokens.get(0), &String("Hello, ".to_owned()));
		assert_eq!(template.tokens.get(1), &Placeholder("name".to_owned()));
		assert_eq!(template.tokens.get(2), &String("! This is a ".to_owned()));
		assert_eq!(template.tokens.get(3), &Placeholder("something".to_owned()));
		assert_eq!(template.tokens.get(4), &String(" template.".to_owned()));
	}

	#[test]
	#[should_fail]
	fn strange_tokens() {
		let _: Template = from_str("Hello, [[[:name]]]! This is a [[[[:something]] template.").unwrap();
	}

	#[test]
	fn escaped_tokens() {
		let template = monitored_from_str("Hello, [[:name]]! Write placeholders like \\[[:this]] and escape them like \\\\\\[[:this]]");
		assert_eq!(template.tokens.get(0), &String("Hello, ".to_owned()));
		assert_eq!(template.tokens.get(1), &Placeholder("name".to_owned()));
		assert_eq!(template.tokens.get(2), &String("! Write placeholders like [[:this]] and escape them like \\[[:this]]".to_owned()));
	}

	#[test]
	fn replacement() {
		let mut template = monitored_from_str("Hello, [[:name]]! This is a [[:something]] template.");
		template.insert("name", box peter);
		template.insert("something", box nice);
		assert_eq!(template.to_str(), "Hello, Peter! This is a nice template.".to_owned());
	}

	#[test]
	fn templates_in_templates() {
		let mut template1 = monitored_from_str("Hello, [[:name]]! This is a [[:something]] template.");
		let mut template2 = box monitored_from_str("really [[:something]]");
		template1.insert("name", box peter);
		template2.insert("something", box nice);

		template1.insert("something", template2);

		assert_eq!(template1.to_str(), "Hello, Peter! This is a really nice template.".to_owned());
	}

	#[test]
	fn conditional() {
		let mut template = monitored_from_str("Hello, [[:name]]![[?condition]] The condition is true.[[/condition]]");
		template.insert("name", box peter);
		assert_eq!(template.to_str(), "Hello, Peter!".to_owned());
		template.set("condition", true);
		assert_eq!(template.to_str(), "Hello, Peter! The condition is true.".to_owned());
	}

	#[test]
	fn conditional_switch() {
		let mut template = monitored_from_str("Hello, [[:name]]! The condition is [[?condition]]true[[/condition]][[?!condition]]false[[/condition]].");
		template.insert("name", box peter);
		assert_eq!(template.to_str(), "Hello, Peter! The condition is false.".to_owned());
		template.set("condition", true);
		assert_eq!(template.to_str(), "Hello, Peter! The condition is true.".to_owned());
	}

	#[test]
	fn content_conditional() {
		let mut template = monitored_from_str("Hello[[?:name]], [[:name]][[/name]]![[?!:name]] I don't know you.[[/!name]]");
		assert_eq!(template.to_str(), "Hello! I don't know you.".to_owned());
		template.insert("name", box peter);
		assert_eq!(template.to_str(), "Hello, Peter!".to_owned());
	}

	#[test]
	fn generator() {
		let mut template = monitored_from_str("[[+\"say hello\" hello Peter    \"how are\" you?]]");
		template.insert_generator("say hello", box echo);

		assert_eq!(template.to_str(), "hello:Peter:how are:you?".to_owned());
	}
}<|endoftext|>