<commit_before>use std::old_io as io;

pub use self::Doc::{
    Nil,
    Append,
    Group,
    Nest,
    Newline,
    Text,
};

#[inline]
fn spaces(n: usize) -> String {
    use std::iter;
    iter::repeat(' ').take(n).collect()
}

#[inline]
fn nl_spaces(n: usize) -> String {
    let mut s = String::from_str("\n");
    s.push_str(&spaces(n));
    s
}

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
enum Mode {
    Break,
    Flat,
}

#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Doc<'a> {
    Nil,
    Append(Box<Doc<'a>>, Box<Doc<'a>>),
    Group(Box<Doc<'a>>),
    Nest(usize, Box<Doc<'a>>),
    Newline,
    Text(::std::string::CowString<'a>),
}

type Cmd<'a> = (usize, Mode, &'a Doc<'a>);

#[inline]
fn fitting<'a>(
       next:          Cmd<'a>,
      bcmds: &    Vec<Cmd<'a>>,
      fcmds: &mut Vec<Cmd<'a>>,
    mut rem: isize
) -> bool {
    let mut bidx = bcmds.len();
    let mut fits = true;

    fcmds.clear();      // clear from previous calls from best
    fcmds.push(next);

    loop {
        if rem < 0 {
            fits = false;
            break;
        }
        match fcmds.pop() {
            None => {
                if bidx == 0 {
                    break;
                } else {
                    fcmds.push(bcmds[ bidx - 1 ]);
                    bidx -= 1;
                }
            },
            Some((ind, mode, doc)) => match doc {
                &Nil => {
                },
                &Append(ref ldoc, ref rdoc) => {
                    fcmds.push((ind, mode, rdoc));
                    fcmds.push((ind, mode, ldoc));
                },
                &Group(ref doc) => {
                    fcmds.push((ind, mode, doc));
                },
                &Nest(off, ref doc) => {
                    fcmds.push((ind + off, mode, doc));
                },
                &Newline => {
                    fits = true;
                },
                &Text(ref str) => {
                    rem -= str.len() as isize;
                },
            }
        }
    }

    fits
}

#[inline]
pub fn best<W: io::Writer>(
      doc: &Doc,
    width: usize,
      out: &mut W
) -> io::IoResult<()> {
    let mut res   = Ok(());
    let mut pos   = 0us;
    let mut bcmds = vec![(0us, Mode::Break, doc)];
    let mut fcmds = vec![];

    while res.is_ok() {
        match bcmds.pop() {
            None => {
                break;
            },
            Some((ind, mode, doc)) => match doc {
                &Nil => {
                },
                &Append(ref ldoc, ref rdoc) => {
                    bcmds.push((ind, mode, rdoc));
                    bcmds.push((ind, mode, ldoc));
                },
                &Group(ref doc) => match mode {
                    Mode::Flat => {
                        bcmds.push((ind, Mode::Flat, doc));
                    },
                    Mode::Break => {
                        let next = (ind, Mode::Flat, &**doc);
                        let rem  = width as isize - pos as isize;
                        if fitting(next, &bcmds, &mut fcmds, rem) {
                            bcmds.push(next);
                        } else {
                            bcmds.push((ind, Mode::Break, doc));
                        }
                    }
                },
                &Nest(off, ref doc) => {
                    bcmds.push((ind + off, mode, doc));
                },
                &Newline => {
                    res = out.write_str(&nl_spaces(ind));
                    pos = ind;
                },
                &Text(ref s) => {
                    res  = out.write_str(&s);
                    pos += s.len();
                },
            }
        }
    }

    res
}
<commit_msg>Fix literal suffixes<commit_after>use std::old_io as io;

pub use self::Doc::{
    Nil,
    Append,
    Group,
    Nest,
    Newline,
    Text,
};

#[inline]
fn spaces(n: usize) -> String {
    use std::iter;
    iter::repeat(' ').take(n).collect()
}

#[inline]
fn nl_spaces(n: usize) -> String {
    let mut s = String::from_str("\n");
    s.push_str(&spaces(n));
    s
}

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
enum Mode {
    Break,
    Flat,
}

#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Doc<'a> {
    Nil,
    Append(Box<Doc<'a>>, Box<Doc<'a>>),
    Group(Box<Doc<'a>>),
    Nest(usize, Box<Doc<'a>>),
    Newline,
    Text(::std::string::CowString<'a>),
}

type Cmd<'a> = (usize, Mode, &'a Doc<'a>);

#[inline]
fn fitting<'a>(
       next:          Cmd<'a>,
      bcmds: &    Vec<Cmd<'a>>,
      fcmds: &mut Vec<Cmd<'a>>,
    mut rem: isize
) -> bool {
    let mut bidx = bcmds.len();
    let mut fits = true;

    fcmds.clear();      // clear from previous calls from best
    fcmds.push(next);

    loop {
        if rem < 0 {
            fits = false;
            break;
        }
        match fcmds.pop() {
            None => {
                if bidx == 0 {
                    break;
                } else {
                    fcmds.push(bcmds[ bidx - 1 ]);
                    bidx -= 1;
                }
            },
            Some((ind, mode, doc)) => match doc {
                &Nil => {
                },
                &Append(ref ldoc, ref rdoc) => {
                    fcmds.push((ind, mode, rdoc));
                    fcmds.push((ind, mode, ldoc));
                },
                &Group(ref doc) => {
                    fcmds.push((ind, mode, doc));
                },
                &Nest(off, ref doc) => {
                    fcmds.push((ind + off, mode, doc));
                },
                &Newline => {
                    fits = true;
                },
                &Text(ref str) => {
                    rem -= str.len() as isize;
                },
            }
        }
    }

    fits
}

#[inline]
pub fn best<W: io::Writer>(
      doc: &Doc,
    width: usize,
      out: &mut W
) -> io::IoResult<()> {
    let mut res   = Ok(());
    let mut pos   = 0usize;
    let mut bcmds = vec![(0usize, Mode::Break, doc)];
    let mut fcmds = vec![];

    while res.is_ok() {
        match bcmds.pop() {
            None => {
                break;
            },
            Some((ind, mode, doc)) => match doc {
                &Nil => {
                },
                &Append(ref ldoc, ref rdoc) => {
                    bcmds.push((ind, mode, rdoc));
                    bcmds.push((ind, mode, ldoc));
                },
                &Group(ref doc) => match mode {
                    Mode::Flat => {
                        bcmds.push((ind, Mode::Flat, doc));
                    },
                    Mode::Break => {
                        let next = (ind, Mode::Flat, &**doc);
                        let rem  = width as isize - pos as isize;
                        if fitting(next, &bcmds, &mut fcmds, rem) {
                            bcmds.push(next);
                        } else {
                            bcmds.push((ind, Mode::Break, doc));
                        }
                    }
                },
                &Nest(off, ref doc) => {
                    bcmds.push((ind + off, mode, doc));
                },
                &Newline => {
                    res = out.write_str(&nl_spaces(ind));
                    pos = ind;
                },
                &Text(ref s) => {
                    res  = out.write_str(&s);
                    pos += s.len();
                },
            }
        }
    }

    res
}
<|endoftext|>


<commit_before>// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use super::*;

use cocoa::foundation::NSUInteger;

#[repr(u64)]
#[derive(Clone, Debug)]
pub enum MTLLoadAction {
    DontCare = 0,
    Load = 1,
    Clear = 2,
}

#[repr(u64)]
#[derive(Clone, Debug)]
pub enum MTLStoreAction {
    DontCare = 0,
    Store = 1,
    MultisampleResolve = 2,
    StoreAndMultisampleResolve = 3,
    Unknown = 4,
    CustomSampleDepthStore = 5,
}

#[repr(C)]
#[derive(Clone, Debug)]
pub struct MTLClearColor {
    red: f64,
    green: f64,
    blue: f64,
    alpha: f64
}

impl MTLClearColor {
    #[inline]
    pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
        MTLClearColor {
            red,
            green,
            blue,
            alpha
        }
    }
}

pub enum MTLRenderPassAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptorRef;
}

impl RenderPassAttachmentDescriptorRef {
    pub fn texture(&self) -> Option<&TextureRef> {
        unsafe {
            msg_send![self, texture]
        }
    }

    pub fn set_texture(&self, texture: Option<&TextureRef>) {
        unsafe {
            msg_send![self, setTexture:texture];
        }
    }

    pub fn level(&self) -> NSUInteger {
        unsafe {
            msg_send![self, level]
        }
    }

    pub fn set_level(&self, level: NSUInteger) {
        unsafe {
            msg_send![self, setLevel:level]
        }
    }

    pub fn slice(&self) -> NSUInteger {
        unsafe {
            msg_send![self, slice]
        }
    }

    pub fn set_slice(&self, slice: NSUInteger) {
        unsafe {
            msg_send![self, setSlice:slice]
        }
    }

    pub fn depth_plane(&self) -> NSUInteger {
        unsafe {
            msg_send![self, depthPlane]
        }
    }

    pub fn set_depth_plane(&self, depth_plane: NSUInteger) {
        unsafe {
            msg_send![self, setDepthPlane:depth_plane]
        }
    }

    pub fn resolve_texture(&self) -> Option<&TextureRef> {
        unsafe {
            msg_send![self, resolveTexture]
        }
    }

    pub fn set_resolve_texture(&self, resolve_texture: Option<&TextureRef>) {
        unsafe {
            msg_send![self, setResolveTexture:resolve_texture]
        }
    }

