<commit_before>use std::fmt::{self, Arguments, Write};

pub(crate) struct OutFile {
    pub namespace: Vec<String>,
    pub header: bool,
    content: Vec<u8>,
    section_pending: bool,
    block: &'static str,
    block_pending: bool,
}

impl OutFile {
    pub fn new(namespace: Vec<String>, header: bool) -> Self {
        OutFile {
            namespace,
            header,
            content: Vec::new(),
            section_pending: false,
            block: "",
            block_pending: false,
        }
    }

    // Write a blank line if the preceding section had any contents.
    pub fn next_section(&mut self) {
        self.section_pending = true;
    }

    pub fn begin_block(&mut self, block: &'static str) {
        self.block = block;
        self.block_pending = true;
    }

    pub fn end_block(&mut self) {
        if self.block_pending {
            self.block_pending = false;
        } else {
            self.content.extend_from_slice(b"} // ");
            self.content.extend_from_slice(self.block.as_bytes());
            self.content.push(b'\n');
            self.block = "";
            self.section_pending = true;
        }
    }

    pub fn write_fmt(&mut self, args: Arguments) {
        Write::write_fmt(self, args).unwrap();
    }
}

impl Write for OutFile {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        if !s.is_empty() {
            if self.block_pending {
                self.content.push(b'\n');
                self.content.extend_from_slice(self.block.as_bytes());
                self.content.extend_from_slice(b" {\n");
                self.block_pending = false;
                self.section_pending = false;
            } else if self.section_pending {
                self.content.push(b'\n');
                self.section_pending = false;
            }
            self.content.extend_from_slice(s.as_bytes());
        }
        Ok(())
    }
}

impl AsRef<[u8]> for OutFile {
    fn as_ref(&self) -> &[u8] {
        &self.content
    }
}
<commit_msg>Support nested blocks in C++ emitter<commit_after>use std::fmt::{self, Arguments, Write};

pub(crate) struct OutFile {
    pub namespace: Vec<String>,
    pub header: bool,
    content: Vec<u8>,
    section_pending: bool,
    blocks: Vec<&'static str>,
    blocks_pending: usize,
}

impl OutFile {
    pub fn new(namespace: Vec<String>, header: bool) -> Self {
        OutFile {
            namespace,
            header,
            content: Vec::new(),
            section_pending: false,
            blocks: Vec::new(),
            blocks_pending: 0,
        }
    }

    // Write a blank line if the preceding section had any contents.
    pub fn next_section(&mut self) {
        self.section_pending = true;
    }

    pub fn begin_block(&mut self, block: &'static str) {
        self.blocks.push(block);
        self.blocks_pending += 1;
    }

    pub fn end_block(&mut self) {
        if self.blocks_pending > 0 {
            self.blocks_pending -= 1;
        } else {
            self.content.extend_from_slice(b"} // ");
            self.content
                .extend_from_slice(self.blocks.pop().unwrap().as_bytes());
            self.content.push(b'\n');
            self.section_pending = true;
        }
    }

    pub fn write_fmt(&mut self, args: Arguments) {
        Write::write_fmt(self, args).unwrap();
    }
}

impl Write for OutFile {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        if !s.is_empty() {
            if self.blocks_pending > 0 {
                self.content.push(b'\n');
                for block in &self.blocks[self.blocks.len() - self.blocks_pending..] {
                    self.content.extend_from_slice(block.as_bytes());
                    self.content.extend_from_slice(b" {\n");
                }
                self.blocks_pending = 0;
                self.section_pending = false;
            } else if self.section_pending {
                self.content.push(b'\n');
                self.section_pending = false;
            }
            self.content.extend_from_slice(s.as_bytes());
        }
        Ok(())
    }
}

impl AsRef<[u8]> for OutFile {
    fn as_ref(&self) -> &[u8] {
        &self.content
    }
}
<|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/. */

/*!
Selector matching

Select matching is performed on generic node types. Client-specific details
about the DOM are encapsulated in the `SelectHandler` type which the `SelectCtx`
uses to query various DOM and UA properties.
*/

use stylesheet::Stylesheet;
use computed::ComputedStyle;
use util::VoidPtrLike;
use wapcaplet::LwcString;
use lwcstr_from_rust_str = wapcaplet::from_rust_string;
use n::u::{rust_str_to_net_qname, net_qname_to_rust_str};
use types::StylesheetOrigin;
use n;

pub struct SelectCtx {
    inner: n::s::CssSelectCtx
}

/**
The SelectCtx, used for performing selector matching.

The `SelectCtx` takes ownership of any number of `Stylesheet` objects,
encapsulates the cascade. Individual node styles can be requested with
the `select_style` method.
*/
impl SelectCtx {
    pub fn new() -> SelectCtx {
        SelectCtx {
            inner: n::s::css_select_ctx_create()
        }
    }

    /**
    Add `Stylesheet`s to the selection context, where they will participate in the cascade
    during future selector matching
    */
    pub fn append_sheet(&mut self, sheet: Stylesheet, origin: StylesheetOrigin) {
        let sheet = match sheet {
            Stylesheet { inner: inner } => inner
        };

        self.inner.append_sheet(sheet, origin.to_net(), n::ll::t::CSS_MEDIA_SCREEN)
    }

    /**
    Select the style for a single node. `handler` is used to query the client for
    a wide range of client-specific details like node relationships, names, and UA
    defaults.
    */
    pub fn select_style<N: VoidPtrLike, H: SelectHandler<N>>(&self, node: &N, handler: &H) -> SelectResults {
        let inner_handler = SelectHandlerWrapper {
            inner: handler
        };
        SelectResults {
            inner: self.inner.select_style::<N, SelectHandlerWrapper<N, H>>(node, n::ll::t::CSS_MEDIA_SCREEN, None, &inner_handler)
        }
    }
}

/**
Represents the 'style' of a single node, including it's pseudo-elements.
*/
pub struct SelectResults {
    inner: n::s::CssSelectResults
}

impl<'self> SelectResults {
    /** Retrieve the computed style of a single pseudo-element */
    pub fn computed_style(&'self self) -> ComputedStyle<'self> {
        ComputedStyle {
            inner: self.inner.computed_style(n::s::CssPseudoElementNone)
        }
    }
}

/**
Callbacks used to query the implementation-specific DOM
*/
pub trait SelectHandler<N> {
    fn with_node_name<R>(&self, node: &N, f: &fn(&str) -> R) -> R;
    fn with_node_classes<R>(&self, node: &N, f: &fn(Option<&str>) -> R) -> R;
    fn with_node_id<R>(&self, node: &N, f: &fn(Option<&str>) -> R) -> R;
    fn named_parent_node(&self, node: &N, name: &str) -> Option<N>;
    fn parent_node(&self, node: &N) -> Option<N>;
    fn node_has_class(&self, node: &N, &str) -> bool;
    fn node_has_id(&self, node: &N, &str) -> bool;
    fn named_ancestor_node(&self, node: &N, name: &str) -> Option<N>;
    fn node_is_root(&self, node: &N) -> bool;
    fn node_is_link(&self, node: &N) -> bool;
}

/** Used to convert the netsurfcss CssSelectHandler callbacks to out SelectHandler callbacks */
struct SelectHandlerWrapper<N, H> {
    // FIXME: Can't encode region variables
    inner: *H
}

impl<'self, N, H: SelectHandler<N>> SelectHandlerWrapper<N, H> {
    priv fn inner_ref(&self) -> &'self H {
        unsafe { &*self.inner }
    }
}