    pub fn resolve_level(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveLevel]
        }
    }

    pub fn set_resolve_level(&self, resolve_level: NSUInteger) {
        unsafe {
            msg_send![self, setResolveLevel:resolve_level]
        }
    }

    pub fn resolve_slice(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveSlice]
        }
    }

    pub fn set_resolve_slice(&self, resolve_slice: NSUInteger) {
        unsafe {
            msg_send![self, setResolveSlice:resolve_slice]
        }
    }

    pub fn resolve_depth_plane(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveDepthPlane]
        }
    }

    pub fn set_resolve_depth_plane(&self, resolve_depth_plane: NSUInteger) {
        unsafe {
            msg_send![self, setResolveDepthPlane:resolve_depth_plane]
        }
    }

    pub fn load_action(&self) -> MTLLoadAction {
        unsafe {
            msg_send![self, loadAction]
        }
    }

    pub fn set_load_action(&self, load_action: MTLLoadAction) {
        unsafe {
            msg_send![self, setLoadAction:load_action]
        }
    }

    pub fn store_action(&self) -> MTLStoreAction {
        unsafe {
            msg_send![self, storeAction]
        }
    }

    pub fn set_store_action(&self, store_action: MTLStoreAction) {
        unsafe {
            msg_send![self, setStoreAction:store_action]
        }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassColorAttachmentDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLRenderPassColorAttachmentDescriptor);
            msg_send![class, new]
        }
    }
}

impl RenderPassColorAttachmentDescriptorRef {
    pub fn clear_color(&self) -> MTLClearColor {
        unsafe {
            msg_send![self, clearColor]
        }
    }

    pub fn set_clear_color(&self, clear_color: MTLClearColor) {
        unsafe {
            msg_send![self, setClearColor:clear_color]
        }
    }
}

pub enum MTLRenderPassDepthAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassDepthAttachmentDescriptorRef {
    pub fn clear_depth(&self) -> f64 {
        unsafe {
            msg_send![self, clearDepth]
        }
    }

    pub fn set_clear_depth(&self, clear_depth: f64) {
        unsafe {
            msg_send![self, setClearDepth:clear_depth]
        }
    }
}

pub enum MTLRenderPassStencilAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassStencilAttachmentDescriptorRef {
    pub fn clear_stencil(&self) -> u32 {
        unsafe {
            msg_send![self, clearStencil]
        }
    }

    pub fn set_clear_stencil(&self, clear_stencil: u32) {
        unsafe {
            msg_send![self, setClearStencil:clear_stencil]
        }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptorArray {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArrayRef;
}

impl RenderPassColorAttachmentDescriptorArrayRef {
    pub fn object_at(&self, index: usize) -> Option<&RenderPassColorAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, objectAtIndexedSubscript:index]
        }
    }

    pub fn set_object_at(&self, index: usize, attachment: Option<&RenderPassColorAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setObject:attachment
                     atIndexedSubscript:index]
        }
    }
}

pub enum MTLRenderPassDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDescriptor;
    pub struct RenderPassDescriptor;
    pub struct RenderPassDescriptorRef;
}

impl RenderPassDescriptor {
    pub fn new<'a>() -> &'a RenderPassDescriptorRef {
        unsafe {
            let class = class!(MTLRenderPassDescriptorInternal);
            msg_send![class, renderPassDescriptor]
        }
    }
}

impl RenderPassDescriptorRef {
    pub fn color_attachments(&self) -> &RenderPassColorAttachmentDescriptorArrayRef {
        unsafe {
            msg_send![self, colorAttachments]
        }
    }

    pub fn depth_attachment(&self) -> Option<&RenderPassDepthAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, depthAttachment]
        }
    }

    pub fn set_depth_attachment(&self, depth_attachment: Option<&RenderPassDepthAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setDepthAttachment:depth_attachment]
        }
    }

    pub fn stencil_attachment(&self) -> Option<&RenderPassStencilAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, stencilAttachment]
        }
    }

    pub fn set_stencil_attachment(&self, stencil_attachment: Option<&RenderPassStencilAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setStencilAttachment:stencil_attachment]
        }
    }

    pub fn visibility_result_buffer(&self) -> Option<&BufferRef> {
        unsafe {
            msg_send![self, visibilityResultBuffer]
        }
    }

    pub fn set_visibility_result_buffer(&self, buffer: Option<&BufferRef>) {
        unsafe {
            msg_send![self, setVisibilityResultBuffer:buffer]
        }
    }

    pub fn render_target_array_length(&self) -> NSUInteger {
        unsafe {
            msg_send![self, renderTargetArrayLength]
        }
    }

    pub fn set_render_target_array_length(&self, length: NSUInteger) {
        unsafe {
            msg_send![self, setRenderTargetArrayLength:length]
        }
    }
}
<commit_msg>[MTLRenderPass] add enum MTLMultisampleStencilResolveFilter<commit_after>// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use super::*;

use cocoa::foundation::NSUInteger;

#[repr(u64)]
#[derive(Clone, Debug)]
pub enum MTLLoadAction {
    DontCare = 0,
    Load = 1,
    Clear = 2,
}

#[repr(u64)]
#[derive(Clone, Debug)]
pub enum MTLStoreAction {
    DontCare = 0,
    Store = 1,
    MultisampleResolve = 2,
    StoreAndMultisampleResolve = 3,
    Unknown = 4,
    CustomSampleDepthStore = 5,
}

#[repr(C)]
#[derive(Clone, Debug)]
pub struct MTLClearColor {
    red: f64,
    green: f64,
    blue: f64,
    alpha: f64
}

impl MTLClearColor {
    #[inline]
    pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
        MTLClearColor {
            red,
            green,
            blue,
            alpha
        }
    }
}

#[repr(u32)]
#[allow(non_camel_case_types)]
pub enum MTLMultisampleStencilResolveFilter {
    Sample0 = 0,
    DepthResolvedSample = 1,
}

pub enum MTLRenderPassAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptorRef;
}

impl RenderPassAttachmentDescriptorRef {
    pub fn texture(&self) -> Option<&TextureRef> {
        unsafe {
            msg_send![self, texture]
        }
    }

    pub fn set_texture(&self, texture: Option<&TextureRef>) {
        unsafe {
            msg_send![self, setTexture:texture];
        }
    }

    pub fn level(&self) -> NSUInteger {
        unsafe {
            msg_send![self, level]
        }
    }

    pub fn set_level(&self, level: NSUInteger) {
        unsafe {
            msg_send![self, setLevel:level]
        }
    }

    pub fn slice(&self) -> NSUInteger {
        unsafe {
            msg_send![self, slice]
        }
    }

    pub fn set_slice(&self, slice: NSUInteger) {
        unsafe {
            msg_send![self, setSlice:slice]
        }
    }

    pub fn depth_plane(&self) -> NSUInteger {
        unsafe {
            msg_send![self, depthPlane]
        }
    }

    pub fn set_depth_plane(&self, depth_plane: NSUInteger) {
        unsafe {
            msg_send![self, setDepthPlane:depth_plane]
        }
    }

    pub fn resolve_texture(&self) -> Option<&TextureRef> {
        unsafe {
            msg_send![self, resolveTexture]
        }
    }

    pub fn set_resolve_texture(&self, resolve_texture: Option<&TextureRef>) {
        unsafe {
            msg_send![self, setResolveTexture:resolve_texture]
        }
    }

    pub fn resolve_level(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveLevel]
        }
    }

    pub fn set_resolve_level(&self, resolve_level: NSUInteger) {
        unsafe {
            msg_send![self, setResolveLevel:resolve_level]
        }
    }

    pub fn resolve_slice(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveSlice]
        }
    }

    pub fn set_resolve_slice(&self, resolve_slice: NSUInteger) {
        unsafe {
            msg_send![self, setResolveSlice:resolve_slice]
        }
    }

    pub fn resolve_depth_plane(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveDepthPlane]
        }
    }

    pub fn set_resolve_depth_plane(&self, resolve_depth_plane: NSUInteger) {
        unsafe {
            msg_send![self, setResolveDepthPlane:resolve_depth_plane]
        }
    }

    pub fn load_action(&self) -> MTLLoadAction {
        unsafe {
            msg_send![self, loadAction]
        }
    }

    pub fn set_load_action(&self, load_action: MTLLoadAction) {
        unsafe {
            msg_send![self, setLoadAction:load_action]
        }
    }

    pub fn store_action(&self) -> MTLStoreAction {
        unsafe {
            msg_send![self, storeAction]
        }
    }

    pub fn set_store_action(&self, store_action: MTLStoreAction) {
        unsafe {
            msg_send![self, setStoreAction:store_action]
        }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassColorAttachmentDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLRenderPassColorAttachmentDescriptor);
            msg_send![class, new]
        }
    }
}

impl RenderPassColorAttachmentDescriptorRef {
    pub fn clear_color(&self) -> MTLClearColor {
        unsafe {
            msg_send![self, clearColor]
        }
    }

    pub fn set_clear_color(&self, clear_color: MTLClearColor) {
        unsafe {
            msg_send![self, setClearColor:clear_color]
        }
    }
}

pub enum MTLRenderPassDepthAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassDepthAttachmentDescriptorRef {
    pub fn clear_depth(&self) -> f64 {
        unsafe {
            msg_send![self, clearDepth]
        }
    }

    pub fn set_clear_depth(&self, clear_depth: f64) {
        unsafe {
            msg_send![self, setClearDepth:clear_depth]
        }
    }
}

pub enum MTLRenderPassStencilAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassStencilAttachmentDescriptorRef {
    pub fn clear_stencil(&self) -> u32 {
        unsafe {
            msg_send![self, clearStencil]
        }
    }

    pub fn set_clear_stencil(&self, clear_stencil: u32) {
        unsafe {
            msg_send![self, setClearStencil:clear_stencil]
        }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptorArray {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArrayRef;
}

impl RenderPassColorAttachmentDescriptorArrayRef {
    pub fn object_at(&self, index: usize) -> Option<&RenderPassColorAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, objectAtIndexedSubscript:index]
        }
    }

    pub fn set_object_at(&self, index: usize, attachment: Option<&RenderPassColorAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setObject:attachment
                     atIndexedSubscript:index]
        }
    }
}

pub enum MTLRenderPassDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDescriptor;
    pub struct RenderPassDescriptor;
    pub struct RenderPassDescriptorRef;
}

impl RenderPassDescriptor {
    pub fn new<'a>() -> &'a RenderPassDescriptorRef {
        unsafe {
            let class = class!(MTLRenderPassDescriptorInternal);
            msg_send![class, renderPassDescriptor]
        }
    }
}

impl RenderPassDescriptorRef {
    pub fn color_attachments(&self) -> &RenderPassColorAttachmentDescriptorArrayRef {
        unsafe {
            msg_send![self, colorAttachments]
        }
    }

    pub fn depth_attachment(&self) -> Option<&RenderPassDepthAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, depthAttachment]
        }
    }

    pub fn set_depth_attachment(&self, depth_attachment: Option<&RenderPassDepthAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setDepthAttachment:depth_attachment]
        }
    }

    pub fn stencil_attachment(&self) -> Option<&RenderPassStencilAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, stencilAttachment]
        }
    }

    pub fn set_stencil_attachment(&self, stencil_attachment: Option<&RenderPassStencilAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setStencilAttachment:stencil_attachment]
        }
    }

    pub fn visibility_result_buffer(&self) -> Option<&BufferRef> {
        unsafe {
            msg_send![self, visibilityResultBuffer]
        }
    }

    pub fn set_visibility_result_buffer(&self, buffer: Option<&BufferRef>) {
        unsafe {
            msg_send![self, setVisibilityResultBuffer:buffer]
        }
    }

    pub fn render_target_array_length(&self) -> NSUInteger {
        unsafe {
            msg_send![self, renderTargetArrayLength]
        }
    }

    pub fn set_render_target_array_length(&self, length: NSUInteger) {
        unsafe {
            msg_send![self, setRenderTargetArrayLength:length]
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
#![deny(warnings)]

extern crate futures;
extern crate hyper;
extern crate pretty_env_logger;
extern crate test;

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::sync::mpsc;

use futures::Future;
use futures::sync::oneshot;

use hyper::header::{ContentLength, ContentType};
use hyper::server::{self, Service};

#[bench]
fn bench_server_tcp_throughput(b: &mut test::Bencher) {
    let (_until_tx, until_rx) = oneshot::channel();
    let addr = spawn_hello(until_rx);

    let mut tcp = TcpStream::connect(addr).unwrap();
    let mut buf = [0u8; 4096];

    b.bytes = 130 + 35;
    b.iter(|| {
        tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();
        let n = tcp.read(&mut buf).unwrap();
        assert_eq!(n, 130);
    })
}

#[bench]
fn bench_raw_tcp_throughput(b: &mut test::Bencher) {
    let (tx, rx) = mpsc::channel();
    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = listener.local_addr().unwrap();
    ::std::thread::spawn(move || {
        let mut sock = listener.accept().unwrap().0;

        let mut buf = [0u8; 4096];
        while rx.try_recv().is_err() {
            sock.read(&mut buf).unwrap();
            sock.write_all(b"\
                HTTP/1.1 200 OK\r\n\
                Content-Length: 13\r\n\
                Content-Type: text/plain; charset=utf-8\r\n\
                Date: Fri, 12 May 2017 18:21:45 GMT\r\n\
                \r\n\
                Hello, World!\
            ").unwrap();
        }
    });

    let mut tcp = TcpStream::connect(addr).unwrap();
    let mut buf = [0u8; 4096];

    b.bytes = 130 + 35;
    b.iter(|| {
        tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();
        let n = tcp.read(&mut buf).unwrap();
        assert_eq!(n, 130);
    });
    tx.send(()).unwrap();
}

struct Hello;

impl Service for Hello {
    type Request = server::Request;
    type Response = server::Response;
    type Error = hyper::Error;
    type Future = ::futures::Finished<Self::Response, hyper::Error>;
    fn call(&self, _req: Self::Request) -> Self::Future {
        ::futures::finished(
            server::Response::new()
                .with_header(ContentLength("Hello, World!".len() as u64))
                .with_header(ContentType::plaintext())
                .with_body("Hello, World!")
        )
    }
}

fn spawn_hello(until: oneshot::Receiver<()>) -> SocketAddr {
    let (addr_tx, addr_rx) = mpsc::channel();
    ::std::thread::spawn(move || {
        let addr = "127.0.0.1:0".parse().unwrap();
        let srv = hyper::server::Http::new().bind(&addr, || Ok(Hello)).unwrap();
        let addr = srv.local_addr().unwrap();
        addr_tx.send(addr).unwrap();
        srv.run_until(until.map_err(|_| ())).unwrap();
    });

    addr_rx.recv().unwrap()
}
<commit_msg>test(server): add benches for TransferEncoding::chunked<commit_after>#![feature(test)]
#![deny(warnings)]

extern crate futures;
extern crate hyper;
extern crate pretty_env_logger;
extern crate test;

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::mpsc;

use futures::Future;
use futures::sync::oneshot;

use hyper::header::{ContentLength, ContentType, TransferEncoding};
use hyper::server::{self, Service};

macro_rules! bench_server {
    ($b:ident, $handler:ident, $total_bytes:expr) => {
        let (_until_tx, until_rx) = oneshot::channel();
        let addr = {
            let (addr_tx, addr_rx) = mpsc::channel();
            ::std::thread::spawn(move || {
                let addr = "127.0.0.1:0".parse().unwrap();
                let srv = hyper::server::Http::new().bind(&addr, || Ok($handler)).unwrap();
                let addr = srv.local_addr().unwrap();
                addr_tx.send(addr).unwrap();
                srv.run_until(until_rx.map_err(|_| ())).unwrap();
            });

            addr_rx.recv().unwrap()
        };

        let mut tcp = TcpStream::connect(addr).unwrap();
        let mut buf = [0u8; 8192];

        $b.bytes = 35 + $total_bytes;
        $b.iter(|| {
            tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();
            let mut sum = 0;
            while sum < $total_bytes {
                sum += tcp.read(&mut buf).unwrap();
            }
            assert_eq!(sum, $total_bytes);
        })
    }
}

#[bench]
fn bench_server_tcp_throughput_fixedsize_small_payload(b: &mut test::Bencher) {
    bench_server!(b, FixedSizeSmallPayload, 130);
}

#[bench]
fn bench_server_tcp_throughput_chunked_small_payload(b: &mut test::Bencher) {
    bench_server!(b, ChunkedSmallPayload, 148);
}

#[bench]
fn bench_server_tcp_throughput_chunked_large_payload(b: &mut test::Bencher) {
    bench_server!(b, ChunkedLargePayload, 13_000_140);
}

#[bench]
fn bench_raw_tcp_throughput_small_payload(b: &mut test::Bencher) {
    let (tx, rx) = mpsc::channel();
    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = listener.local_addr().unwrap();
    ::std::thread::spawn(move || {
        let mut sock = listener.accept().unwrap().0;

        let mut buf = [0u8; 8192];
        while rx.try_recv().is_err() {
            sock.read(&mut buf).unwrap();
            sock.write_all(b"\
                HTTP/1.1 200 OK\r\n\
                Content-Length: 13\r\n\
                Content-Type: text/plain; charset=utf-8\r\n\
                Date: Fri, 12 May 2017 18:21:45 GMT\r\n\
                \r\n\
                Hello, World!\
            ").unwrap();
        }
    });

    let mut tcp = TcpStream::connect(addr).unwrap();
    let mut buf = [0u8; 4096];

    b.bytes = 130 + 35;
    b.iter(|| {
        tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();
        let n = tcp.read(&mut buf).unwrap();
        assert_eq!(n, 130);
    });
    tx.send(()).unwrap();
}

struct FixedSizeSmallPayload;

impl Service for FixedSizeSmallPayload {
    type Request = server::Request;
    type Response = server::Response;
    type Error = hyper::Error;
    type Future = ::futures::Finished<Self::Response, hyper::Error>;
    fn call(&self, _req: Self::Request) -> Self::Future {
        ::futures::finished(
            server::Response::new()
                .with_header(ContentLength("Hello, World!".len() as u64))
                .with_header(ContentType::plaintext())
                .with_body("Hello, World!")
        )
    }
}

struct ChunkedSmallPayload;

impl Service for ChunkedSmallPayload {
    type Request = server::Request;
    type Response = server::Response;
    type Error = hyper::Error;
    type Future = ::futures::Finished<Self::Response, hyper::Error>;
    fn call(&self, _req: Self::Request) -> Self::Future {
        ::futures::finished(
            server::Response::new()
                .with_header(TransferEncoding::chunked())
                .with_header(ContentType::plaintext())
                .with_body("Hello, World!")
        )
    }
}

struct ChunkedLargePayload;

impl Service for ChunkedLargePayload {
    type Request = server::Request;
    type Response = server::Response;
    type Error = hyper::Error;
    type Future = ::futures::Finished<Self::Response, hyper::Error>;
    fn call(&self, _req: Self::Request) -> Self::Future {
        ::futures::finished(
            server::Response::new()
                .with_header(TransferEncoding::chunked())
                .with_header(ContentType::plaintext())
                .with_body((0..1_000_000).flat_map(|_| "Hello, World!".bytes()).collect::<Vec<u8>>())
        )
    }
}

<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod std;
extern mod extra;

use extra::test::{TestOpts, run_tests_console, TestDesc, TestDescAndFn, DynTestFn, DynTestName};
use extra::getopts::{getopts, reqopt};
use std::{os, run, str};
use std::cell::Cell;
use std::os::list_dir_path;

#[deriving(Clone)]
struct Config {
    source_dir: ~str,
    filter: Option<~str>
}

fn main() {
    let args = os::args();
    let config = parse_config(args);
    let opts = test_options(config.clone());
    let tests = find_tests(config);
    if !run_tests_console(&opts, tests) {
        os::set_exit_status(1);
    }
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt("source-dir")];
    let matches = match getopts(args, opts) {
      Ok(m) => m,
      Err(f) => fail!(f.to_err_msg())
    };

    Config {
        source_dir: matches.opt_str("source-dir").unwrap(),
        filter: if matches.free.is_empty() {
            None
        } else {
            Some((*matches.free.head()).clone())
        }
    }
}

fn test_options(config: Config) -> TestOpts {
    TestOpts {
        filter: config.filter,
        run_ignored: false,
        run_tests: true,
        run_benchmarks: false,
        ratchet_metrics: None,
        ratchet_noise_percent: None,
        save_metrics: None,
        test_shard: None,
        logfile: None
    }
}

fn find_tests(config: Config) -> ~[TestDescAndFn] {
    let mut files = list_dir_path(&Path::new(config.source_dir));
    // FIXME (#1094): not the right way to transform a path
    files.retain( |file| file.display().to_str().ends_with(".html") );
    return files.map(|file| make_test(file.display().to_str()) );
}

fn make_test(file: ~str) -> TestDescAndFn {
    let f = Cell::new(file.clone());
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(file),
            ignore: false,
            should_fail: false
        },
        testfn: DynTestFn(|| { run_test(f.take()) })
    }
}