impl<N, H: SelectHandler<N>> n::s::CssSelectHandler<N> for SelectHandlerWrapper<N, H> {
    fn node_name(&self, node: &N) -> n::t::CssQName {
        do self.inner_ref().with_node_name(node) |name| {
            rust_str_to_net_qname(name)
        }
    }

    fn node_classes(&self, node: &N) -> Option<~[LwcString]> {
        do self.inner_ref().with_node_classes(node) |node_classes_opt| {
           do node_classes_opt.map |s| {
               debug!("SelectHandlerWrapper::node_classes - classes: %?", *s);
               let mut v = ~[];
               for s.split_iter(' ').advance |s| {
                   debug!("SelectHandlerWrapper::node_classes - class: %?", s);
                   if s != ~"" { v.push(lwcstr_from_rust_str(s)) }
               }
               debug!("SelectHandlerWrapper::classes: %?", v);
               v
           }
        }
    }

    fn node_id(&self, node: &N) -> Option<LwcString> {
        do self.inner_ref().with_node_id(node) |node_id_opt| {
            node_id_opt.map(|s| lwcstr_from_rust_str(*s))
        }
    }

    fn named_parent_node(&self, node: &N, qname: &n::t::CssQName) -> Option<N> {
        self.inner_ref().named_parent_node(node, net_qname_to_rust_str(qname))
    }

    fn parent_node(&self, node: &N) -> Option<N> {
        self.inner_ref().parent_node(node)
    }

    fn node_has_class(&self, node: &N, name: LwcString) -> bool {
        self.inner_ref().node_has_class(node, name.to_str_slice())
    }

    fn node_has_id(&self, node: &N, name: LwcString) -> bool {
        self.inner_ref().node_has_id(node, name.to_str_slice())
    }

    fn named_ancestor_node(&self, node: &N, qname: &n::t::CssQName) -> Option<N> {
        self.inner_ref().named_ancestor_node(node, net_qname_to_rust_str(qname))
    }

    fn node_is_root(&self, node: &N) -> bool {
        self.inner_ref().node_is_root(node)
    }

    fn node_is_link(&self, node: &N) -> bool {
        self.inner_ref().node_is_link(node)
    }

    fn node_is_visited(&self, _node: &N) -> bool {
        // FIXME
        warn_unimpl("node_is_visited");
        false
    }

    fn ua_default_for_property(&self, property: n::p::CssProperty) -> n::h::CssHint {
        warn!("not specifiying ua default for property %?", property);
        n::h::CssHintDefault
    }
}

fn warn_unimpl(what: &str) {
    warn!("unimplemented select handler: %?", what);
}
<commit_msg>Update to latest Rust.<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/. */

/*!
Selector matching

Select matching is performed on generic node types. Client-specific details
about the DOM are encapsulated in the `SelectHandler` type which the `SelectCtx`
uses to query various DOM and UA properties.
*/

use stylesheet::Stylesheet;
use computed::ComputedStyle;
use util::VoidPtrLike;
use wapcaplet::LwcString;
use lwcstr_from_rust_str = wapcaplet::from_rust_string;
use n::u::{rust_str_to_net_qname, net_qname_to_rust_str};
use types::StylesheetOrigin;
use n;

pub struct SelectCtx {
    inner: n::s::CssSelectCtx
}

/**
The SelectCtx, used for performing selector matching.

The `SelectCtx` takes ownership of any number of `Stylesheet` objects,
encapsulates the cascade. Individual node styles can be requested with
the `select_style` method.
*/
impl SelectCtx {
    pub fn new() -> SelectCtx {
        SelectCtx {
            inner: n::s::css_select_ctx_create()
        }
    }

    /**
    Add `Stylesheet`s to the selection context, where they will participate in the cascade
    during future selector matching
    */
    pub fn append_sheet(&mut self, sheet: Stylesheet, origin: StylesheetOrigin) {
        let sheet = match sheet {
            Stylesheet { inner: inner } => inner
        };

        self.inner.append_sheet(sheet, origin.to_net(), n::ll::t::CSS_MEDIA_SCREEN)
    }

    /**
    Select the style for a single node. `handler` is used to query the client for
    a wide range of client-specific details like node relationships, names, and UA
    defaults.
    */
    pub fn select_style<N: VoidPtrLike, H: SelectHandler<N>>(&self, node: &N, handler: &H) -> SelectResults {
        let inner_handler = SelectHandlerWrapper {
            inner: handler
        };
        SelectResults {
            inner: self.inner.select_style::<N, SelectHandlerWrapper<N, H>>(node, n::ll::t::CSS_MEDIA_SCREEN, None, &inner_handler)
        }
    }
}

/**
Represents the 'style' of a single node, including it's pseudo-elements.
*/
pub struct SelectResults {
    inner: n::s::CssSelectResults
}

impl<'self> SelectResults {
    /** Retrieve the computed style of a single pseudo-element */
    pub fn computed_style(&'self self) -> ComputedStyle<'self> {
        ComputedStyle {
            inner: self.inner.computed_style(n::s::CssPseudoElementNone)
        }
    }
}

/**
Callbacks used to query the implementation-specific DOM
*/
pub trait SelectHandler<N> {
    fn with_node_name<R>(&self, node: &N, f: &fn(&str) -> R) -> R;
    fn with_node_classes<R>(&self, node: &N, f: &fn(Option<&str>) -> R) -> R;
    fn with_node_id<R>(&self, node: &N, f: &fn(Option<&str>) -> R) -> R;
    fn named_parent_node(&self, node: &N, name: &str) -> Option<N>;
    fn parent_node(&self, node: &N) -> Option<N>;
    fn node_has_class(&self, node: &N, &str) -> bool;
    fn node_has_id(&self, node: &N, &str) -> bool;
    fn named_ancestor_node(&self, node: &N, name: &str) -> Option<N>;
    fn node_is_root(&self, node: &N) -> bool;
    fn node_is_link(&self, node: &N) -> bool;
}

/** Used to convert the netsurfcss CssSelectHandler callbacks to out SelectHandler callbacks */
struct SelectHandlerWrapper<N, H> {
    // FIXME: Can't encode region variables
    inner: *H
}

impl<'self, N, H: SelectHandler<N>> SelectHandlerWrapper<N, H> {
    priv fn inner_ref(&self) -> &'self H {
        unsafe { &*self.inner }
    }
}

impl<N, H: SelectHandler<N>> n::s::CssSelectHandler<N> for SelectHandlerWrapper<N, H> {
    fn node_name(&self, node: &N) -> n::t::CssQName {
        do self.inner_ref().with_node_name(node) |name| {
            rust_str_to_net_qname(name)
        }
    }

    fn node_classes(&self, node: &N) -> Option<~[LwcString]> {
        do self.inner_ref().with_node_classes(node) |node_classes_opt| {
           do node_classes_opt.map |s| {
               debug!("SelectHandlerWrapper::node_classes - classes: %?", *s);
               let mut v = ~[];
               for s.split_iter(' ').advance |s| {
                   debug!("SelectHandlerWrapper::node_classes - class: %?", s);
                   if s != "" { v.push(lwcstr_from_rust_str(s)) }
               }
               debug!("SelectHandlerWrapper::classes: %?", v);
               v
           }
        }
    }

    fn node_id(&self, node: &N) -> Option<LwcString> {
        do self.inner_ref().with_node_id(node) |node_id_opt| {
            node_id_opt.map(|s| lwcstr_from_rust_str(*s))
        }
    }

    fn named_parent_node(&self, node: &N, qname: &n::t::CssQName) -> Option<N> {
        self.inner_ref().named_parent_node(node, net_qname_to_rust_str(qname))
    }