fn run_test(file: ~str) {
    let path = os::make_absolute(&Path::new(file));
    // FIXME (#1094): not the right way to transform a path
    let infile = ~"file://" + path.display().to_str();
    let res = run::process_output("./servo", [~"-z", infile]);
    let out = str::from_utf8(res.output);
    print(out);
    let lines: ~[&str] = out.split_iter('\n').collect();
    for &line in lines.iter() {
        if line.contains("TEST-UNEXPECTED-FAIL") {
            fail!(line);
        }
    }
}
<commit_msg>Display live stdout from content tests.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod std;
extern mod extra;

use extra::test::{TestOpts, run_tests_console, TestDesc, TestDescAndFn, DynTestFn, DynTestName};
use extra::getopts::{getopts, reqopt};
use std::{os, str};
use std::cell::Cell;
use std::os::list_dir_path;
use std::rt::io::Reader;
use std::rt::io::process::{Process, ProcessConfig, Ignored, CreatePipe};

#[deriving(Clone)]
struct Config {
    source_dir: ~str,
    filter: Option<~str>
}

fn main() {
    let args = os::args();
    let config = parse_config(args);
    let opts = test_options(config.clone());
    let tests = find_tests(config);
    if !run_tests_console(&opts, tests) {
        os::set_exit_status(1);
    }
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt("source-dir")];
    let matches = match getopts(args, opts) {
      Ok(m) => m,
      Err(f) => fail!(f.to_err_msg())
    };

    Config {
        source_dir: matches.opt_str("source-dir").unwrap(),
        filter: if matches.free.is_empty() {
            None
        } else {
            Some((*matches.free.head()).clone())
        }
    }
}

fn test_options(config: Config) -> TestOpts {
    TestOpts {
        filter: config.filter,
        run_ignored: false,
        run_tests: true,
        run_benchmarks: false,
        ratchet_metrics: None,
        ratchet_noise_percent: None,
        save_metrics: None,
        test_shard: None,
        logfile: None
    }
}

fn find_tests(config: Config) -> ~[TestDescAndFn] {
    let mut files = list_dir_path(&Path::new(config.source_dir));
    // FIXME (#1094): not the right way to transform a path
    files.retain( |file| file.display().to_str().ends_with(".html") );
    return files.map(|file| make_test(file.display().to_str()) );
}

fn make_test(file: ~str) -> TestDescAndFn {
    let f = Cell::new(file.clone());
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(file),
            ignore: false,
            should_fail: false
        },
        testfn: DynTestFn(|| { run_test(f.take()) })
    }
}

fn run_test(file: ~str) {
    let path = os::make_absolute(&Path::new(file));
    // FIXME (#1094): not the right way to transform a path
    let infile = ~"file://" + path.display().to_str();
    let create_pipe = CreatePipe(true, false); // rustc #10228

    let config = ProcessConfig {
        program: "./servo",
        args: [~"-z", infile.clone()],
        env: None,
        cwd: None,
        io: [Ignored, create_pipe, Ignored]
    };

    let mut prc = Process::new(config).unwrap();
    let stdout = prc.io[1].get_mut_ref();
    let mut output = ~[];
    loop {
        let byte = stdout.read_byte();
        match byte {
            Some(byte) => {
                print!("{}", byte as char);
                output.push(byte);
            }
            None => break
        }
    }

    let out = str::from_utf8(output);
    let lines: ~[&str] = out.split_iter('\n').collect();
    for &line in lines.iter() {
        if line.contains("TEST-UNEXPECTED-FAIL") {
            fail!(line);
        }
    }
}
<|endoftext|>


<commit_before>//! `StructureStorage` data description.
use crate::data::RoomName;
use crate::websocket::types::room::resources::ResourceType;
use crate::websocket::types::room::resources::Store;

with_base_fields_and_update_struct! {
    /// A storage structure - a structure that has a large capacity for storing multiple resources,
    /// and does not decay over time.
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureStorage {
        /// The current number of hit-points this structure has.
        #[serde(default)]
        pub hits: i32,
        /// The maximum number of hit-points this structure has.
        #[serde(default)]
        pub hits_max: i32,
        /// The user ID of the owner of this structure.
        pub user: String,
        /// Whether or not this structure is non-functional due to a degraded controller.
        #[serde(default, rename = "off")]
        pub disabled: bool,
        /// Total capacity for this structure.
        #[serde(rename = "energyCapacity")]
        pub capacity: i32,
        /// Whether or not an attack on this structure will send an email to the owner automatically.
        pub notify_when_attacked: bool,
        /// The resources and amounts of each resource some game object holds.
        pub store: Store,
    }

    /// The update structure for an extension structure.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureStorageUpdate {
        - hits: i32,
        - hits_max: i32,
        - user: String,
        #[serde(rename = "off")]
        - disabled: bool,
        #[serde(rename = "storeCapacity")]
        - capacity: i32,
        - notify_when_attacked: bool,
        - store: Store,
    }
}

impl StructureStorage {
    /// Iterates over this structure's resources.
    pub fn resources(&self) -> impl Iterator<Item = (ResourceType, i32)> + '_ {
        self.store.iter()
    }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;

    use super::StructureStorage;
    use crate::websocket::types::room::resources::ResourceType;

    #[test]
    fn parse_storage() {
        let json = json!({
            "GO": 0,
            "KO": 0,
            "O": 0,
            "U": 33581,
            "XGHO2": 5400,
            "XKHO2": 4249,
            "XLHO2": 2554,
            "XZH2O": 2660,
            "ZH": 0,
            "_id": "57f376603bbada4a68f0135c",
            "energy": 631112,
            "energyCapacity": 1000000,
            "hits": 10000,
            "hitsMax": 10000,
            "notifyWhenAttacked": true,
            "room": "E17N55",
            "type": "storage",
            "user": "57874d42d0ae911e3bd15bbc",
            "x": 7,
            "y": 16
        });

        let obj = StructureStorage::deserialize(json).unwrap();

        match obj {
            StructureStorage {
                capacity: 1000000,
                hits: 10000,
                hits_max: 10000,
                notify_when_attacked: true,
                x: 7,
                y: 16,
                ref store,
                ..
            } if *store
                == store! { Energy: 631112, Utrium: 33581, CatalyzedGhodiumAlkalide: 5400 } =>
            {
                ()
            }
            other => panic!(
                "expected pre-set StructureStorage to match, found {:#?}",
                other
            ),
        }

        assert_eq!(
            {
                let mut contents = obj.resources().collect::<Vec<_>>();
                contents.sort();
                contents
            },
            {
                let mut expected = vec![
                    (ResourceType::Utrium, 33581),
                    (ResourceType::CatalyzedGhodiumAlkalide, 5400),
                    (ResourceType::CatalyzedKeaniumAlkalide, 4249),
                    (ResourceType::CatalyzedLemergiumAlkalide, 2554),
                    (ResourceType::CatalyzedZynthiumAcid, 2660),
                    (ResourceType::Energy, 631112),
                ];
                expected.sort();
                expected
            }
        );
    }
}
<commit_msg>Fix StructureStorage deserializing & tests<commit_after>//! `StructureStorage` data description.
use crate::data::RoomName;
use crate::websocket::types::room::resources::ResourceType;
use crate::websocket::types::room::resources::Store;