    fn parent_node(&self, node: &N) -> Option<N> {
        self.inner_ref().parent_node(node)
    }

    fn node_has_class(&self, node: &N, name: LwcString) -> bool {
        self.inner_ref().node_has_class(node, name.to_str_slice())
    }

    fn node_has_id(&self, node: &N, name: LwcString) -> bool {
        self.inner_ref().node_has_id(node, name.to_str_slice())
    }

    fn named_ancestor_node(&self, node: &N, qname: &n::t::CssQName) -> Option<N> {
        self.inner_ref().named_ancestor_node(node, net_qname_to_rust_str(qname))
    }

    fn node_is_root(&self, node: &N) -> bool {
        self.inner_ref().node_is_root(node)
    }

    fn node_is_link(&self, node: &N) -> bool {
        self.inner_ref().node_is_link(node)
    }

    fn node_is_visited(&self, _node: &N) -> bool {
        // FIXME
        warn_unimpl("node_is_visited");
        false
    }

    fn ua_default_for_property(&self, property: n::p::CssProperty) -> n::h::CssHint {
        warn!("not specifiying ua default for property %?", property);
        n::h::CssHintDefault
    }
}

fn warn_unimpl(what: &str) {
    warn!("unimplemented select handler: %?", what);
}
<|endoftext|>


<commit_before>use crate::*;
use helpers::check_arg_count;
use rustc_middle::ty::TypeAndMut;
use rustc_ast::ast::Mutability;
use rustc_span::BytePos;
use rustc_target::abi::Size;
use std::convert::TryInto as _;
use crate::rustc_target::abi::LayoutOf as _;

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

    fn handle_miri_get_backtrace(
        &mut self,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();
        let tcx = this.tcx;
        let &[flags] = check_arg_count(args)?;

        let flags = this.read_scalar(flags)?.to_u64()?;
        if flags != 0 {
            throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags);
        }

        let mut data = Vec::new();
        for frame in this.active_thread_stack().iter().rev() {
            data.push((frame.instance, frame.current_span().lo()));
        }

        let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| {
            let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance));
            fn_ptr.offset = Size::from_bytes(pos.0);
            Scalar::Ptr(fn_ptr)
        }).collect();

        let len = ptrs.len();

        let ptr_ty = tcx.mk_ptr(TypeAndMut {
            ty: tcx.types.unit,
            mutbl: Mutability::Mut
        });

        let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap());

        // Write pointers into array
        let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into());
        for (i, ptr) in ptrs.into_iter().enumerate() {
            let place = this.mplace_index(alloc, i as u64)?;
            this.write_immediate_to_mplace(ptr.into(), place)?;
        }

        this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?;
        Ok(())
    }

    fn handle_miri_resolve_frame(
        &mut self,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();
        let tcx = this.tcx;
        let &[ptr, flags] = check_arg_count(args)?;

        let flags = this.read_scalar(flags)?.to_u64()?;
        if flags != 0 {
            throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags);
        }

        let ptr = match this.read_scalar(ptr)?.check_init()? {
            Scalar::Ptr(ptr) => ptr,
            Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr)
        };

        let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) {
            instance
        } else {
            throw_ub_format!("expected function pointer, found {:?}", ptr);
        };

        if dest.layout.layout.fields.count() != 4 {
            throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields");
        }

        let pos = BytePos(ptr.offset.bytes().try_into().unwrap());
        let name = fn_instance.to_string();

        let lo = tcx.sess.source_map().lookup_char_pos(pos);

        let filename = lo.file.name.to_string();
        let lineno: u32 = lo.line as u32;
        // `lo.col` is 0-based - add 1 to make it 1-based for the caller.
        let colno: u32 = lo.col.0 as u32 + 1;

        let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into());
        let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into());
        let lineno_alloc = Scalar::from_u32(lineno);
        let colno_alloc = Scalar::from_u32(colno);

        let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0;

        this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?;
        this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?;
        this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?;
        this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?;
        Ok(())
    }
}
<commit_msg>Explain encoding scheme<commit_after>use crate::*;
use helpers::check_arg_count;
use rustc_middle::ty::TypeAndMut;
use rustc_ast::ast::Mutability;
use rustc_span::BytePos;
use rustc_target::abi::Size;
use std::convert::TryInto as _;
use crate::rustc_target::abi::LayoutOf as _;

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

    fn handle_miri_get_backtrace(
        &mut self,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();
        let tcx = this.tcx;
        let &[flags] = check_arg_count(args)?;

        let flags = this.read_scalar(flags)?.to_u64()?;
        if flags != 0 {
            throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags);
        }

        let mut data = Vec::new();
        for frame in this.active_thread_stack().iter().rev() {
            data.push((frame.instance, frame.current_span().lo()));
        }

        let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| {
            // We represent a frame pointer by using the `span.lo` value
            // as an offset into the function's allocation. This gives us an
            // opaque pointer that we can return to user code, and allows us
            // to reconstruct the needed frame information in `handle_miri_resolve_frame`.
            // Note that we never actually read or write anything from/to this pointer -
            // all of the data is represented by the pointer value itself.
            let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance));
            fn_ptr.offset = Size::from_bytes(pos.0);
            Scalar::Ptr(fn_ptr)
        }).collect();

        let len = ptrs.len();

        let ptr_ty = tcx.mk_ptr(TypeAndMut {
            ty: tcx.types.unit,
            mutbl: Mutability::Mut
        });

        let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap());

        // Write pointers into array
        let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into());
        for (i, ptr) in ptrs.into_iter().enumerate() {
            let place = this.mplace_index(alloc, i as u64)?;
            this.write_immediate_to_mplace(ptr.into(), place)?;
        }

        this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?;
        Ok(())
    }

    fn handle_miri_resolve_frame(
        &mut self,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();
        let tcx = this.tcx;
        let &[ptr, flags] = check_arg_count(args)?;

        let flags = this.read_scalar(flags)?.to_u64()?;
        if flags != 0 {
            throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags);
        }

        let ptr = match this.read_scalar(ptr)?.check_init()? {
            Scalar::Ptr(ptr) => ptr,
            Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr)
        };

        let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) {
            instance
        } else {
            throw_ub_format!("expected function pointer, found {:?}", ptr);
        };

        if dest.layout.layout.fields.count() != 4 {
            throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields");
        }

        let pos = BytePos(ptr.offset.bytes().try_into().unwrap());
        let name = fn_instance.to_string();

        let lo = tcx.sess.source_map().lookup_char_pos(pos);

        let filename = lo.file.name.to_string();
        let lineno: u32 = lo.line as u32;
        // `lo.col` is 0-based - add 1 to make it 1-based for the caller.
        let colno: u32 = lo.col.0 as u32 + 1;

        let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into());
        let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into());
        let lineno_alloc = Scalar::from_u32(lineno);
        let colno_alloc = Scalar::from_u32(colno);

        let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0;

        this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?;
        this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?;
        this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?;
        this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use irc::client::prelude::*;
use irc::error::IrcError;

use std::time::Duration;
use std::sync::Mutex;

use time;
use chrono::NaiveDateTime;
use humantime::format_duration;

use plugin::*;

pub mod database;
use self::database::{Database, DbResponse};

macro_rules! try_lock {
    ( $m:expr ) => {
        match $m.lock() {
            Ok(guard) => guard,
            Err(poisoned) => poisoned.into_inner(),
        }
    }
}

#[derive(PluginName, Default)]
pub struct Tell<T: Database> {
    tells: Mutex<T>,
}

impl<T: Database> Tell<T> {
    pub fn new(db: T) -> Tell<T> {
        Tell {
            tells: Mutex::new(db),
        }
    }