with_base_fields_and_update_struct! {
    /// A storage structure - a structure that has a large capacity for storing multiple resources,
    /// and does not decay over time.
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureStorage {
        /// The current number of hit-points this structure has.
        #[serde(default)]
        pub hits: i32,
        /// The maximum number of hit-points this structure has.
        #[serde(default)]
        pub hits_max: i32,
        /// The user ID of the owner of this structure.
        pub user: String,
        /// Whether or not this structure is non-functional due to a degraded controller.
        #[serde(default, rename = "off")]
        pub disabled: bool,
        /// Total capacity for this structure.
        #[serde(rename = "storeCapacity")]
        pub capacity: i32,
        /// Whether or not an attack on this structure will send an email to the owner automatically.
        pub notify_when_attacked: bool,
        /// The resources and amounts of each resource some game object holds.
        pub store: Store,
    }

    /// The update structure for an extension structure.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureStorageUpdate {
        - hits: i32,
        - hits_max: i32,
        - user: String,
        #[serde(rename = "off")]
        - disabled: bool,
        #[serde(rename = "storeCapacity")]
        - capacity: i32,
        - notify_when_attacked: bool,
        - store: Store,
    }
}

impl StructureStorage {
    /// Iterates over this structure's resources.
    pub fn resources(&self) -> impl Iterator<Item = (ResourceType, i32)> + '_ {
        self.store.iter()
    }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;

    use super::StructureStorage;

    #[test]
    fn parse_storage() {
        let json = json!({
            "_id": "599ca7f2e48c09254b443791",
            "hits": 10000,
            "hitsMax": 10000,
            "notifyWhenAttacked": true,
            "room": "W39N49",
            "store": {
                "energy": 913026
            },
            "storeCapacity": 1000000,
            "type": "storage",
            "user": "5788389e3fd9069e6b546e2d",
            "x": 6,
            "y": 13
        });

        let obj = StructureStorage::deserialize(json).unwrap();

        match obj {
            StructureStorage {
                capacity: 1000000,
                hits: 10000,
                hits_max: 10000,
                notify_when_attacked: true,
                x: 6,
                y: 13,
                ref store,
                ..
            } if *store
                == store! { Energy: 913026 } =>
            {
                ()
            }
            other => panic!(
                "expected pre-set StructureStorage to match, found {:#?}",
                other
            ),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This is the developer documentation of Oak, if you do not intend to contribute, please read the [user manual](http://hyc.io/oak) instead. This library proposes a syntax extension for a parser generator based on [Parsing Expression Grammar (PEG)](https://en.wikipedia.org/wiki/Parsing_expression_grammar). It aims at simplifying the construction of the AST by typing the parsing rules. This is an experimental library.

#![feature(convert, rustc_private, plugin_registrar, quote, box_syntax, vec_push_all, drain, str_escape)]
#![crate_name = "oak"]

extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;

use front::parser;

mod ast;
mod front;
mod middle;
mod back;
mod rust;
mod identifier;
mod monad;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
  reg.register_syntax_extension(
    rust::token::intern("grammar"),
    rust::SyntaxExtension::IdentTT(Box::new(expand), None, false));
}

fn expand<'cx>(cx: &'cx mut rust::ExtCtxt, _sp: rust::Span, grammar_name: rust::Ident,
  tts: Vec<rust::TokenTree>) -> Box<rust::MacResult + 'cx>
{
  parse(cx, grammar_name, tts)
}

fn abort_if_errors(cx: &rust::ExtCtxt) {
  cx.parse_sess.span_diagnostic.handler.abort_if_errors();
}

fn parse<'cx>(cx: &'cx mut rust::ExtCtxt, grammar_name: rust::Ident,
  tts: Vec<rust::TokenTree>) -> Box<rust::MacResult + 'cx>
{
  let mut parser = parser::Parser::new(cx.parse_sess(), cx.cfg(), tts, grammar_name);
  let ast = parser.parse_grammar();
  abort_if_errors(cx);
  let cx: &'cx rust::ExtCtxt = cx;
  middle::analyse(cx, ast)
    .and_next(|ast| back::compile(cx, ast))
    .unwrap_or_else(|| {
      abort_if_errors(cx);
      rust::DummyResult::any(rust::DUMMY_SP)
    })
}
<commit_msg>[Macros] Allow unstable items in macro. Rational: We are already using a lot of unstable features, we will revised this when procedural macros will be stabilized.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This is the developer documentation of Oak, if you do not intend to contribute, please read the [user manual](http://hyc.io/oak) instead. This library proposes a syntax extension for a parser generator based on [Parsing Expression Grammar (PEG)](https://en.wikipedia.org/wiki/Parsing_expression_grammar). It aims at simplifying the construction of the AST by typing the parsing rules. This is an experimental library.

#![feature(convert, rustc_private, plugin_registrar, quote, box_syntax, vec_push_all, drain, str_escape)]
#![crate_name = "oak"]

extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;

use front::parser;

mod ast;
mod front;
mod middle;
mod back;
mod rust;
mod identifier;
mod monad;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
  reg.register_syntax_extension(
    rust::token::intern("grammar"),
    rust::SyntaxExtension::IdentTT(Box::new(expand), None, true));
}

fn expand<'cx>(cx: &'cx mut rust::ExtCtxt, _sp: rust::Span, grammar_name: rust::Ident,
  tts: Vec<rust::TokenTree>) -> Box<rust::MacResult + 'cx>
{
  parse(cx, grammar_name, tts)
}

fn abort_if_errors(cx: &rust::ExtCtxt) {
  cx.parse_sess.span_diagnostic.handler.abort_if_errors();
}

fn parse<'cx>(cx: &'cx mut rust::ExtCtxt, grammar_name: rust::Ident,
  tts: Vec<rust::TokenTree>) -> Box<rust::MacResult + 'cx>
{
  let mut parser = parser::Parser::new(cx.parse_sess(), cx.cfg(), tts, grammar_name);
  let ast = parser.parse_grammar();
  abort_if_errors(cx);
  let cx: &'cx rust::ExtCtxt = cx;
  middle::analyse(cx, ast)
    .and_next(|ast| back::compile(cx, ast))
    .unwrap_or_else(|| {
      abort_if_errors(cx);
      rust::DummyResult::any(rust::DUMMY_SP)
    })
}
<|endoftext|>


<commit_before>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(decl_macro)]

//extern crate holyjit_plugin;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_plugin;
extern crate rustc_trans_utils;
extern crate rustc_mir;
extern crate syntax;

extern crate holyjit_plugin;

use rustc_mir::transform::dump_mir;
use rustc::hir::def_id::DefId;
use rustc::mir::Mir;
use rustc::ty::TyCtxt;
use rustc::ty::maps::Providers;
use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_trans_utils::trans_crate::TransCrate;
use rustc::session::{config, Session};
use rustc::session::config::{ErrorOutputType, Input};
use std::path::PathBuf;
use syntax::ast;
use std::env;
use std::process::Command;
use rustc_mir::transform::{MirPass, MirSource};

struct HolyJitCompilerCalls {
    default: RustcDefaultCalls,

    // Whether we should instrument or not the code with HolyJIT.
    add_jit: bool,
}

impl HolyJitCompilerCalls {
    fn new(add_jit: bool) -> Self {
        Self {
            default: RustcDefaultCalls,
            add_jit,
        }
    }
}

impl<'a> CompilerCalls<'a> for HolyJitCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default
            .early_callback(matches, sopts, cfg, descriptions, output)
    }

    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default
            .no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }

    fn late_callback(
        &mut self,
        trans_crate: &TransCrate,
        matches: &getopts::Matches,
        sess: &Session,
        crate_stores: &rustc::middle::cstore::CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default
            .late_callback(trans_crate, matches, sess, crate_stores, input, odir, ofile)
    }

    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
        let mut controller = self.default.build_controller(sess, matches);

        // Extend rustc default driver, with the extra pass provided by the
        // holyjit driver. This extra pass is registered at the end of the
        // optimization made on the Mir, such that we have a desugared version
        // of Rust before it goes into the trans phase.
        if self.add_jit {
            // nbp-note: controller.provide_extern = ?
            //   https://github.com/rust-lang/rust/blob/1670a532dd769763f1d6ad9e5d624ec31361a098/src/librustc_driver/driver.rs#L1003

            // https://github.com/rust-lang/rust/blob/1670a532dd769763f1d6ad9e5d624ec31361a098/src/librustc_driver/driver.rs#L328
            //
            // controller.provide = box |providers| providers.optimized_mir = |tcx, def_id| { let mut mir = transform::optimized_mir(tcx, def_id).clone(); /* mutate mir */ tcx.alloc_mir(mir) };

            // instead of transform::optimized_mir...
            //   let mut p = ty::maps::Providers::default(); driver::default_provide(&mut p); (p.optimized_mir)(tcx, def_id)
            let old_provide = std::mem::replace(&mut controller.provide, box |_| {});
            controller.provide = box (move |providers| {
                old_provide(providers);
                // Note: this erases the default one, but we re-create the
                // default Provider within optimized_mir function in order to
                // execute all other optimization passes.
                *providers = Providers {
                    optimized_mir,
                    ..*providers
                };
            });
        }

        controller
    }
}

pub macro run_passes($tcx:ident, $mir:ident, $def_id:ident, $suite_index:expr; $($pass:expr,)*) {{
    let suite_index: usize = $suite_index;
    let run_passes = |mir: &mut _, promoted| {
        let source = MirSource {
            def_id: $def_id,
            promoted
        };
        let mut index = 0;
        let mut run_pass = |pass: &MirPass| {
            let run_hooks = |mir: &_, index, is_after| {
                dump_mir::on_mir_pass($tcx, &format_args!("{:03}-{:03}", suite_index, index),
                                      &pass.name(), source, mir, is_after);
            };
            run_hooks(mir, index, false);
            pass.run_pass($tcx, source, mir);
            run_hooks(mir, index, true);

            index += 1;
        };
        $(run_pass(&$pass);)*
    };

    run_passes(&mut $mir, None);

    for (index, promoted_mir) in $mir.promoted.iter_enumerated_mut() {
        run_passes(promoted_mir, Some(index));

        // Let's make sure we don't miss any nested instances
        assert!(promoted_mir.promoted.is_empty());
    }
}}

fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> {
    let mut p = Providers::default();
    driver::default_provide(&mut p);
    let optmir = p.optimized_mir;
    let mut mir = optmir(tcx, def_id).clone();
    // TODO
    run_passes![tcx, mir, def_id, 3;
        holyjit_plugin::AttachFnGraphOnCst,
    ];
    tcx.alloc_mir(mir)
}

fn extract_sysroot() -> String {
    // If we attempt to compile without a sysroot, then the core library would
    // not be found which would prevent the compilation of some crates. This
    // code is a work-around which either relies on the environment variables,
    // or on the original rustc compiler to extra the sysroot path.
    option_env!("SYSROOT")
        .map(String::from)
        .or_else(|| env::var("SYSROOT").ok())
        .or_else(|| {
            let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
            let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
            home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain)))
        })
        .or_else(|| {
            Command::new("rustc")
                .arg("--print")
                .arg("sysroot")
                .output()
                .ok()
                .and_then(|out| String::from_utf8(out.stdout).ok())
                .map(|s| s.trim().to_owned())
        })
        .expect("need to specify SYSROOT env var during holyjit compilation, or use rustup or multirust")
}

pub fn main() {
    let mut args: Vec<String> = env::args().collect();

    // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
    // We're invoking the compiler programmatically, so we ignore this.
    if args.len() <= 1 {
        std::process::exit(1);
    }
    if args[1] == "rustc" {
        // we still want to be able to invoke it normally though
        args.remove(1);
    }

    let args = if args.iter().any(|s| s == "--sysroot") {
        // User provides the --sysroot on the command line.
        args
    } else {
        // HolyJit provide the --sysroot from the environment or extracted from
        // rustc.
        args.into_iter()
            .chain(Some("--sysroot".to_owned()))
            .chain(Some(extract_sysroot()))
            .collect()
    };

    let holyjit_enabled = true;
    let mut holyjit_cc = HolyJitCompilerCalls::new(holyjit_enabled);
    rustc_driver::run(move || {
        rustc_driver::run_compiler(&args, &mut holyjit_cc, None, None)
    });
}
<commit_msg>Use the run_passes macro from rustc_mir::transform.<commit_after>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(decl_macro)]

//extern crate holyjit_plugin;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_plugin;
extern crate rustc_trans_utils;
extern crate rustc_mir;
extern crate syntax;

extern crate holyjit_plugin;

use rustc::hir::def_id::DefId;
use rustc::mir::Mir;
use rustc::ty::TyCtxt;
use rustc::ty::maps::Providers;
use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_trans_utils::trans_crate::TransCrate;
use rustc::session::{config, Session};
use rustc::session::config::{ErrorOutputType, Input};
use std::path::PathBuf;
use syntax::ast;
use std::env;
use std::process::Command;
use rustc_mir::transform::run_passes;

struct HolyJitCompilerCalls {
    default: RustcDefaultCalls,

    // Whether we should instrument or not the code with HolyJIT.
    add_jit: bool,
}

impl HolyJitCompilerCalls {
    fn new(add_jit: bool) -> Self {
        Self {
            default: RustcDefaultCalls,
            add_jit,
        }
    }
}

impl<'a> CompilerCalls<'a> for HolyJitCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default
            .early_callback(matches, sopts, cfg, descriptions, output)
    }

    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default
            .no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }

    fn late_callback(
        &mut self,
        trans_crate: &TransCrate,
        matches: &getopts::Matches,
        sess: &Session,
        crate_stores: &rustc::middle::cstore::CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default
            .late_callback(trans_crate, matches, sess, crate_stores, input, odir, ofile)
    }

    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
        let mut controller = self.default.build_controller(sess, matches);

        // Extend rustc default driver, with the extra pass provided by the
        // holyjit driver. This extra pass is registered at the end of the
        // optimization made on the Mir, such that we have a desugared version
        // of Rust before it goes into the trans phase.
        if self.add_jit {
            // nbp-note: controller.provide_extern = ?
            //   https://github.com/rust-lang/rust/blob/1670a532dd769763f1d6ad9e5d624ec31361a098/src/librustc_driver/driver.rs#L1003

            // https://github.com/rust-lang/rust/blob/1670a532dd769763f1d6ad9e5d624ec31361a098/src/librustc_driver/driver.rs#L328
            //
            // controller.provide = box |providers| providers.optimized_mir = |tcx, def_id| { let mut mir = transform::optimized_mir(tcx, def_id).clone(); /* mutate mir */ tcx.alloc_mir(mir) };

            // instead of transform::optimized_mir...
            //   let mut p = ty::maps::Providers::default(); driver::default_provide(&mut p); (p.optimized_mir)(tcx, def_id)
            let old_provide = std::mem::replace(&mut controller.provide, box |_| {});
            controller.provide = box (move |providers| {
                old_provide(providers);
                // Note: this erases the default one, but we re-create the
                // default Provider within optimized_mir function in order to
                // execute all other optimization passes.
                *providers = Providers {
                    optimized_mir,
                    ..*providers
                };
            });
        }

        controller
    }
}

fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> {
    let mut p = Providers::default();
    driver::default_provide(&mut p);
    let optmir = p.optimized_mir;
    let mut mir = optmir(tcx, def_id).clone();
    // TODO
    run_passes![tcx, mir, def_id, 3;
        holyjit_plugin::AttachFnGraphOnCst,
    ];
    tcx.alloc_mir(mir)
}

fn extract_sysroot() -> String {
    // If we attempt to compile without a sysroot, then the core library would
    // not be found which would prevent the compilation of some crates. This
    // code is a work-around which either relies on the environment variables,
    // or on the original rustc compiler to extra the sysroot path.
    option_env!("SYSROOT")
        .map(String::from)
        .or_else(|| env::var("SYSROOT").ok())
        .or_else(|| {
            let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
            let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
            home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain)))
        })
        .or_else(|| {
            Command::new("rustc")
                .arg("--print")
                .arg("sysroot")
                .output()
                .ok()
                .and_then(|out| String::from_utf8(out.stdout).ok())
                .map(|s| s.trim().to_owned())
        })
        .expect("need to specify SYSROOT env var during holyjit compilation, or use rustup or multirust")
}

pub fn main() {
    let mut args: Vec<String> = env::args().collect();

    // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
    // We're invoking the compiler programmatically, so we ignore this.
    if args.len() <= 1 {
        std::process::exit(1);
    }
    if args[1] == "rustc" {
        // we still want to be able to invoke it normally though
        args.remove(1);
    }

    let args = if args.iter().any(|s| s == "--sysroot") {
        // User provides the --sysroot on the command line.
        args
    } else {
        // HolyJit provide the --sysroot from the environment or extracted from
        // rustc.
        args.into_iter()
            .chain(Some("--sysroot".to_owned()))
            .chain(Some(extract_sysroot()))
            .collect()
    };

    let holyjit_enabled = true;
    let mut holyjit_cc = HolyJitCompilerCalls::new(holyjit_enabled);
    rustc_driver::run(move || {
        rustc_driver::run_compiler(&args, &mut holyjit_cc, None, None)
    });
}
<|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/.

// Code to handle the backing store of a pool.

use std::collections::HashMap;
use std::path::{Path, PathBuf};

use chrono::{DateTime, Utc};

use devicemapper::{DM, Device, DmDevice, LinearDev, Sectors};

use super::super::super::engine::BlockDev;
use super::super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::super::types::{DevUuid, PoolUuid};

use super::super::dmnames::{CacheRole, format_backstore_ids};
use super::super::serde_structs::{BackstoreSave, Recordable};

use super::blockdevmgr::{BlkDevSegment, BlockDevMgr, Segment, coalesce_blkdevsegs, map_to_dm};
use super::setup::get_blockdevs;

/// Handles the lowest level, base layer of this tier.
/// The dm_device organizes all block devs into a single linear allocation
/// pool. This structure can allocate additional space to the upper layer,
/// but it cannot accept returned space. When it is extended to be able to
/// accept returned space the allocation algorithm will have to be revised.
/// All available sectors on blockdevs in the manager are allocated to
/// dm_device.
#[derive(Debug)]
struct DataTier {
    /// Manages the individual block devices
    /// it is always the case block_mgr.avail_space() == 0.
    block_mgr: BlockDevMgr,
    /// The device mapper device which aggregates block_mgr's devices
    dm_device: LinearDev,
    /// The list of segments granted by block_mgr and used by dm_device
    segments: Vec<BlkDevSegment>,
    /// The position from which requested space is allocated
    next: Sectors,
}