    fn tell_command(&self, client: &IrcClient, command: &PluginCommand) -> Result<&str, String> {
        if command.tokens.len() < 2 {
            return Err(self.invalid_command(client));
        }

        let receiver = command.tokens[0].to_string();
        let sender = command.source.to_owned();

        if receiver == sender {
            //return Err(String::from("That's your name!"));
        }

        if command.source != command.target {
            if let Some(users) = client.list_users(&command.target) {
                if users.iter().any(|u| u.get_nickname() == receiver) {
                    //return Err(format!("{} is in this channel.", receiver));
                }
            }
        }

        let tm = time::now().to_timespec();
        let message = command.tokens[1..].join(" ");
        let tell = database::NewTellMessage {
            sender: &sender,
            receiver: &receiver,
            time: NaiveDateTime::from_timestamp(tm.sec, 0u32),
            message: &message,
        };

        match try_lock!(self.tells).insert_tell(&tell) {
            DbResponse::Success => Ok("Got it!"),
            DbResponse::Failed(e) => Err(e.to_string()),
        }
    }

    fn send_tell(&self, client: &IrcClient, receiver: &str) -> ExecutionStatus {
        let mut tells = try_lock!(self.tells);
        if let Some(tell_messages) = tells.get_tells(receiver) {
            for tell in tell_messages {
                let now = Duration::new(time::now().to_timespec().sec as u64, 0);
                let dur = now - Duration::new(tell.time.timestamp() as u64, 0);
                let human_dur = format_duration(dur);

                if let Err(e) = client.send_notice(
                    receiver,
                    &format!(
                        "Tell from {} {} ago: {}",
                        tell.sender, human_dur, tell.message
                    ),
                ) {
                    return ExecutionStatus::Err(Box::new(e));
                }
                debug!(
                    "Sent {:?} from {:?} to {:?}",
                    tell.message, tell.sender, receiver
                );
            }
        }
        tells.delete_tells(receiver);
        ExecutionStatus::Done
    }

    fn invalid_command(&self, client: &IrcClient) -> String {
        format!(
            "Incorrect Command. \
             Send \"{} tell help\" for help.",
            client.current_nickname()
        )
    }

    fn help(&self, client: &IrcClient) -> String {
        format!(
            "usage: {} tell user message\r\n\
             example: {0} tell Foobar Hello!",
            client.current_nickname()
        )
    }
}

impl<T: Database> Plugin for Tell<T> {
    fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::JOIN(_, _, _) | Command::PRIVMSG(_, _) => {
                self.send_tell(client, message.source_nickname().unwrap())
            }
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), IrcError> {
        panic!("Tell should not use threading")
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), IrcError> {
        if command.tokens.is_empty() {
            return client.send_notice(&command.source, &self.invalid_command(client));
        }

        match command.tokens[0].as_ref() {
            "help" => client.send_notice(&command.source, &self.help(client)),
            _ => match self.tell_command(client, &command) {
                Ok(msg) => client.send_notice(&command.source, msg),
                Err(msg) => client.send_notice(&command.source, &msg),
            },
        }
    }

    fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
        Err(String::from("This Plugin does not implement any commands."))
    }
}

use std::fmt;
impl<T: Database> fmt::Debug for Tell<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Tell {{ ... }}")
    }
}
<commit_msg>Add accidentally removed errors<commit_after>use irc::client::prelude::*;
use irc::error::IrcError;

use std::time::Duration;
use std::sync::Mutex;

use time;
use chrono::NaiveDateTime;
use humantime::format_duration;

use plugin::*;

pub mod database;
use self::database::{Database, DbResponse};

macro_rules! try_lock {
    ( $m:expr ) => {
        match $m.lock() {
            Ok(guard) => guard,
            Err(poisoned) => poisoned.into_inner(),
        }
    }
}

#[derive(PluginName, Default)]
pub struct Tell<T: Database> {
    tells: Mutex<T>,
}

impl<T: Database> Tell<T> {
    pub fn new(db: T) -> Tell<T> {
        Tell {
            tells: Mutex::new(db),
        }
    }

    fn tell_command(&self, client: &IrcClient, command: &PluginCommand) -> Result<&str, String> {
        if command.tokens.len() < 2 {
            return Err(self.invalid_command(client));
        }

        let receiver = command.tokens[0].to_string();
        let sender = command.source.to_owned();

        if receiver == sender {
            return Err(String::from("That's your name!"));
        }

        if command.source != command.target {
            if let Some(users) = client.list_users(&command.target) {
                if users.iter().any(|u| u.get_nickname() == receiver) {
                    return Err(format!("{} is in this channel.", receiver));
                }
            }
        }

        let tm = time::now().to_timespec();
        let message = command.tokens[1..].join(" ");
        let tell = database::NewTellMessage {
            sender: &sender,
            receiver: &receiver,
            time: NaiveDateTime::from_timestamp(tm.sec, 0u32),
            message: &message,
        };

        match try_lock!(self.tells).insert_tell(&tell) {
            DbResponse::Success => Ok("Got it!"),
            DbResponse::Failed(e) => Err(e.to_string()),
        }
    }

    fn send_tell(&self, client: &IrcClient, receiver: &str) -> ExecutionStatus {
        let mut tells = try_lock!(self.tells);
        if let Some(tell_messages) = tells.get_tells(receiver) {
            for tell in tell_messages {
                let now = Duration::new(time::now().to_timespec().sec as u64, 0);
                let dur = now - Duration::new(tell.time.timestamp() as u64, 0);
                let human_dur = format_duration(dur);

                if let Err(e) = client.send_notice(
                    receiver,
                    &format!(
                        "Tell from {} {} ago: {}",
                        tell.sender, human_dur, tell.message
                    ),
                ) {
                    return ExecutionStatus::Err(Box::new(e));
                }
                debug!(
                    "Sent {:?} from {:?} to {:?}",
                    tell.message, tell.sender, receiver
                );
            }
        }
        tells.delete_tells(receiver);
        ExecutionStatus::Done
    }

    fn invalid_command(&self, client: &IrcClient) -> String {
        format!(
            "Incorrect Command. \
             Send \"{} tell help\" for help.",
            client.current_nickname()
        )
    }

    fn help(&self, client: &IrcClient) -> String {
        format!(
            "usage: {} tell user message\r\n\
             example: {0} tell Foobar Hello!",
            client.current_nickname()
        )
    }
}

impl<T: Database> Plugin for Tell<T> {
    fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::JOIN(_, _, _) | Command::PRIVMSG(_, _) => {
                self.send_tell(client, message.source_nickname().unwrap())
            }
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), IrcError> {
        panic!("Tell should not use threading")
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), IrcError> {
        if command.tokens.is_empty() {
            return client.send_notice(&command.source, &self.invalid_command(client));
        }

        match command.tokens[0].as_ref() {
            "help" => client.send_notice(&command.source, &self.help(client)),
            _ => match self.tell_command(client, &command) {
                Ok(msg) => client.send_notice(&command.source, msg),
                Err(msg) => client.send_notice(&command.source, &msg),
            },
        }
    }

    fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
        Err(String::from("This Plugin does not implement any commands."))
    }
}

use std::fmt;
impl<T: Database> fmt::Debug for Tell<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Tell {{ ... }}")
    }
}
<|endoftext|>


<commit_before>use response;
use handler::ErrorHandler;
use codegen::StaticCatchInfo;
use error::Error;
use request::Request;

use std::fmt;
use term_painter::ToStyle;
use term_painter::Color::*;