impl DataTier {
    /// Setup a previously existing data layer from the block_mgr and
    /// previously allocated segments. There is a possibility that the
    /// size of some blockdev has changed for the bigger since the last time
    /// its metadata was recorded, so allocate any unallocated segments that
    /// might have resulted from this.
    /// WARNING: metadata changing event
    pub fn setup(dm: &DM,
                 block_mgr: BlockDevMgr,
                 segments: &[(DevUuid, Sectors, Sectors)],
                 next: Sectors)
                 -> EngineResult<DataTier> {
        if block_mgr.avail_space() != Sectors(0) {
            let err_msg = format!("{} unallocated to device; probable metadata corruption",
                                  block_mgr.avail_space());
            return Err(EngineError::Engine(ErrorEnum::Error, err_msg));
        }

        let uuid_to_devno = block_mgr.uuid_to_devno();
        let mapper = |triple: &(DevUuid, Sectors, Sectors)| -> EngineResult<BlkDevSegment> {
            let device = uuid_to_devno(triple.0)
                .ok_or_else(|| {
                                EngineError::Engine(ErrorEnum::NotFound,
                                                    format!("missing device for UUUD {:?}",
                                                            &triple.0))
                            })?;
            Ok(BlkDevSegment::new(triple.0, Segment::new(device, triple.1, triple.2)))
        };
        let segments = segments
            .iter()
            .map(&mapper)
            .collect::<EngineResult<Vec<_>>>()?;

        let (dm_name, dm_uuid) = format_backstore_ids(block_mgr.pool_uuid(), CacheRole::OriginSub);
        let ld = LinearDev::setup(dm, &dm_name, Some(&dm_uuid), map_to_dm(&segments))?;

        Ok(DataTier {
               block_mgr,
               dm_device: ld,
               segments,
               next,
           })
    }

    /// Setup a new DataTier struct from the block_mgr.
    /// WARNING: metadata changing event
    pub fn new(dm: &DM, mut block_mgr: BlockDevMgr) -> EngineResult<DataTier> {
        let avail_space = block_mgr.avail_space();
        let segments = block_mgr
            .alloc_space(&[avail_space])
            .expect("asked for exactly the space available, must get")
            .iter()
            .flat_map(|s| s.iter())
            .cloned()
            .collect::<Vec<_>>();
        let (dm_name, dm_uuid) = format_backstore_ids(block_mgr.pool_uuid(), CacheRole::OriginSub);
        let ld = LinearDev::setup(dm, &dm_name, Some(&dm_uuid), map_to_dm(&segments))?;
        Ok(DataTier {
               block_mgr,
               dm_device: ld,
               segments,
               next: Sectors(0),
           })
    }

    /// Add the given paths to self. Return UUIDs of the new blockdevs
    /// corresponding to the specified paths.
    /// WARNING: metadata changing event
    pub fn add(&mut self, dm: &DM, paths: &[&Path], force: bool) -> EngineResult<Vec<DevUuid>> {
        let uuids = self.block_mgr.add(paths, force)?;

        let avail_space = self.block_mgr.avail_space();
        let segments = self.block_mgr
            .alloc_space(&[avail_space])
            .expect("asked for exactly the space available, must get")
            .iter()
            .flat_map(|s| s.iter())
            .cloned()
            .collect::<Vec<_>>();
        let coalesced = coalesce_blkdevsegs(&self.segments, &segments);

        self.dm_device.set_table(dm, map_to_dm(&coalesced))?;

        self.segments = coalesced;

        Ok(uuids)
    }

    /// All the sectors available to this device
    pub fn capacity(&self) -> Sectors {
        let size = self.dm_device.size();
        assert_eq!(self.segments
                       .iter()
                       .map(|x| x.segment.length)
                       .sum::<Sectors>(),
                   size);
        size
    }

    /// The total size of all the blockdevs combined
    pub fn current_capacity(&self) -> Sectors {
        let size = self.block_mgr.current_capacity();
        assert_eq!(size - self.metadata_size(), self.capacity());
        size
    }

    /// Number of sectors unused
    pub fn available(&self) -> Sectors {
        self.capacity() - self.next
    }

    /// The number of sectors used for metadata by all the blockdevs
    pub fn metadata_size(&self) -> Sectors {
        self.block_mgr.metadata_size()
    }

    /// Allocate requested chunks from device.
    /// Returns None if it is not possible to satisfy the request.
    /// Each segment allocated is contiguous with its neighbors in the return
    /// vector.
    /// WARNING: All this must change when it becomes possible to return
    /// sectors to the store.
    /// WARNING: metadata changing event
    pub fn alloc_space(&mut self, sizes: &[Sectors]) -> Option<Vec<Vec<(Sectors, Sectors)>>> {
        if self.available() < sizes.iter().cloned().sum() {
            return None;
        }

        let mut chunks = Vec::new();
        for size in sizes {
            chunks.push(vec![(self.next, *size)]);
            self.next += *size;
        }
        Some(chunks)
    }

    /// Destroy the store. Teardown its DM devices and wipe its blockdevs.
    pub fn destroy(self, dm: &DM) -> EngineResult<()> {
        self.dm_device.teardown(dm)?;
        self.block_mgr.destroy_all()
    }
}

#[derive(Debug)]
pub struct Backstore {
    data_tier: DataTier,
}

impl Backstore {
    /// Make a Backstore object from blockdevs that already belong to Stratis.
    /// WARNING: metadata changing event
    pub fn setup(dm: &DM,
                 pool_uuid: PoolUuid,
                 backstore_save: &BackstoreSave,
                 devnodes: &HashMap<Device, PathBuf>,
                 last_update_time: Option<DateTime<Utc>>)
                 -> EngineResult<Backstore> {
        let blockdevs = get_blockdevs(pool_uuid, backstore_save, devnodes)?;
        let block_mgr = BlockDevMgr::new(pool_uuid, blockdevs, last_update_time);
        Ok(Backstore {
               data_tier: DataTier::setup(dm,
                                          block_mgr,
                                          &backstore_save.segments,
                                          backstore_save.next)?,
           })
    }

    /// Initialize a Backstore object, by initializing the specified devs.
    /// WARNING: metadata changing event
    pub fn initialize(dm: &DM,
                      pool_uuid: PoolUuid,
                      paths: &[&Path],
                      mda_size: Sectors,
                      force: bool)
                      -> EngineResult<Backstore> {
        Ok(Backstore {
               data_tier: DataTier::new(dm,
                                        BlockDevMgr::initialize(pool_uuid,
                                                                paths,
                                                                mda_size,
                                                                force)?)?,
           })
    }

    /// Add the given paths to self. Return UUIDs of the new blockdevs
    /// corresponding to the specified paths.
    /// WARNING: metadata changing event
    pub fn add(&mut self, dm: &DM, paths: &[&Path], force: bool) -> EngineResult<Vec<DevUuid>> {
        self.data_tier.add(dm, paths, force)
    }

    /// Allocate space from the underlying device.
    /// WARNING: metadata changing event
    pub fn alloc_space(&mut self, sizes: &[Sectors]) -> Option<Vec<Vec<(Sectors, Sectors)>>> {
        self.data_tier.alloc_space(sizes)
    }

    /// Return a reference to the blockdevs that form the basis of the
    /// backstore.
    pub fn blockdevs(&self) -> Vec<(DevUuid, &BlockDev)> {
        self.data_tier.block_mgr.blockdevs()
    }

    /// The current capacity of all the blockdevs that make up the backstore.
    pub fn current_capacity(&self) -> Sectors {
        self.data_tier.current_capacity()
    }

    /// Destroy the entire store.
    pub fn destroy(self, dm: &DM) -> EngineResult<()> {
        self.data_tier.destroy(dm)
    }

    /// Return the device that this tier is currently using.
    /// WARNING: This may change it the backstore switches between its
    /// cache and its non-cache incarnations, among other reasons.
    pub fn device(&self) -> Device {
        self.data_tier.dm_device.device()
    }

    /// Lookup an immutable blockdev by its Stratis UUID.
    pub fn get_blockdev_by_uuid(&self, uuid: DevUuid) -> Option<&BlockDev> {
        self.data_tier.block_mgr.get_blockdev_by_uuid(uuid)
    }

    /// Lookup a mutable blockdev by its Stratis UUID.
    pub fn get_mut_blockdev_by_uuid(&mut self, uuid: DevUuid) -> Option<&mut BlockDev> {
        self.data_tier.block_mgr.get_mut_blockdev_by_uuid(uuid)
    }

    /// The number of sectors in the backstore given up to Stratis
    /// metadata.
    pub fn metadata_size(&self) -> Sectors {
        self.data_tier.metadata_size()
    }

    /// Write the given data directly to the blockdevs that make up the
    /// backstore. This action bypasses the DM device entirely,
    /// in order to allow control over which blockdevs the metadata is written
    /// to.
    pub fn save_state(&mut self, metadata: &[u8]) -> EngineResult<()> {
        self.data_tier.block_mgr.save_state(metadata)
    }
}

impl Recordable<BackstoreSave> for Backstore {
    fn record(&self) -> BackstoreSave {
        BackstoreSave {
            segments: self.data_tier.segments.record(),
            block_devs: self.data_tier.block_mgr.record(),
            next: self.data_tier.next,
        }
    }
}
<commit_msg>Remove an obsoleted comment<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/.

// Code to handle the backing store of a pool.

use std::collections::HashMap;
use std::path::{Path, PathBuf};

use chrono::{DateTime, Utc};

use devicemapper::{DM, Device, DmDevice, LinearDev, Sectors};

use super::super::super::engine::BlockDev;
use super::super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::super::types::{DevUuid, PoolUuid};

use super::super::dmnames::{CacheRole, format_backstore_ids};
use super::super::serde_structs::{BackstoreSave, Recordable};

use super::blockdevmgr::{BlkDevSegment, BlockDevMgr, Segment, coalesce_blkdevsegs, map_to_dm};
use super::setup::get_blockdevs;