/// An error catching route.
///
/// Catchers are routes that run when errors occur. They correspond directly
/// with the HTTP error status code they will be handling and are registered
/// with Rocket via the [Rocket::catch](/rocket/struct.Rocket.html#method.catch)
/// method. For example, to handle "404 not found" errors, a catcher for the
/// "404" status code is registered.
///
/// Because error handlers are only called when all routes are exhausted, they
/// should not fail nor forward. If an error catcher fails, the user will
/// receive no response. If an error catcher forwards, Rocket will respond with
/// an internal server error.
///
/// # Built-In Catchers
///
/// Rocket has many built-in, pre-registered default catchers. In particular,
/// Rocket has catchers for all of the following status codes: 400, 401, 402,
/// 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417,
/// 418, 421, 426, 428, 429, 431, 451, 500, 501, 503, and 510. As such, catchers
/// only need to be registered if an error needs to be handled in a custom
/// fashion.
///
/// # Code Generation
///
/// Catchers should rarely be used directly. Instead, they are typically
/// declared using the `error` decorator, as follows:
///
/// ```rust
/// #![feature(plugin)]
/// #![plugin(rocket_codegen)]
///
/// extern crate rocket;
///
/// use rocket::Request;
///
/// #[error(500)]
/// fn internal_error() -> &'static str {
///     "Whoops! Looks like we messed up."
/// }
///
/// #[error(400)]
/// fn not_found(req: &Request) -> String {
///     format!("I couldn't find '{}'. Try something else?", req.uri())
/// }
///
/// fn main() {
/// # if false { // We don't actually want to launch the server in an example.
///     rocket::ignite().catch(errors![internal_error, not_found]).launch()
/// # }
/// }
/// ```
///
/// A function decorated with `error` can take in 0, 1, or 2 parameters:
/// `Error`, `&Request`, or both, as desired.
pub struct Catcher {
    /// The HTTP status code to match against.
    pub code: u16,
    handler: ErrorHandler,
    is_default: bool,
}

impl Catcher {
    /// Creates a catcher for the given status code using the given error
    /// handler. This should only be used when routing manually.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #![allow(unused_variables)]
    /// use rocket::{Catcher, Request, Error};
    /// use rocket::response::{Result, Responder};
    ///
    /// fn handle_404<'r>(_: Error, req: &'r Request) -> Result<'r> {
    ///    format!("Couldn't find: {}", req.uri()).respond()
    /// }
    ///
    /// fn handle_500<'r>(_: Error, _: &'r Request) -> Result<'r> {
    ///     "Whoops, we messed up!".respond()
    /// }
    ///
    /// let not_found_catcher = Catcher::new(404, handle_404);
    /// let internal_server_error_catcher = Catcher::new(500, handle_500);
    /// ```
    #[inline(always)]
    pub fn new(code: u16, handler: ErrorHandler) -> Catcher {
        Catcher { code: code, handler: handler, is_default: false }
    }

    #[inline(always)]
    pub(crate) fn handle<'r>(&self, err: Error, req: &'r Request)
            -> response::Result<'r> {
        (self.handler)(err, req)
    }

    #[inline(always)]
    fn new_default(code: u16, handler: ErrorHandler) -> Catcher {
        Catcher { code: code, handler: handler, is_default: true, }
    }

    #[inline(always)]
    pub(crate) fn is_default(&self) -> bool {
        self.is_default
    }
}

#[doc(hidden)]
impl<'a> From<&'a StaticCatchInfo> for Catcher {
    fn from(info: &'a StaticCatchInfo) -> Catcher {
        Catcher::new(info.code, info.handler)
    }
}

impl fmt::Display for Catcher {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", Blue.paint(&self.code))
    }
}

macro_rules! error_page_template {
    ($code:expr, $name:expr, $description:expr) => (
        concat!(r#"
            <!DOCTYPE html>

                <meta charset="utf-8">
                <title>"#, $code, " ", $name, r#"</title>

"#, $code, ": ", $name, r#"

"#, $description, r#"

                    Rocket

        "#
        )
    )
}

macro_rules! default_errors {
    ($($code:expr, $name:expr, $description:expr, $fn_name:ident),+) => (
        let mut map = HashMap::new();

        $(
            fn $fn_name<'r>(_: Error, _r: &'r Request) -> response::Result<'r> {
                status::Custom(Status::from_code($code).unwrap(),
                    content::HTML(error_page_template!($code, $name, $description))
                ).respond()
            }

            map.insert($code, Catcher::new_default($code, $fn_name));
        )+

        map
    )
}

pub mod defaults {
    use super::Catcher;

    use std::collections::HashMap;

    use request::Request;
    use response::{self, content, status, Responder};
    use http::Status;
    use error::Error;

    pub fn get() -> HashMap<u16, Catcher> {
        default_errors! {
            400, "Bad Request", "The request could not be understood by the server due
                to malformed syntax.", handle_400,
            401, "Unauthorized", "The request requires user authentication.",
                handle_401,
            402, "Payment Required", "The request could not be processed due to lack of
                payment.", handle_402,
            403, "Forbidden", "The request was forbidden by the server.
                Check authentication.", handle_403,
            404, "Not Found", "The requested resource could not be found.", handle_404,
            405, "Method Not Allowed", "The request method is not supported for the
                requested resource.", handle_405,
            406, "Not Acceptable", "The requested resource is capable of generating
                only content not acceptable according to the Accept headers sent in the
                request.", handle_406,
            407, "Proxy Authentication Required", "Authentication with the proxy is
                required.", handle_407,
            408, "Request Timeout", "The server timed out waiting for the
                request.", handle_408,
            409, "Conflict", "The request could not be processed because of a conflict
                in the request.", handle_409,
            410, "Gone", "The resource requested is no longer available and will not be
                available again.", handle_410,
            411, "Length Required", "The request did not specify the length of its
                content, which is required by the requested resource.", handle_411,
            412, "Precondition Failed", "The server does not meet one of the
                preconditions specified in the request.", handle_412,
            413, "Payload Too Large", "The request is larger than the server is
                willing or able to process.", handle_413,
            414, "URI Too Long", "The URI provided was too long for the server to
                process.", handle_414,
            415, "Unsupported Media Type", "The request entity has a media type which
                the server or resource does not support.", handle_415,
            416, "Range Not Satisfiable", "The portion of the requested file cannot be
                supplied by the server.", handle_416,
            417, "Expectation Failed", "The server cannot meet the requirements of the
                Expect request-header field.", handle_417,
            418, "I'm a teapot", "I was requested to brew coffee, and I am a
                teapot.", handle_418,
            421, "Misdirected Request", "The server cannot produce a response for this
                request.", handle_421,
            422, "Unprocessable Entity", "The request was well-formed but was unable to
                be followed due to semantic errors.", handle_422,
            426, "Upgrade Required", "Switching to the protocol in the Upgrade header
                field is required.", handle_426,
            428, "Precondition Required", "The server requires the request to be
               conditional.", handle_428,
            429, "Too Many Requests", "Too many requests have been received
                recently.", handle_429,
            431, "Request Header Fields Too Large", "The server is unwilling to process
                the request because either an individual header field, or all
                the header fields collectively, are too large.", handle_431,
            451, "Unavailable For Legal Reasons", "The requested resource is
                unavailable due to a legal demand to deny access to this
                resource.", handle_451,
            500, "Internal Server Error", "The server encountered an internal error
                while processing this request.", handle_500,
            501, "Not Implemented", "The server either does not recognize the request
                method, or it lacks the ability to fulfill the request.", handle_501,
            503, "Service Unavailable", "The server is currently unavailable.",
                handle_503,
            510, "Not Extended", "Further extensions to the request are required for
                the server to fulfill it.", handle_510
        }
    }
}

<commit_msg>Update `Catcher` example: returns Status::NotFound on 404.<commit_after>use response;
use handler::ErrorHandler;
use codegen::StaticCatchInfo;
use error::Error;
use request::Request;

use std::fmt;
use term_painter::ToStyle;
use term_painter::Color::*;

/// An error catching route.
///
/// Catchers are routes that run when errors occur. They correspond directly
/// with the HTTP error status code they will be handling and are registered
/// with Rocket via the [Rocket::catch](/rocket/struct.Rocket.html#method.catch)
/// method. For example, to handle "404 not found" errors, a catcher for the
/// "404" status code is registered.
///
/// Because error handlers are only called when all routes are exhausted, they
/// should not fail nor forward. If an error catcher fails, the user will
/// receive no response. If an error catcher forwards, Rocket will respond with
/// an internal server error.
///
/// # Built-In Catchers
///
/// Rocket has many built-in, pre-registered default catchers. In particular,
/// Rocket has catchers for all of the following status codes: 400, 401, 402,
/// 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417,
/// 418, 421, 426, 428, 429, 431, 451, 500, 501, 503, and 510. As such, catchers
/// only need to be registered if an error needs to be handled in a custom
/// fashion.
///
/// # Code Generation
///
/// Catchers should rarely be used directly. Instead, they are typically
/// declared using the `error` decorator, as follows:
///
/// ```rust
/// #![feature(plugin)]
/// #![plugin(rocket_codegen)]
///
/// extern crate rocket;
///
/// use rocket::Request;
///
/// #[error(500)]
/// fn internal_error() -> &'static str {
///     "Whoops! Looks like we messed up."
/// }
///
/// #[error(400)]
/// fn not_found(req: &Request) -> String {
///     format!("I couldn't find '{}'. Try something else?", req.uri())
/// }
///
/// fn main() {
/// # if false { // We don't actually want to launch the server in an example.
///     rocket::ignite().catch(errors![internal_error, not_found]).launch()
/// # }
/// }
/// ```
///
/// A function decorated with `error` can take in 0, 1, or 2 parameters:
/// `Error`, `&Request`, or both, as desired.
pub struct Catcher {
    /// The HTTP status code to match against.
    pub code: u16,
    handler: ErrorHandler,
    is_default: bool,
}

impl Catcher {
    /// Creates a catcher for the given status code using the given error
    /// handler. This should only be used when routing manually.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #![allow(unused_variables)]
    /// use rocket::{Catcher, Request, Error};
    /// use rocket::response::{Result, Responder};
    /// use rocket::response::status::Custom;
    /// use rocket::http::Status;
    ///
    /// fn handle_404<'r>(_: Error, req: &'r Request) -> Result<'r> {
    ///     Custom(Status::NotFound, format!("Couldn't find: {}", req.uri())).respond()
    /// }
    ///
    /// fn handle_500<'r>(_: Error, _: &'r Request) -> Result<'r> {
    ///     "Whoops, we messed up!".respond()
    /// }
    ///
    /// let not_found_catcher = Catcher::new(404, handle_404);
    /// let internal_server_error_catcher = Catcher::new(500, handle_500);
    /// ```
    #[inline(always)]
    pub fn new(code: u16, handler: ErrorHandler) -> Catcher {
        Catcher { code: code, handler: handler, is_default: false }
    }

    #[inline(always)]
    pub(crate) fn handle<'r>(&self, err: Error, req: &'r Request)
            -> response::Result<'r> {
        (self.handler)(err, req)
    }

    #[inline(always)]
    fn new_default(code: u16, handler: ErrorHandler) -> Catcher {
        Catcher { code: code, handler: handler, is_default: true, }
    }

    #[inline(always)]
    pub(crate) fn is_default(&self) -> bool {
        self.is_default
    }
}

#[doc(hidden)]
impl<'a> From<&'a StaticCatchInfo> for Catcher {
    fn from(info: &'a StaticCatchInfo) -> Catcher {
        Catcher::new(info.code, info.handler)
    }
}

impl fmt::Display for Catcher {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", Blue.paint(&self.code))
    }
}

macro_rules! error_page_template {
    ($code:expr, $name:expr, $description:expr) => (
        concat!(r#"
            <!DOCTYPE html>

                <meta charset="utf-8">
                <title>"#, $code, " ", $name, r#"</title>

"#, $code, ": ", $name, r#"

"#, $description, r#"

                    Rocket

        "#
        )
    )
}

macro_rules! default_errors {
    ($($code:expr, $name:expr, $description:expr, $fn_name:ident),+) => (
        let mut map = HashMap::new();

        $(
            fn $fn_name<'r>(_: Error, _r: &'r Request) -> response::Result<'r> {
                status::Custom(Status::from_code($code).unwrap(),
                    content::HTML(error_page_template!($code, $name, $description))
                ).respond()
            }

            map.insert($code, Catcher::new_default($code, $fn_name));
        )+

        map
    )
}

pub mod defaults {
    use super::Catcher;

    use std::collections::HashMap;

    use request::Request;
    use response::{self, content, status, Responder};
    use http::Status;
    use error::Error;

    pub fn get() -> HashMap<u16, Catcher> {
        default_errors! {
            400, "Bad Request", "The request could not be understood by the server due
                to malformed syntax.", handle_400,
            401, "Unauthorized", "The request requires user authentication.",
                handle_401,
            402, "Payment Required", "The request could not be processed due to lack of
                payment.", handle_402,
            403, "Forbidden", "The request was forbidden by the server.
                Check authentication.", handle_403,
            404, "Not Found", "The requested resource could not be found.", handle_404,
            405, "Method Not Allowed", "The request method is not supported for the
                requested resource.", handle_405,
            406, "Not Acceptable", "The requested resource is capable of generating
                only content not acceptable according to the Accept headers sent in the
                request.", handle_406,
            407, "Proxy Authentication Required", "Authentication with the proxy is
                required.", handle_407,
            408, "Request Timeout", "The server timed out waiting for the
                request.", handle_408,
            409, "Conflict", "The request could not be processed because of a conflict
                in the request.", handle_409,
            410, "Gone", "The resource requested is no longer available and will not be
                available again.", handle_410,
            411, "Length Required", "The request did not specify the length of its
                content, which is required by the requested resource.", handle_411,
            412, "Precondition Failed", "The server does not meet one of the
                preconditions specified in the request.", handle_412,
            413, "Payload Too Large", "The request is larger than the server is
                willing or able to process.", handle_413,
            414, "URI Too Long", "The URI provided was too long for the server to
                process.", handle_414,
            415, "Unsupported Media Type", "The request entity has a media type which
                the server or resource does not support.", handle_415,
            416, "Range Not Satisfiable", "The portion of the requested file cannot be
                supplied by the server.", handle_416,
            417, "Expectation Failed", "The server cannot meet the requirements of the
                Expect request-header field.", handle_417,
            418, "I'm a teapot", "I was requested to brew coffee, and I am a
                teapot.", handle_418,
            421, "Misdirected Request", "The server cannot produce a response for this
                request.", handle_421,
            422, "Unprocessable Entity", "The request was well-formed but was unable to
                be followed due to semantic errors.", handle_422,
            426, "Upgrade Required", "Switching to the protocol in the Upgrade header
                field is required.", handle_426,
            428, "Precondition Required", "The server requires the request to be
               conditional.", handle_428,
            429, "Too Many Requests", "Too many requests have been received
                recently.", handle_429,
            431, "Request Header Fields Too Large", "The server is unwilling to process
                the request because either an individual header field, or all
                the header fields collectively, are too large.", handle_431,
            451, "Unavailable For Legal Reasons", "The requested resource is
                unavailable due to a legal demand to deny access to this
                resource.", handle_451,
            500, "Internal Server Error", "The server encountered an internal error
                while processing this request.", handle_500,
            501, "Not Implemented", "The server either does not recognize the request
                method, or it lacks the ability to fulfill the request.", handle_501,
            503, "Service Unavailable", "The server is currently unavailable.",
                handle_503,
            510, "Not Extended", "Further extensions to the request are required for
                the server to fulfill it.", handle_510
        }
    }
}