/// Handles the lowest level, base layer of this tier.
/// The dm_device organizes all block devs into a single linear allocation
/// pool. This structure can allocate additional space to the upper layer,
/// but it cannot accept returned space. When it is extended to be able to
/// accept returned space the allocation algorithm will have to be revised.
/// All available sectors on blockdevs in the manager are allocated to
/// dm_device.
#[derive(Debug)]
struct DataTier {
    /// Manages the individual block devices
    /// it is always the case block_mgr.avail_space() == 0.
    block_mgr: BlockDevMgr,
    /// The device mapper device which aggregates block_mgr's devices
    dm_device: LinearDev,
    /// The list of segments granted by block_mgr and used by dm_device
    segments: Vec<BlkDevSegment>,
    /// The position from which requested space is allocated
    next: Sectors,
}

impl DataTier {
    /// Setup a previously existing data layer from the block_mgr and
    /// previously allocated segments.
    ///
    /// WARNING: metadata changing event
    pub fn setup(dm: &DM,
                 block_mgr: BlockDevMgr,
                 segments: &[(DevUuid, Sectors, Sectors)],
                 next: Sectors)
                 -> EngineResult<DataTier> {
        if block_mgr.avail_space() != Sectors(0) {
            let err_msg = format!("{} unallocated to device; probable metadata corruption",
                                  block_mgr.avail_space());
            return Err(EngineError::Engine(ErrorEnum::Error, err_msg));
        }

        let uuid_to_devno = block_mgr.uuid_to_devno();
        let mapper = |triple: &(DevUuid, Sectors, Sectors)| -> EngineResult<BlkDevSegment> {
            let device = uuid_to_devno(triple.0)
                .ok_or_else(|| {
                                EngineError::Engine(ErrorEnum::NotFound,
                                                    format!("missing device for UUUD {:?}",
                                                            &triple.0))
                            })?;
            Ok(BlkDevSegment::new(triple.0, Segment::new(device, triple.1, triple.2)))
        };
        let segments = segments
            .iter()
            .map(&mapper)
            .collect::<EngineResult<Vec<_>>>()?;

        let (dm_name, dm_uuid) = format_backstore_ids(block_mgr.pool_uuid(), CacheRole::OriginSub);
        let ld = LinearDev::setup(dm, &dm_name, Some(&dm_uuid), map_to_dm(&segments))?;

        Ok(DataTier {
               block_mgr,
               dm_device: ld,
               segments,
               next,
           })
    }

    /// Setup a new DataTier struct from the block_mgr.
    /// WARNING: metadata changing event
    pub fn new(dm: &DM, mut block_mgr: BlockDevMgr) -> EngineResult<DataTier> {
        let avail_space = block_mgr.avail_space();
        let segments = block_mgr
            .alloc_space(&[avail_space])
            .expect("asked for exactly the space available, must get")
            .iter()
            .flat_map(|s| s.iter())
            .cloned()
            .collect::<Vec<_>>();
        let (dm_name, dm_uuid) = format_backstore_ids(block_mgr.pool_uuid(), CacheRole::OriginSub);
        let ld = LinearDev::setup(dm, &dm_name, Some(&dm_uuid), map_to_dm(&segments))?;
        Ok(DataTier {
               block_mgr,
               dm_device: ld,
               segments,
               next: Sectors(0),
           })
    }

    /// Add the given paths to self. Return UUIDs of the new blockdevs
    /// corresponding to the specified paths.
    /// WARNING: metadata changing event
    pub fn add(&mut self, dm: &DM, paths: &[&Path], force: bool) -> EngineResult<Vec<DevUuid>> {
        let uuids = self.block_mgr.add(paths, force)?;

        let avail_space = self.block_mgr.avail_space();
        let segments = self.block_mgr
            .alloc_space(&[avail_space])
            .expect("asked for exactly the space available, must get")
            .iter()
            .flat_map(|s| s.iter())
            .cloned()
            .collect::<Vec<_>>();
        let coalesced = coalesce_blkdevsegs(&self.segments, &segments);

        self.dm_device.set_table(dm, map_to_dm(&coalesced))?;

        self.segments = coalesced;

        Ok(uuids)
    }

    /// All the sectors available to this device
    pub fn capacity(&self) -> Sectors {
        let size = self.dm_device.size();
        assert_eq!(self.segments
                       .iter()
                       .map(|x| x.segment.length)
                       .sum::<Sectors>(),
                   size);
        size
    }

    /// The total size of all the blockdevs combined
    pub fn current_capacity(&self) -> Sectors {
        let size = self.block_mgr.current_capacity();
        assert_eq!(size - self.metadata_size(), self.capacity());
        size
    }

    /// Number of sectors unused
    pub fn available(&self) -> Sectors {
        self.capacity() - self.next
    }

    /// The number of sectors used for metadata by all the blockdevs
    pub fn metadata_size(&self) -> Sectors {
        self.block_mgr.metadata_size()
    }

    /// Allocate requested chunks from device.
    /// Returns None if it is not possible to satisfy the request.
    /// Each segment allocated is contiguous with its neighbors in the return
    /// vector.
    /// WARNING: All this must change when it becomes possible to return
    /// sectors to the store.
    /// WARNING: metadata changing event
    pub fn alloc_space(&mut self, sizes: &[Sectors]) -> Option<Vec<Vec<(Sectors, Sectors)>>> {
        if self.available() < sizes.iter().cloned().sum() {
            return None;
        }

        let mut chunks = Vec::new();
        for size in sizes {
            chunks.push(vec![(self.next, *size)]);
            self.next += *size;
        }
        Some(chunks)
    }

    /// Destroy the store. Teardown its DM devices and wipe its blockdevs.
    pub fn destroy(self, dm: &DM) -> EngineResult<()> {
        self.dm_device.teardown(dm)?;
        self.block_mgr.destroy_all()
    }
}

#[derive(Debug)]
pub struct Backstore {
    data_tier: DataTier,
}

impl Backstore {
    /// Make a Backstore object from blockdevs that already belong to Stratis.
    /// WARNING: metadata changing event
    pub fn setup(dm: &DM,
                 pool_uuid: PoolUuid,
                 backstore_save: &BackstoreSave,
                 devnodes: &HashMap<Device, PathBuf>,
                 last_update_time: Option<DateTime<Utc>>)
                 -> EngineResult<Backstore> {
        let blockdevs = get_blockdevs(pool_uuid, backstore_save, devnodes)?;
        let block_mgr = BlockDevMgr::new(pool_uuid, blockdevs, last_update_time);
        Ok(Backstore {
               data_tier: DataTier::setup(dm,
                                          block_mgr,
                                          &backstore_save.segments,
                                          backstore_save.next)?,
           })
    }

    /// Initialize a Backstore object, by initializing the specified devs.
    /// WARNING: metadata changing event
    pub fn initialize(dm: &DM,
                      pool_uuid: PoolUuid,
                      paths: &[&Path],
                      mda_size: Sectors,
                      force: bool)
                      -> EngineResult<Backstore> {
        Ok(Backstore {
               data_tier: DataTier::new(dm,
                                        BlockDevMgr::initialize(pool_uuid,
                                                                paths,
                                                                mda_size,
                                                                force)?)?,
           })
    }

    /// Add the given paths to self. Return UUIDs of the new blockdevs
    /// corresponding to the specified paths.
    /// WARNING: metadata changing event
    pub fn add(&mut self, dm: &DM, paths: &[&Path], force: bool) -> EngineResult<Vec<DevUuid>> {
        self.data_tier.add(dm, paths, force)
    }

    /// Allocate space from the underlying device.
    /// WARNING: metadata changing event
    pub fn alloc_space(&mut self, sizes: &[Sectors]) -> Option<Vec<Vec<(Sectors, Sectors)>>> {
        self.data_tier.alloc_space(sizes)
    }

    /// Return a reference to the blockdevs that form the basis of the
    /// backstore.
    pub fn blockdevs(&self) -> Vec<(DevUuid, &BlockDev)> {
        self.data_tier.block_mgr.blockdevs()
    }

    /// The current capacity of all the blockdevs that make up the backstore.
    pub fn current_capacity(&self) -> Sectors {
        self.data_tier.current_capacity()
    }

    /// Destroy the entire store.
    pub fn destroy(self, dm: &DM) -> EngineResult<()> {
        self.data_tier.destroy(dm)
    }

    /// Return the device that this tier is currently using.
    /// WARNING: This may change it the backstore switches between its
    /// cache and its non-cache incarnations, among other reasons.
    pub fn device(&self) -> Device {
        self.data_tier.dm_device.device()
    }

    /// Lookup an immutable blockdev by its Stratis UUID.
    pub fn get_blockdev_by_uuid(&self, uuid: DevUuid) -> Option<&BlockDev> {
        self.data_tier.block_mgr.get_blockdev_by_uuid(uuid)
    }

    /// Lookup a mutable blockdev by its Stratis UUID.
    pub fn get_mut_blockdev_by_uuid(&mut self, uuid: DevUuid) -> Option<&mut BlockDev> {
        self.data_tier.block_mgr.get_mut_blockdev_by_uuid(uuid)
    }

    /// The number of sectors in the backstore given up to Stratis
    /// metadata.
    pub fn metadata_size(&self) -> Sectors {
        self.data_tier.metadata_size()
    }

    /// Write the given data directly to the blockdevs that make up the
    /// backstore. This action bypasses the DM device entirely,
    /// in order to allow control over which blockdevs the metadata is written
    /// to.
    pub fn save_state(&mut self, metadata: &[u8]) -> EngineResult<()> {
        self.data_tier.block_mgr.save_state(metadata)
    }
}

impl Recordable<BackstoreSave> for Backstore {
    fn record(&self) -> BackstoreSave {
        BackstoreSave {
            segments: self.data_tier.segments.record(),
            block_devs: self.data_tier.block_mgr.record(),
            next: self.data_tier.next,
        }
    }
}
<|endoftext|>