<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::new(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    pub fn iter_ids(&self, m: &Module) -> Result<IntoIter<FileID>, StorageBackendError>
    {
        let globstr = self.prefix_of_files_for_module(m) + "*.imag";
        debug!("Globstring = {}", globstr);
        glob(&globstr[..])
            .and_then(|globlist| {
                debug!("Iterating over globlist");
                Ok(globlist_to_file_id_vec(globlist).into_iter())
            })
            .map_err(|e| {
                debug!("glob() returned error: {:?}", e);
                let serr = StorageBackendError::new(
                        "iter_ids()",
                        "Cannot iter on file ids",
                        None);
                // Why the hack is Error not implemented for glob::PatternError
                // serr.caused_by = Some(Box::new(e));
                serr
            })
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Result<IntoIter<File<'a>>, StorageBackendError>
        where HP: FileHeaderParser
    {
        self.iter_ids(m)
            .and_then(|ids| {
                debug!("Iterating ids and building files from them");
                debug!("  number of ids = {}", ids.len());
                Ok(self.filter_map_ids_to_files(m, p, ids).into_iter())
            })
            .map_err(|e| {
                debug!("StorageBackend::iter_ids() returned error = {:?}", e);
                let mut serr = StorageBackendError::new("iter_files()",
                                           "Cannot iter on files",
                                           None);
                serr.caused_by = Some(Box::new(e));
                serr
            })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::new(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::new(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::new(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::new(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: &FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        use std::ops::Index;

        debug!("Searching for file with id '{}'", id);

        if id.get_type() == FileIDType::NONE {
            // We don't know the hash type, so we glob() around a bit.
            debug!("Having FileIDType::NONE, so we glob() for the raw ID");

            let id_str = id.get_id().unwrap_or(String::from("INVALID"));
            let globstr = self.prefix_of_files_for_module(m) + "*" + &id_str[..] + ".imag";
            debug!("Globbing with globstr = '{}'", globstr);
            glob(&globstr[..]).map(|globlist| {
                let idvec = globlist_to_file_id_vec(globlist).into_iter();
                let mut vec = self.filter_map_ids_to_files(m, p, idvec);
                vec.reverse();
                vec.pop()
            }).unwrap_or({
                debug!("No glob matches, actually. We can't do anything at this point");
                None
            })
        } else {
            // The (hash)type is already in the FileID object, so we can just
            // build a path from the information we already have
            debug!("We know FileIDType, so we build the path directly now");
            if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
                let mut s = String::new();
                fs.read_to_string(&mut s);
                debug!("Success opening file with id '{}'", id);
                debug!("Parsing to internal structure now");
                p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
            } else {
                debug!("No file with id '{}'", id);
                None
            }
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::new(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        let idstr   : String        = id.clone().into();
        let idtype  : FileIDType    = id.into();
        let typestr : String        = idtype.into();

        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("        id: '{}'", idstr);
        debug!("      type: '{}'", typestr);

        self.prefix_of_files_for_module(owner) +
            "-" + &typestr[..] +
            "-" + &idstr[..] +
            ".imag"
    }

    fn prefix_of_files_for_module(&self, m: &Module) -> String {
        self.storepath.clone() + m.name()
    }

    fn filter_map_ids_to_files<'a, HP>(&self,
                                        m: &'a Module,
                                        p: &Parser<HP>,
                                        ids: IntoIter<FileID>)
        -> Vec<File<'a>>
        where HP: FileHeaderParser
    {
        ids.filter_map(|id| self.get_file_by_id(m, &id, p))
           .collect::<Vec<File>>()
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {

    fn new<S>(action: S, desc: S, data: Option<String>) -> StorageBackendError
        where S: Into<String>
    {
        StorageBackendError {
            action:         action.into(),
            desc:           desc.into(),
            data_dump:      data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::new(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}

fn globlist_to_file_id_vec(globlist: Paths) -> Vec<FileID> {
    globlist.filter_map(Result::ok)
            .map(|pbuf| FileID::from(&pbuf))
            .collect::<Vec<FileID>>()
}

<commit_msg>Refactor for readability<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::new(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    pub fn iter_ids(&self, m: &Module) -> Result<IntoIter<FileID>, StorageBackendError>
    {
        let globstr = self.prefix_of_files_for_module(m) + "*.imag";
        debug!("Globstring = {}", globstr);
        glob(&globstr[..])
            .and_then(|globlist| {
                debug!("Iterating over globlist");
                Ok(globlist_to_file_id_vec(globlist).into_iter())
            })
            .map_err(|e| {
                debug!("glob() returned error: {:?}", e);
                let serr = StorageBackendError::new(
                        "iter_ids()",
                        "Cannot iter on file ids",
                        None);
                // Why the hack is Error not implemented for glob::PatternError
                // serr.caused_by = Some(Box::new(e));
                serr
            })
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Result<IntoIter<File<'a>>, StorageBackendError>
        where HP: FileHeaderParser
    {
        self.iter_ids(m)
            .and_then(|ids| {
                debug!("Iterating ids and building files from them");
                debug!("  number of ids = {}", ids.len());
                Ok(self.filter_map_ids_to_files(m, p, ids).into_iter())
            })
            .map_err(|e| {
                debug!("StorageBackend::iter_ids() returned error = {:?}", e);
                let mut serr = StorageBackendError::new("iter_files()",
                                           "Cannot iter on files",
                                           None);
                serr.caused_by = Some(Box::new(e));
                serr
            })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::new(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::new(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::new(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::new(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: &FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        use std::ops::Index;

        debug!("Searching for file with id '{}'", id);

        if id.get_type() == FileIDType::NONE {
            // We don't know the hash type, so we glob() around a bit.
            debug!("Having FileIDType::NONE, so we glob() for the raw ID");

            let id_str = id.get_id().unwrap_or(String::from("INVALID"));
            let globstr = self.prefix_of_files_for_module(m) + "*" + &id_str[..] + ".imag";
            debug!("Globbing with globstr = '{}'", globstr);
            glob(&globstr[..]).map(|globlist| {
                let idvec = globlist_to_file_id_vec(globlist).into_iter();
                let mut vec = self.filter_map_ids_to_files(m, p, idvec);
                vec.reverse();
                vec.pop()
            }).unwrap_or({
                debug!("No glob matches, actually. We can't do anything at this point");
                None
            })
        } else {
            // The (hash)type is already in the FileID object, so we can just
            // build a path from the information we already have
            debug!("We know FileIDType, so we build the path directly now");
            let filepath = self.build_filepath_with_id(m, id.clone());
            if let Ok(mut fs) = FSFile::open(filepath) {
                let mut s = String::new();
                fs.read_to_string(&mut s);

                debug!("Success opening file with id '{}'", id);
                debug!("Parsing to internal structure now");
                p.read(s).and_then(|(h, d)| {
                    Ok(File::from_parser_result(m, id.clone(), h, d))
                }).ok()
            } else {
                debug!("No file with id '{}'", id);
                None
            }
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::new(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        let idstr   : String        = id.clone().into();
        let idtype  : FileIDType    = id.into();
        let typestr : String        = idtype.into();

        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("        id: '{}'", idstr);
        debug!("      type: '{}'", typestr);

        self.prefix_of_files_for_module(owner) +
            "-" + &typestr[..] +
            "-" + &idstr[..] +
            ".imag"
    }

    fn prefix_of_files_for_module(&self, m: &Module) -> String {
        self.storepath.clone() + m.name()
    }

    fn filter_map_ids_to_files<'a, HP>(&self,
                                        m: &'a Module,
                                        p: &Parser<HP>,
                                        ids: IntoIter<FileID>)
        -> Vec<File<'a>>
        where HP: FileHeaderParser
    {
        ids.filter_map(|id| self.get_file_by_id(m, &id, p))
           .collect::<Vec<File>>()
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {

    fn new<S>(action: S, desc: S, data: Option<String>) -> StorageBackendError
        where S: Into<String>
    {
        StorageBackendError {
            action:         action.into(),
            desc:           desc.into(),
            data_dump:      data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::new(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}

fn globlist_to_file_id_vec(globlist: Paths) -> Vec<FileID> {
    globlist.filter_map(Result::ok)
            .map(|pbuf| FileID::from(&pbuf))
            .collect::<Vec<FileID>>()
}

<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult = Result<(), StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
}

impl StorageBackend {

    pub fn new(basepath: String) -> StorageBackend {
        StorageBackend {
            basepath: basepath,
        }
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self) -> Option<Vec<FileID>> {
        debug!("Getting files from {}", self.basepath);
        let list = glob(&self.basepath[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, id: FileID, p: &Parser<HP>) -> Option<File>
        where HP: FileHeaderParser<'a>
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(id, h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.id())
    }

    fn build_filepath_with_id(&self, id: FileID) -> String {
        debug!("Building filepath for id '{}'", id);
        self.basepath.clone() + &id[..]
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<commit_msg>Implement StorageBackend::remove_file()<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult = Result<(), StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
}

impl StorageBackend {

    pub fn new(basepath: String) -> StorageBackend {
        StorageBackend {
            basepath: basepath,
        }
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self) -> Option<Vec<FileID>> {
        debug!("Getting files from {}", self.basepath);
        let list = glob(&self.basepath[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, id: FileID, p: &Parser<HP>) -> Option<File>
        where HP: FileHeaderParser<'a>
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(id, h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.id())
    }

    fn build_filepath_with_id(&self, id: FileID) -> String {
        debug!("Building filepath for id '{}'", id);
        self.basepath.clone() + &id[..]
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<|endoftext|>


<commit_before>use {SyntaxKind, Token};

#[macro_use]
mod parser;
mod grammar;

#[derive(Debug)]
pub(crate) enum Event {
    Start {
        kind: SyntaxKind,
        forward_parent: Option<u32>,
    },
    Finish,
    Token {
        kind: SyntaxKind,
        n_raw_tokens: u8,
    },
    Error {
        message: String,
    },
}

pub(crate) fn parse<'t>(text: &'t str, raw_tokens: &'t [Token]) -> Vec<Event> {
    let mut parser = parser::Parser::new(text, raw_tokens);
    grammar::file(&mut parser);
    parser.into_events()
}
<commit_msg>Document events a bit<commit_after>use {SyntaxKind, Token};

#[macro_use]
mod parser;
mod grammar;

/// `Parser` produces a flat list of `Event`s.
/// They are converted to a tree-structure in
/// a separate pass, via `TreeBuilder`.
#[derive(Debug)]
pub(crate) enum Event {
    /// This event signifies the start of the node.
    /// It should be either abandoned (in which case the
    /// `kind` is `TOMBSTONE`, and the event is ignored),
    /// or completed via a `Finish` event.
    ///
    /// All tokens between a `Start` and a `Finish` would
    /// become the children of the respective node.
    ///
    /// For left-recursive syntactic constructs, the parser produces
    /// a child node before it sees a parent. `forward_parent`
    /// exists to allow to tweak parent-child relationships.
    ///
    /// Consider this path
    ///
    /// foo::bar
    ///
    /// The events for it would look like this:
    ///
    ///
    /// START(PATH) IDENT('foo') FINISH START(PATH) COLONCOLON IDENT('bar') FINISH
    ///       |                          /\
    ///       |                          |
    ///       +------forward-parent------+
    ///
    /// And the tree would look like this
    ///
    ///    +--PATH---------+
    ///    |   |           |
    ///    |   |           |
    ///    |  '::'       'bar'
    ///    |
    ///   PATH
    ///    |
    ///   'foo'
    ///
    /// See also `CompleteMarker::precede`.
    Start {
        kind: SyntaxKind,
        forward_parent: Option<u32>,
    },

    /// Complete the previous `Start` event
    Finish,

    /// Produce a single leaf-element.
    /// `n_raw_tokens` is used to glue complex contextual tokens.
    /// For example, lexer tokenizes `>>` as `>`, `>`, and
    /// `n_raw_tokens = 2` is used to produced a single `>>`.
    Token {
        kind: SyntaxKind,
        n_raw_tokens: u8,
    },

    Error {
        message: String,
    },
}

pub(crate) fn parse<'t>(text: &'t str, raw_tokens: &'t [Token]) -> Vec<Event> {
    let mut parser = parser::Parser::new(text, raw_tokens);
    grammar::file(&mut parser);
    parser.into_events()
}
<|endoftext|>


<commit_before>
use pass;
use ir;

/// An IR strength reduction pass.
pub struct Inliner;

impl pass::Metadata for Inliner
{
    fn id(&self) -> pass::Id { pass::Id(0x32bbc291) }
    fn name(&self) -> &'static str { "inliner" }
}

impl pass::Transform<ir::Value> for Inliner
{
    fn run_function(&mut self,
                    func: ir::Function,
                    module: &ir::Module)
        -> ir::Function {

        use ::util::Identifiable;

        let _function = module.get_function(func.get_id());
        func
    }
}

// TODO: blamket impl for all passes
impl Into<pass::Info<ir::Value>> for Box<Inliner>
{
    fn into(self) -> pass::Info<ir::Value> {
        pass::Info::Transform(self)
    }
}

pub fn inline(inst: ir::Instruction) -> ir::Value {
    match inst {
        ir::Instruction::Call(i) => self::inline_call(i),
        _ => panic!("{} instructions cannot be inlined"),
    }
}

pub fn inline_call(_inst: ir::instruction::Call) -> ir::Value {
    unimplemented!();
}

<commit_msg>Removed panic triggering test case from inliner<commit_after>
use pass;
use ir;

/// An IR strength reduction pass.
pub struct Inliner;

impl pass::Metadata for Inliner
{
    fn id(&self) -> pass::Id { pass::Id(0x32bbc291) }
    fn name(&self) -> &'static str { "inliner" }
}

impl pass::Transform<ir::Value> for Inliner
{
    fn run_function(&mut self,
                    func: ir::Function,
                    _module: &ir::Module)
        -> ir::Function {
        func
    }
}

// TODO: blamket impl for all passes
impl Into<pass::Info<ir::Value>> for Box<Inliner>
{
    fn into(self) -> pass::Info<ir::Value> {
        pass::Info::Transform(self)
    }
}

pub fn inline(inst: ir::Instruction) -> ir::Value {
    match inst {
        ir::Instruction::Call(i) => self::inline_call(i),
        _ => panic!("{} instructions cannot be inlined"),
    }
}

pub fn inline_call(_inst: ir::instruction::Call) -> ir::Value {
    unimplemented!();
}

<|endoftext|>