<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 https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Keyword, Method, PHYSICAL_SIDES, ALL_SIDES, maybe_moz_logical_alias %>

<% data.new_style_struct("Border", inherited=False,
                   additional_methods=[Method("border_" + side + "_has_nonzero_width",
                                              "bool") for side in ["top", "right", "bottom", "left"]]) %>
<%
    def maybe_logical_spec(side, kind):
        if side[1]: # if it is logical
            return "https://drafts.csswg.org/css-logical-props/#propdef-border-%s-%s" % (side[0], kind)
        else:
            return "https://drafts.csswg.org/css-backgrounds/#border-%s-%s" % (side[0], kind)
%>
% for side in ALL_SIDES:
    <%
        side_name = side[0]
        is_logical = side[1]
    %>
    ${helpers.predefined_type(
        "border-%s-color" % side_name, "Color",
        "computed_value::T::currentcolor()",
        alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-color"),
        spec=maybe_logical_spec(side, "color"),
        animation_value_type="AnimatedColor",
        logical=is_logical,
        logical_group="border-color",
        allow_quirks=not is_logical,
        flags="APPLIES_TO_FIRST_LETTER",
        ignored_when_colors_disabled=True,
    )}

    ${helpers.predefined_type(
        "border-%s-style" % side_name, "BorderStyle",
        "specified::BorderStyle::None",
        alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
        spec=maybe_logical_spec(side, "style"),
        flags="APPLIES_TO_FIRST_LETTER",
        animation_value_type="discrete" if not is_logical else "none",
        logical=is_logical,
        logical_group="border-style",
        needs_context=False,
    )}

    ${helpers.predefined_type(
        "border-%s-width" % side_name,
        "BorderSideWidth",
        "crate::values::computed::NonNegativeLength::new(3.)",
        computed_type="crate::values::computed::NonNegativeLength",
        alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"),
        spec=maybe_logical_spec(side, "width"),
        animation_value_type="NonNegativeLength",
        logical=is_logical,
        logical_group="border-width",
        flags="APPLIES_TO_FIRST_LETTER GETCS_NEEDS_LAYOUT_FLUSH",
        allow_quirks=not is_logical,
        servo_restyle_damage="reflow rebuild_and_reflow_inline"
    )}
% endfor

${helpers.gecko_keyword_conversion(
    Keyword('border-style',
    "none solid double dotted dashed hidden groove ridge inset outset",
    gecko_enum_prefix="StyleBorderStyle",
    gecko_inexhaustive=True),
    type="crate::values::specified::BorderStyle",
)}

// FIXME(#4126): when gfx supports painting it, make this Size2D<LengthPercentage>
% for corner in ["top-left", "top-right", "bottom-right", "bottom-left"]:
    ${helpers.predefined_type(
        "border-" + corner + "-radius",
        "BorderCornerRadius",
        "computed::BorderCornerRadius::zero()",
        "parse",
        extra_prefixes="webkit",
        spec="https://drafts.csswg.org/css-backgrounds/#border-%s-radius" % corner,
        boxed=True,
        flags="APPLIES_TO_FIRST_LETTER",
        animation_value_type="BorderCornerRadius",
    )}
% endfor

${helpers.single_keyword(
    "box-decoration-break",
    "slice clone",
    gecko_enum_prefix="StyleBoxDecorationBreak",
    spec="https://drafts.csswg.org/css-break/#propdef-box-decoration-break",
    products="gecko",
    animation_value_type="discrete",
)}

${helpers.single_keyword(
    "-moz-float-edge",
    "content-box margin-box",
    gecko_ffi_name="mFloatEdge",
    gecko_enum_prefix="StyleFloatEdge",
    products="gecko",
    spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
    animation_value_type="discrete",
)}

${helpers.predefined_type(
    "border-image-source",
    "ImageLayer",
    initial_value="Either::First(None_)",
    initial_specified_value="Either::First(None_)",
    spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
    vector=False,
    animation_value_type="discrete",
    flags="APPLIES_TO_FIRST_LETTER",
    boxed=product == "servo",
    ignored_when_colors_disabled=True
)}

${helpers.predefined_type(
    "border-image-outset",
    "LengthOrNumberRect",
    parse_method="parse_non_negative",
    initial_value="computed::LengthOrNumberRect::all(computed::LengthOrNumber::zero())",
    initial_specified_value="specified::LengthOrNumberRect::all(specified::LengthOrNumber::zero())",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
    animation_value_type="discrete",
    flags="APPLIES_TO_FIRST_LETTER",
    boxed=True,
)}

${helpers.predefined_type(
    "border-image-repeat",
    "BorderImageRepeat",
    "computed::BorderImageRepeat::stretch()",
    initial_specified_value="specified::BorderImageRepeat::stretch()",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat",
    flags="APPLIES_TO_FIRST_LETTER",
)}

${helpers.predefined_type(
    "border-image-width",
    "BorderImageWidth",
    initial_value="computed::BorderImageWidth::all(computed::BorderImageSideWidth::one())",
    initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
    animation_value_type="discrete",
    flags="APPLIES_TO_FIRST_LETTER",
    boxed=True,
)}

${helpers.predefined_type(
    "border-image-slice",
    "BorderImageSlice",
    initial_value="computed::BorderImageSlice::hundred_percent()",
    initial_specified_value="specified::BorderImageSlice::hundred_percent()",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
    animation_value_type="discrete",
    flags="APPLIES_TO_FIRST_LETTER",
    boxed=True,
)}

// FIXME(emilio): Why does this live here? ;_;
#[cfg(feature = "gecko")]
impl crate::values::computed::BorderImageWidth {
    pub fn to_gecko_rect(&self, sides: &mut crate::gecko_bindings::structs::nsStyleSides) {
        use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue};
        use crate::gecko::values::GeckoStyleCoordConvertible;
        use crate::values::generics::border::BorderImageSideWidth;

        % for i in range(0, 4):
        match self.${i} {
            BorderImageSideWidth::Auto => {
                sides.data_at_mut(${i}).set_value(CoordDataValue::Auto)
            },
            BorderImageSideWidth::Length(l) => {
                l.to_gecko_style_coord(&mut sides.data_at_mut(${i}))
            },
            BorderImageSideWidth::Number(n) => {
                sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n.0))
            },
        }
        % endfor
    }

    pub fn from_gecko_rect(
        sides: &crate::gecko_bindings::structs::nsStyleSides,
    ) -> Option<crate::values::computed::BorderImageWidth> {
        use crate::gecko_bindings::structs::nsStyleUnit::{eStyleUnit_Factor, eStyleUnit_Auto};
        use crate::gecko_bindings::sugar::ns_style_coord::CoordData;
        use crate::gecko::values::GeckoStyleCoordConvertible;
        use crate::values::computed::{LengthPercentage, Number};
        use crate::values::generics::border::BorderImageSideWidth;
        use crate::values::generics::NonNegative;

        Some(
            crate::values::computed::BorderImageWidth::new(
                % for i in range(0, 4):
                match sides.data_at(${i}).unit() {
                    eStyleUnit_Auto => {
                        BorderImageSideWidth::Auto
                    },
                    eStyleUnit_Factor => {
                        BorderImageSideWidth::Number(
                            NonNegative(Number::from_gecko_style_coord(&sides.data_at(${i}))
                                .expect("sides[${i}] could not convert to Number")))
                    },
                    _ => {
                        BorderImageSideWidth::Length(
                            NonNegative(LengthPercentage::from_gecko_style_coord(&sides.data_at(${i}))
                                .expect("sides[${i}] could not convert to LengthPercentage")))
                    },
                },
                % endfor
            )
        )
    }
}
<commit_msg>style: Implement the flow-relative border-radius properties.<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 https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Keyword, Method, ALL_CORNERS, PHYSICAL_SIDES, ALL_SIDES, maybe_moz_logical_alias %>

<% data.new_style_struct("Border", inherited=False,
                   additional_methods=[Method("border_" + side + "_has_nonzero_width",
                                              "bool") for side in ["top", "right", "bottom", "left"]]) %>
<%
    def maybe_logical_spec(side, kind):
        if side[1]: # if it is logical
            return "https://drafts.csswg.org/css-logical-props/#propdef-border-%s-%s" % (side[0], kind)
        else:
            return "https://drafts.csswg.org/css-backgrounds/#border-%s-%s" % (side[0], kind)
%>
% for side in ALL_SIDES:
    <%
        side_name = side[0]
        is_logical = side[1]
    %>
    ${helpers.predefined_type(
        "border-%s-color" % side_name, "Color",
        "computed_value::T::currentcolor()",
        alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-color"),
        spec=maybe_logical_spec(side, "color"),
        animation_value_type="AnimatedColor",
        logical=is_logical,
        logical_group="border-color",
        allow_quirks=not is_logical,
        flags="APPLIES_TO_FIRST_LETTER",
        ignored_when_colors_disabled=True,
    )}

    ${helpers.predefined_type(
        "border-%s-style" % side_name, "BorderStyle",
        "specified::BorderStyle::None",
        alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
        spec=maybe_logical_spec(side, "style"),
        flags="APPLIES_TO_FIRST_LETTER",
        animation_value_type="discrete" if not is_logical else "none",
        logical=is_logical,
        logical_group="border-style",
        needs_context=False,
    )}

    ${helpers.predefined_type(
        "border-%s-width" % side_name,
        "BorderSideWidth",
        "crate::values::computed::NonNegativeLength::new(3.)",
        computed_type="crate::values::computed::NonNegativeLength",
        alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"),
        spec=maybe_logical_spec(side, "width"),
        animation_value_type="NonNegativeLength",
        logical=is_logical,
        logical_group="border-width",
        flags="APPLIES_TO_FIRST_LETTER GETCS_NEEDS_LAYOUT_FLUSH",
        allow_quirks=not is_logical,
        servo_restyle_damage="reflow rebuild_and_reflow_inline"
    )}
% endfor

${helpers.gecko_keyword_conversion(
    Keyword('border-style',
    "none solid double dotted dashed hidden groove ridge inset outset",
    gecko_enum_prefix="StyleBorderStyle",
    gecko_inexhaustive=True),
    type="crate::values::specified::BorderStyle",
)}

// FIXME(#4126): when gfx supports painting it, make this Size2D<LengthPercentage>
% for corner in ALL_CORNERS:
    <%
        corner_name = corner[0]
        is_logical = corner[1]
        if is_logical:
            prefixes = None
        else:
            prefixes = "webkit"
    %>
    ${helpers.predefined_type(
        "border-%s-radius" % corner_name,
        "BorderCornerRadius",
        "computed::BorderCornerRadius::zero()",
        "parse",
        extra_prefixes=prefixes,
        spec=maybe_logical_spec(corner, "radius"),
        boxed=True,
        flags="APPLIES_TO_FIRST_LETTER",
        animation_value_type="BorderCornerRadius",
        logical_group="border-radius",
        logical=is_logical,
    )}
% endfor

${helpers.single_keyword(
    "box-decoration-break",
    "slice clone",
    gecko_enum_prefix="StyleBoxDecorationBreak",
    spec="https://drafts.csswg.org/css-break/#propdef-box-decoration-break",
    products="gecko",
    animation_value_type="discrete",
)}

${helpers.single_keyword(
    "-moz-float-edge",
    "content-box margin-box",
    gecko_ffi_name="mFloatEdge",
    gecko_enum_prefix="StyleFloatEdge",
    products="gecko",
    spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
    animation_value_type="discrete",
)}

${helpers.predefined_type(
    "border-image-source",
    "ImageLayer",
    initial_value="Either::First(None_)",
    initial_specified_value="Either::First(None_)",
    spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
    vector=False,
    animation_value_type="discrete",
    flags="APPLIES_TO_FIRST_LETTER",
    boxed=product == "servo",
    ignored_when_colors_disabled=True
)}

${helpers.predefined_type(
    "border-image-outset",
    "LengthOrNumberRect",
    parse_method="parse_non_negative",
    initial_value="computed::LengthOrNumberRect::all(computed::LengthOrNumber::zero())",
    initial_specified_value="specified::LengthOrNumberRect::all(specified::LengthOrNumber::zero())",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
    animation_value_type="discrete",
    flags="APPLIES_TO_FIRST_LETTER",
    boxed=True,
)}

${helpers.predefined_type(
    "border-image-repeat",
    "BorderImageRepeat",
    "computed::BorderImageRepeat::stretch()",
    initial_specified_value="specified::BorderImageRepeat::stretch()",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat",
    flags="APPLIES_TO_FIRST_LETTER",
)}

${helpers.predefined_type(
    "border-image-width",
    "BorderImageWidth",
    initial_value="computed::BorderImageWidth::all(computed::BorderImageSideWidth::one())",
    initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
    animation_value_type="discrete",
    flags="APPLIES_TO_FIRST_LETTER",
    boxed=True,
)}

${helpers.predefined_type(
    "border-image-slice",
    "BorderImageSlice",
    initial_value="computed::BorderImageSlice::hundred_percent()",
    initial_specified_value="specified::BorderImageSlice::hundred_percent()",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
    animation_value_type="discrete",
    flags="APPLIES_TO_FIRST_LETTER",
    boxed=True,
)}

// FIXME(emilio): Why does this live here? ;_;
#[cfg(feature = "gecko")]
impl crate::values::computed::BorderImageWidth {
    pub fn to_gecko_rect(&self, sides: &mut crate::gecko_bindings::structs::nsStyleSides) {
        use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue};
        use crate::gecko::values::GeckoStyleCoordConvertible;
        use crate::values::generics::border::BorderImageSideWidth;

        % for i in range(0, 4):
        match self.${i} {
            BorderImageSideWidth::Auto => {
                sides.data_at_mut(${i}).set_value(CoordDataValue::Auto)
            },
            BorderImageSideWidth::Length(l) => {
                l.to_gecko_style_coord(&mut sides.data_at_mut(${i}))
            },
            BorderImageSideWidth::Number(n) => {
                sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n.0))
            },
        }
        % endfor
    }

    pub fn from_gecko_rect(
        sides: &crate::gecko_bindings::structs::nsStyleSides,
    ) -> Option<crate::values::computed::BorderImageWidth> {
        use crate::gecko_bindings::structs::nsStyleUnit::{eStyleUnit_Factor, eStyleUnit_Auto};
        use crate::gecko_bindings::sugar::ns_style_coord::CoordData;
        use crate::gecko::values::GeckoStyleCoordConvertible;
        use crate::values::computed::{LengthPercentage, Number};
        use crate::values::generics::border::BorderImageSideWidth;
        use crate::values::generics::NonNegative;

        Some(
            crate::values::computed::BorderImageWidth::new(
                % for i in range(0, 4):
                match sides.data_at(${i}).unit() {
                    eStyleUnit_Auto => {
                        BorderImageSideWidth::Auto
                    },
                    eStyleUnit_Factor => {
                        BorderImageSideWidth::Number(
                            NonNegative(Number::from_gecko_style_coord(&sides.data_at(${i}))
                                .expect("sides[${i}] could not convert to Number")))
                    },
                    _ => {
                        BorderImageSideWidth::Length(
                            NonNegative(LengthPercentage::from_gecko_style_coord(&sides.data_at(${i}))
                                .expect("sides[${i}] could not convert to LengthPercentage")))
                    },
                },
                % endfor
            )
        )
    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::path::Path;
use std::ptr;
use std::ffi::CString;

use libarchive3_sys::ffi;

use archive::{Entry, ExtractOptions, Handle, WriteFilter, WriteFormat};
use reader::{Reader, ReaderEntry};
use error::{ArchiveResult, ArchiveError};

pub struct Writer {
    handle: *mut ffi::Struct_archive,
}

pub struct Disk {
    handle: *mut ffi::Struct_archive,
}

pub struct Builder {
    handle: *mut ffi::Struct_archive,
    consumed: bool,
}

impl Writer {
    pub fn new(handle: *mut ffi::Struct_archive) -> Self {
        Writer { handle: handle }
    }
}

impl Handle for Writer {
    unsafe fn handle(&self) -> *mut ffi::Struct_archive {
        self.handle
    }
}

impl Drop for Writer {
    fn drop(&mut self) {
        unsafe {
            ffi::archive_write_free(self.handle());
        }
    }
}

impl Disk {
    pub fn new() -> Self {
        Disk::default()
    }

    // Retrieve the currently-set value for last block size. A value of -1 here indicates that the
    // library should use default values.
    pub fn bytes_in_last_block(&self) -> i32 {
        unsafe { ffi::archive_write_get_bytes_in_last_block(self.handle) }
    }

    // Retrieve the block size to be used for writing. A value of -1 here indicates that the
    // library should use default values. A value of zero indicates that internal blocking is
    // suppressed.
    pub fn bytes_per_block(&self) -> i32 {
        unsafe { ffi::archive_write_get_bytes_per_block(self.handle) }
    }

    pub fn set_bytes_per_block(&mut self, count: i32) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_set_bytes_per_block(self.handle, count);
        }
        ArchiveResult::from(self as &Handle)
    }

    pub fn set_bytes_in_last_block(&mut self, count: i32) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_set_bytes_in_last_block(self.handle, count);
        }
        ArchiveResult::from(self as &Handle)
    }

    // Set options for extraction built from `ExtractOptions`
    pub fn set_options(&self, eopt: &ExtractOptions) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_disk_set_options(self.handle, eopt.flags);
        }
        ArchiveResult::from(self as &Handle)
    }

    // This convenience function installs a standard set of user and group lookup functions. These
    // functions use getpwnam(3) and getgrnam(3) to convert names to ids, defaulting to the ids if
    // the names cannot be looked up. These functions also implement a simple memory cache to
    // reduce the number of calls to getpwnam(3) and getgrnam(3).
    pub fn set_standard_lookup(&self) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_disk_set_standard_lookup(self.handle);
        }
        ArchiveResult::from(self as &Handle)
    }

    // * Failures - HeaderPosition
    pub fn write<T: Reader>(&self, reader: &mut T, prefix: Option<&str>) -> ArchiveResult<usize> {
        if reader.header_position() != 0 {
            return Err(ArchiveError::HeaderPosition);
        }
        let mut bytes: usize = 0;
        let mut write_pending: bool = false;
        loop {
            {
                if let Some(entry) = reader.next_header() {
                    if let Some(pfx) = prefix {
                        let path = Path::new(pfx).join(entry.pathname());
                        try!(entry.set_pathname(path));
                    }
                    match self.write_header(entry) {
                        Ok(()) => (),
                        Err(e) => return Err(e),
                    }
                    if entry.size() > 0 {
                        write_pending = true
                    }
                } else {
                    break;
                }
            }
            if write_pending {
                bytes += try!(self.write_data(reader));
                write_pending = false;
            }
        }
        unsafe {
            match ffi::archive_write_finish_entry(self.handle()) {
                ffi::ARCHIVE_OK => Ok(bytes),
                _ => Err(ArchiveError::from(self as &Handle)),
            }
        }
    }

    pub fn close(&self) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_close(self.handle());
        }
        ArchiveResult::from(self as &Handle)
    }

    fn write_data<T: Reader>(&self, reader: &T) -> ArchiveResult<usize> {
        let mut buff = ptr::null();
        let mut size = 0;
        let mut offset = 0;

        unsafe {
            match ffi::archive_read_data_block(reader.handle(), &mut buff, &mut size, &mut offset) {
                ffi::ARCHIVE_EOF => Ok(size),
                ffi::ARCHIVE_OK => {
                    if ffi::archive_write_data_block(self.handle, buff, size, offset) < 0 {
                        Err(ArchiveError::from(self as &Handle))
                    } else {
                        Ok(size)
                    }
                }
                _ => Err(ArchiveError::from(reader as &Handle)),
            }
        }
    }

    fn write_header(&self, entry: &ReaderEntry) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_header(self.handle, entry.entry());
        }
        ArchiveResult::from(self as &Handle)
    }
}

impl Handle for Disk {
    unsafe fn handle(&self) -> *mut ffi::Struct_archive {
        self.handle
    }
}

impl Default for Disk {
    fn default() -> Self {
        unsafe {
            let handle = ffi::archive_write_disk_new();
            if handle.is_null() {
                panic!("Allocation error");
            }
            Disk { handle: handle }
        }
    }
}

impl Drop for Disk {
    fn drop(&mut self) {
        self.close().unwrap();
        unsafe {
            ffi::archive_write_free(self.handle());
        }
    }
}

impl Builder {
    pub fn new() -> Self {
        Builder::default()
    }

    pub fn add_filter(&mut self, filter: WriteFilter) -> ArchiveResult<()> {
        match filter {
            WriteFilter::B64Encode => unsafe {
                ffi::archive_write_add_filter_b64encode(self.handle);
            },
            WriteFilter::Bzip2 => unsafe {
                ffi::archive_write_add_filter_bzip2(self.handle);
            },
            WriteFilter::Compress => unsafe {
                ffi::archive_write_add_filter_compress(self.handle);
            },
            WriteFilter::Grzip => unsafe {
                ffi::archive_write_add_filter_grzip(self.handle);
            },
            WriteFilter::Gzip => unsafe {
                ffi::archive_write_add_filter_gzip(self.handle);
            },
            WriteFilter::Lrzip => unsafe {
                ffi::archive_write_add_filter_lrzip(self.handle);
            },
            WriteFilter::Lzip => unsafe {
                ffi::archive_write_add_filter_lzip(self.handle);
            },
            WriteFilter::Lzma => unsafe {
                ffi::archive_write_add_filter_lzma(self.handle);
            },
            WriteFilter::Lzop => unsafe {
                ffi::archive_write_add_filter_lzop(self.handle);
            },
            WriteFilter::None => unsafe {
                ffi::archive_write_add_filter_none(self.handle);
            },
            WriteFilter::Program(prog) => {
                let c_prog = CString::new(prog).unwrap();
                unsafe { ffi::archive_write_add_filter_program(self.handle, c_prog.as_ptr()) };

            }
            WriteFilter::UuEncode => unsafe {
                ffi::archive_write_add_filter_uuencode(self.handle);
            },
            WriteFilter::Xz => unsafe {
                ffi::archive_write_add_filter_xz(self.handle);
            },
        }
        ArchiveResult::from(self as &Handle)
    }

    pub fn set_format(&self, format: WriteFormat) -> ArchiveResult<()> {
        match format {
            WriteFormat::SevenZip => unsafe {
                ffi::archive_write_set_format_7zip(self.handle);
            },
            WriteFormat::ArBsd => unsafe {
                ffi::archive_write_set_format_ar_bsd(self.handle);
            },
            WriteFormat::ArSvr4 => unsafe {
                ffi::archive_write_set_format_ar_svr4(self.handle);
            },
            WriteFormat::Cpio => unsafe {
                ffi::archive_write_set_format_cpio(self.handle);
            },
            WriteFormat::CpioNewc => unsafe {
                ffi::archive_write_set_format_cpio_newc(self.handle);
            },
            WriteFormat::Gnutar => unsafe {
                ffi::archive_write_set_format_gnutar(self.handle);
            },
            WriteFormat::Iso9660 => unsafe {
                ffi::archive_write_set_format_iso9660(self.handle);
            },
            WriteFormat::Mtree => unsafe {
                ffi::archive_write_set_format_mtree(self.handle);
            },
            WriteFormat::MtreeClassic => unsafe {
                ffi::archive_write_set_format_mtree_classic(self.handle);
            },
            WriteFormat::Pax => unsafe {
                ffi::archive_write_set_format_pax(self.handle);
            },
            WriteFormat::PaxRestricted => unsafe {
                ffi::archive_write_set_format_pax_restricted(self.handle);
            },
            WriteFormat::Shar => unsafe {
                ffi::archive_write_set_format_shar(self.handle);
            },
            WriteFormat::SharDump => unsafe {
                ffi::archive_write_set_format_shar_dump(self.handle);
            },
            WriteFormat::Ustar => unsafe {
                ffi::archive_write_set_format_ustar(self.handle);
            },
            WriteFormat::V7tar => unsafe {
                ffi::archive_write_set_format_v7tar(self.handle);
            },
            WriteFormat::Xar => unsafe {
                ffi::archive_write_set_format_xar(self.handle);
            },
            WriteFormat::Zip => unsafe {
                ffi::archive_write_set_format_zip(self.handle);
            },
        }
        ArchiveResult::from(self as &Handle)
    }

    pub fn open_file<T: AsRef<Path>>(mut self, file: T) -> ArchiveResult<Writer> {
        if self.consumed {
            return Err(ArchiveError::Consumed);
        }
        let c_file = CString::new(file.as_ref().to_string_lossy().as_bytes()).unwrap();
        let res = unsafe { ffi::archive_write_open_filename(self.handle, c_file.as_ptr()) };
        match res {
            0 => {
                self.consumed = true;
                Ok(Writer::new(self.handle))
            }
            _ => Err(ArchiveError::from(&self as &Handle)),
        }
    }
}

impl Default for Builder {
    fn default() -> Self {
        unsafe {
            let handle = ffi::archive_write_new();
            if handle.is_null() {
                panic!("Allocation error");
            }
            Builder {
                handle: handle,
                consumed: false,
            }
        }
    }
}

impl Handle for Builder {
    unsafe fn handle(&self) -> *mut ffi::Struct_archive {
        self.handle
    }
}

impl Drop for Builder {
    fn drop(&mut self) {
        if !self.consumed {
            unsafe {
                ffi::archive_write_free(self.handle);
            }
        }
    }
}
<commit_msg>fix bug where all data blocks were not extracted to file<commit_after>use std::default::Default;
use std::path::Path;
use std::ptr;
use std::ffi::CString;

use libarchive3_sys::ffi;

use archive::{Entry, ExtractOptions, Handle, WriteFilter, WriteFormat};
use reader::{Reader, ReaderEntry};
use error::{ArchiveResult, ArchiveError};

pub struct Writer {
    handle: *mut ffi::Struct_archive,
}

pub struct Disk {
    handle: *mut ffi::Struct_archive,
}

pub struct Builder {
    handle: *mut ffi::Struct_archive,
    consumed: bool,
}

impl Writer {
    pub fn new(handle: *mut ffi::Struct_archive) -> Self {
        Writer { handle: handle }
    }
}

impl Handle for Writer {
    unsafe fn handle(&self) -> *mut ffi::Struct_archive {
        self.handle
    }
}

impl Drop for Writer {
    fn drop(&mut self) {
        unsafe {
            ffi::archive_write_free(self.handle());
        }
    }
}

impl Disk {
    pub fn new() -> Self {
        Disk::default()
    }

    // Retrieve the currently-set value for last block size. A value of -1 here indicates that the
    // library should use default values.
    pub fn bytes_in_last_block(&self) -> i32 {
        unsafe { ffi::archive_write_get_bytes_in_last_block(self.handle) }
    }

    // Retrieve the block size to be used for writing. A value of -1 here indicates that the
    // library should use default values. A value of zero indicates that internal blocking is
    // suppressed.
    pub fn bytes_per_block(&self) -> i32 {
        unsafe { ffi::archive_write_get_bytes_per_block(self.handle) }
    }

    pub fn set_bytes_per_block(&mut self, count: i32) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_set_bytes_per_block(self.handle, count);
        }
        ArchiveResult::from(self as &Handle)
    }

    pub fn set_bytes_in_last_block(&mut self, count: i32) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_set_bytes_in_last_block(self.handle, count);
        }
        ArchiveResult::from(self as &Handle)
    }

    // Set options for extraction built from `ExtractOptions`
    pub fn set_options(&self, eopt: &ExtractOptions) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_disk_set_options(self.handle, eopt.flags);
        }
        ArchiveResult::from(self as &Handle)
    }

    // This convenience function installs a standard set of user and group lookup functions. These
    // functions use getpwnam(3) and getgrnam(3) to convert names to ids, defaulting to the ids if
    // the names cannot be looked up. These functions also implement a simple memory cache to
    // reduce the number of calls to getpwnam(3) and getgrnam(3).
    pub fn set_standard_lookup(&self) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_disk_set_standard_lookup(self.handle);
        }
        ArchiveResult::from(self as &Handle)
    }

    // * Failures - HeaderPosition
    pub fn write<T: Reader>(&self, reader: &mut T, prefix: Option<&str>) -> ArchiveResult<usize> {
        if reader.header_position() != 0 {
            return Err(ArchiveError::HeaderPosition);
        }
        let mut bytes: usize = 0;
        let mut write_pending: bool = false;
        loop {
            {
                if let Some(entry) = reader.next_header() {
                    if let Some(pfx) = prefix {
                        let path = Path::new(pfx).join(entry.pathname());
                        try!(entry.set_pathname(path));
                    }
                    match self.write_header(entry) {
                        Ok(()) => (),
                        Err(e) => return Err(e),
                    }
                    if entry.size() > 0 {
                        write_pending = true
                    }
                } else {
                    break;
                }
            }
            if write_pending {
                bytes += try!(self.write_data(reader));
                write_pending = false;
            }
        }
        unsafe {
            match ffi::archive_write_finish_entry(self.handle()) {
                ffi::ARCHIVE_OK => Ok(bytes),
                _ => Err(ArchiveError::from(self as &Handle)),
            }
        }
    }

    pub fn close(&self) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_close(self.handle());
        }
        ArchiveResult::from(self as &Handle)
    }

    fn write_data<T: Reader>(&self, reader: &T) -> ArchiveResult<usize> {
        let mut buff = ptr::null();
        let mut size = 0;
        let mut offset = 0;

        unsafe {
            loop {
                match ffi::archive_read_data_block(reader.handle(),
                                                   &mut buff,
                                                   &mut size,
                                                   &mut offset) {
                    ffi::ARCHIVE_EOF => return Ok(size),
                    ffi::ARCHIVE_OK => {
                        if ffi::archive_write_data_block(self.handle, buff, size, offset) !=
                           ffi::ARCHIVE_OK as isize {
                            return Err(ArchiveError::from(self as &Handle));
                        }
                    }
                    _ => return Err(ArchiveError::from(reader as &Handle)),
                }
            }
        }
    }

    fn write_header(&self, entry: &ReaderEntry) -> ArchiveResult<()> {
        unsafe {
            ffi::archive_write_header(self.handle, entry.entry());
        }
        ArchiveResult::from(self as &Handle)
    }
}

impl Handle for Disk {
    unsafe fn handle(&self) -> *mut ffi::Struct_archive {
        self.handle
    }
}

impl Default for Disk {
    fn default() -> Self {
        unsafe {
            let handle = ffi::archive_write_disk_new();
            if handle.is_null() {
                panic!("Allocation error");
            }
            Disk { handle: handle }
        }
    }
}

impl Drop for Disk {
    fn drop(&mut self) {
        self.close().unwrap();
        unsafe {
            ffi::archive_write_free(self.handle());
        }
    }
}

impl Builder {
    pub fn new() -> Self {
        Builder::default()
    }

    pub fn add_filter(&mut self, filter: WriteFilter) -> ArchiveResult<()> {
        match filter {
            WriteFilter::B64Encode => unsafe {
                ffi::archive_write_add_filter_b64encode(self.handle);
            },
            WriteFilter::Bzip2 => unsafe {
                ffi::archive_write_add_filter_bzip2(self.handle);
            },
            WriteFilter::Compress => unsafe {
                ffi::archive_write_add_filter_compress(self.handle);
            },
            WriteFilter::Grzip => unsafe {
                ffi::archive_write_add_filter_grzip(self.handle);
            },
            WriteFilter::Gzip => unsafe {
                ffi::archive_write_add_filter_gzip(self.handle);
            },
            WriteFilter::Lrzip => unsafe {
                ffi::archive_write_add_filter_lrzip(self.handle);
            },
            WriteFilter::Lzip => unsafe {
                ffi::archive_write_add_filter_lzip(self.handle);
            },
            WriteFilter::Lzma => unsafe {
                ffi::archive_write_add_filter_lzma(self.handle);
            },
            WriteFilter::Lzop => unsafe {
                ffi::archive_write_add_filter_lzop(self.handle);
            },
            WriteFilter::None => unsafe {
                ffi::archive_write_add_filter_none(self.handle);
            },
            WriteFilter::Program(prog) => {
                let c_prog = CString::new(prog).unwrap();
                unsafe { ffi::archive_write_add_filter_program(self.handle, c_prog.as_ptr()) };

            }
            WriteFilter::UuEncode => unsafe {
                ffi::archive_write_add_filter_uuencode(self.handle);
            },
            WriteFilter::Xz => unsafe {
                ffi::archive_write_add_filter_xz(self.handle);
            },
        }
        ArchiveResult::from(self as &Handle)
    }

    pub fn set_format(&self, format: WriteFormat) -> ArchiveResult<()> {
        match format {
            WriteFormat::SevenZip => unsafe {
                ffi::archive_write_set_format_7zip(self.handle);
            },
            WriteFormat::ArBsd => unsafe {
                ffi::archive_write_set_format_ar_bsd(self.handle);
            },
            WriteFormat::ArSvr4 => unsafe {
                ffi::archive_write_set_format_ar_svr4(self.handle);
            },
            WriteFormat::Cpio => unsafe {
                ffi::archive_write_set_format_cpio(self.handle);
            },
            WriteFormat::CpioNewc => unsafe {
                ffi::archive_write_set_format_cpio_newc(self.handle);
            },
            WriteFormat::Gnutar => unsafe {
                ffi::archive_write_set_format_gnutar(self.handle);
            },
            WriteFormat::Iso9660 => unsafe {
                ffi::archive_write_set_format_iso9660(self.handle);
            },
            WriteFormat::Mtree => unsafe {
                ffi::archive_write_set_format_mtree(self.handle);
            },
            WriteFormat::MtreeClassic => unsafe {
                ffi::archive_write_set_format_mtree_classic(self.handle);
            },
            WriteFormat::Pax => unsafe {
                ffi::archive_write_set_format_pax(self.handle);
            },
            WriteFormat::PaxRestricted => unsafe {
                ffi::archive_write_set_format_pax_restricted(self.handle);
            },
            WriteFormat::Shar => unsafe {
                ffi::archive_write_set_format_shar(self.handle);
            },
            WriteFormat::SharDump => unsafe {
                ffi::archive_write_set_format_shar_dump(self.handle);
            },
            WriteFormat::Ustar => unsafe {
                ffi::archive_write_set_format_ustar(self.handle);
            },
            WriteFormat::V7tar => unsafe {
                ffi::archive_write_set_format_v7tar(self.handle);
            },
            WriteFormat::Xar => unsafe {
                ffi::archive_write_set_format_xar(self.handle);
            },
            WriteFormat::Zip => unsafe {
                ffi::archive_write_set_format_zip(self.handle);
            },
        }
        ArchiveResult::from(self as &Handle)
    }

    pub fn open_file<T: AsRef<Path>>(mut self, file: T) -> ArchiveResult<Writer> {
        if self.consumed {
            return Err(ArchiveError::Consumed);
        }
        let c_file = CString::new(file.as_ref().to_string_lossy().as_bytes()).unwrap();
        let res = unsafe { ffi::archive_write_open_filename(self.handle, c_file.as_ptr()) };
        match res {
            0 => {
                self.consumed = true;
                Ok(Writer::new(self.handle))
            }
            _ => Err(ArchiveError::from(&self as &Handle)),
        }
    }
}

impl Default for Builder {
    fn default() -> Self {
        unsafe {
            let handle = ffi::archive_write_new();
            if handle.is_null() {
                panic!("Allocation error");
            }
            Builder {
                handle: handle,
                consumed: false,
            }
        }
    }
}

impl Handle for Builder {
    unsafe fn handle(&self) -> *mut ffi::Struct_archive {
        self.handle
    }
}

impl Drop for Builder {
    fn drop(&mut self) {
        if !self.consumed {
            unsafe {
                ffi::archive_write_free(self.handle);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate nadezhda;

use nadezhda::grammar::Program;
use nadezhda::environment::Environment;
use nadezhda::population::Population;
use nadezhda::evaluate::Evaluator;
use nadezhda::darwin::evolve::succesion;

fn main() {
    let mut rng = rand::thread_rng();
    let environment: Environment = Environment::new(5);
    let mut last_population: Population = Population::new(5);

    let mut generation_count = 0;
    while generation_count < 100 {
        println!("[{}]", generation_count);
        let next_population = succesion(&mut rng, environment.clone(), last_population.clone());
        let Population(generation) = next_population.clone();
        let survivors: Vec<Program> = generation
            .iter()
            .map(|program| (program.clone(), program.evaluate_on(environment.clone())))
            .filter(|&(_, ref env)| env.cockroach_location - env.food_location == 0)
            .map(|(program, _)| program)
            .collect();

        if survivors.len() > 0 { break; }

        last_population = next_population;
        generation_count += 1;
    }
    println!("{:?}", last_population);

}
<commit_msg>Only show generation count after loop<commit_after>extern crate rand;
extern crate nadezhda;

use nadezhda::grammar::Program;
use nadezhda::environment::Environment;
use nadezhda::population::Population;
use nadezhda::evaluate::Evaluator;
use nadezhda::darwin::evolve::succesion;

fn main() {
    let mut rng = rand::thread_rng();
    let environment: Environment = Environment::new(5);
    let mut last_population: Population = Population::new(5);

    let mut generation_count = 0;
    while generation_count < 100 {
        let next_population = succesion(&mut rng, environment.clone(), last_population.clone());
        let Population(generation) = next_population.clone();
        let survivors: Vec<Program> = generation
            .iter()
            .map(|program| (program.clone(), program.evaluate_on(environment.clone())))
            .filter(|&(_, ref env)| env.cockroach_location - env.food_location == 0)
            .map(|(program, _)| program)
            .collect();

        if survivors.len() > 0 { break; }

        last_population = next_population;
        generation_count += 1;
    }
    println!("{} {:?}", generation_count, last_population);

}
<|endoftext|>


<commit_before>// test2.rs
// This is a test for the following sections:
// - Strings

// Ok, here are a bunch of values-- some are `Strings`, some are `&strs`. Your
// task is to call one of these two functions on each value depending on what
// you think each value is. That is, add either `string_slice` or `string`
// before the parentheses on each line. If you're right, it will compile!

// I AM NOT DONE

fn string_slice(arg: &str) {
    println!("{}", arg);
}
fn string(arg: String) {
    println!("{}", arg);
}

fn main() {
    ("blue");
    ("red".to_string());
    (String::from("hi"));
    ("rust is fun!".to_owned());
    ("nice weather".into());
    (format!("Interpolation {}", "Station"));
    (&String::from("abc")[0..1]);
    ("  hello there ".trim());
    ("Happy Monday!".to_string().replace("Mon", "Tues"));
    ("mY sHiFt KeY iS sTiCkY".to_lowercase());
}
<commit_msg>fix(test2): name of type String and &str (#394)<commit_after>// test2.rs
// This is a test for the following sections:
// - Strings

// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
// task is to call one of these two functions on each value depending on what
// you think each value is. That is, add either `string_slice` or `string`
// before the parentheses on each line. If you're right, it will compile!

// I AM NOT DONE

fn string_slice(arg: &str) {
    println!("{}", arg);
}
fn string(arg: String) {
    println!("{}", arg);
}

fn main() {
    ("blue");
    ("red".to_string());
    (String::from("hi"));
    ("rust is fun!".to_owned());
    ("nice weather".into());
    (format!("Interpolation {}", "Station"));
    (&String::from("abc")[0..1]);
    ("  hello there ".trim());
    ("Happy Monday!".to_string().replace("Mon", "Tues"));
    ("mY sHiFt KeY iS sTiCkY".to_lowercase());
}
<|endoftext|>


<commit_before>// TODO
<commit_msg>Add synchronizer skeleton<commit_after>use tokio::prelude::*;
use net::peer_pool::*;
use std::sync::Arc;
use blockchain::*;

pub struct Synchronizer {
    chain: Arc<Blockchain>,
    pool: Arc<PeerPool>
}

impl Synchronizer {
    pub fn new(chain: Arc<Blockchain>, pool: Arc<PeerPool>) -> Synchronizer {
        Synchronizer {
            chain,
            pool
        }
    }

    pub fn start(&self) {
        // TODO
    }
}
<|endoftext|>


<commit_before>extern crate mdbook;

mod dummy_book;

use dummy_book::DummyBook;
use mdbook::preprocess::{CmdPreprocessor, Preprocessor};
use mdbook::MDBook;

fn example() -> CmdPreprocessor {
    CmdPreprocessor::new(
        "nop-preprocessor".to_string(),
        "cargo run --example nop-preprocessor --".to_string(),
    )
}

#[test]
fn example_supports_whatever() {
    let cmd = example();

    let got = cmd.supports_renderer("whatever");

    assert_eq!(got, true);
}

#[test]
fn example_doesnt_support_not_supported() {
    let cmd = example();

    let got = cmd.supports_renderer("not-supported");

    assert_eq!(got, false);
}

#[test]
fn ask_the_preprocessor_to_blow_up() {
    let dummy_book = DummyBook::new();
    let temp = dummy_book.build().unwrap();
    let mut md = MDBook::load(temp.path()).unwrap();
    md.with_preprecessor(example());

    md.config
        .set("preprocessor.nop-preprocessor.blow-up", true)
        .unwrap();

    let got = md.build();

    assert!(got.is_err());
}

#[test]
fn process_the_dummy_book() {
    let dummy_book = DummyBook::new();
    let temp = dummy_book.build().unwrap();
    let mut md = MDBook::load(temp.path()).unwrap();
    md.with_preprecessor(example());

    md.build().unwrap();
}
<commit_msg>Update custom_preprocessors.rs<commit_after>extern crate mdbook;

mod dummy_book;

use dummy_book::DummyBook;
use mdbook::preprocess::{CmdPreprocessor, Preprocessor};
use mdbook::MDBook;

fn example() -> CmdPreprocessor {
    CmdPreprocessor::new(
        "nop-preprocessor".to_string(),
        "cargo run --example nop-preprocessor --".to_string(),
    )
}

#[test]
fn example_supports_whatever() {
    let cmd = example();

    let got = cmd.supports_renderer("whatever");

    assert_eq!(got, true);
}

#[test]
fn example_doesnt_support_not_supported() {
    let cmd = example();

    let got = cmd.supports_renderer("not-supported");

    assert_eq!(got, false);
}

#[test]
fn ask_the_preprocessor_to_blow_up() {
    let dummy_book = DummyBook::new();
    let temp = dummy_book.build().unwrap();
    let mut md = MDBook::load(temp.path()).unwrap();
    md.with_preprocessor(example());

    md.config
        .set("preprocessor.nop-preprocessor.blow-up", true)
        .unwrap();

    let got = md.build();

    assert!(got.is_err());
}

#[test]
fn process_the_dummy_book() {
    let dummy_book = DummyBook::new();
    let temp = dummy_book.build().unwrap();
    let mut md = MDBook::load(temp.path()).unwrap();
    md.with_preprocessor(example());

    md.build().unwrap();
}
<|endoftext|>


<commit_before>// ignore-windows: Unwind panicking does not currently work on Windows
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::cell::Cell;

thread_local! {
    static MY_COUNTER: Cell<usize> = Cell::new(0);
    static DROPPED: Cell<bool> = Cell::new(false);
    static HOOK_CALLED: Cell<bool> = Cell::new(false);
}

struct DropTester;

impl Drop for DropTester {
    fn drop(&mut self) {
        DROPPED.with(|c| {
            c.set(true);
        });
    }
}

fn do_panic_counter(do_panic: impl FnOnce(usize) -> !) {
    // If this gets leaked, it will be easy to spot
    // in Miri's leak report
    let _string = "LEAKED FROM do_panic_counter".to_string();

    // When we panic, this should get dropped during unwinding
    let _drop_tester = DropTester;

    // Check for bugs in Miri's panic implementation.
    // If do_panic_counter() somehow gets called more than once,
    // we'll generate a different panic message and stderr will differ.
    let old_val = MY_COUNTER.with(|c| {
        let val = c.get();
        c.set(val + 1);
        val
    });
    do_panic(old_val);
}

fn main() {
    let prev = std::panic::take_hook();
    std::panic::set_hook(Box::new(move |panic_info| {
        HOOK_CALLED.with(|h| h.set(true));
        prev(panic_info)
    }));

    test(|_old_val| std::panic!("Hello from panic: std"));
    test(|old_val| std::panic!(format!("Hello from panic: {:?}", old_val)));
    test(|old_val| std::panic!("Hello from panic: {:?}", old_val));
    test(|_old_val| std::panic!(1337));

    test(|_old_val| core::panic!("Hello from panic: core"));
    test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val)));
    test(|old_val| core::panic!("Hello from panic: {:?}", old_val));

    // Cleanup: reset to default hook.
    drop(std::panic::take_hook());

    eprintln!("Success!"); // Make sure we get this in stderr
}

fn test(do_panic: impl FnOnce(usize) -> !) {
    // Reset test flags.
    DROPPED.with(|c| c.set(false));
    HOOK_CALLED.with(|c| c.set(false));

    // Cause and catch a panic.
    let res = catch_unwind(AssertUnwindSafe(|| {
        let _string = "LEAKED FROM CLOSURE".to_string();
        do_panic_counter(do_panic)
    })).expect_err("do_panic() did not panic!");

    // See if we can extract panic message.
    match res.downcast::<String>() {
        Ok(s) => {
            eprintln!("Caught panic message (String): {}", s);
        }
        Err(res) =>
            if let Ok(s) = res.downcast::<&str>() {
                eprintln!("Caught panic message (&str): {}", s);
            } else {
                eprintln!("Failed get caught panic message.");
            }
    }

    // Test flags.
    assert!(DROPPED.with(|c| c.get()));
    assert!(HOOK_CALLED.with(|c| c.get()));
}

<commit_msg>improve style in catch_panic test<commit_after>// ignore-windows: Unwind panicking does not currently work on Windows
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::cell::Cell;

thread_local! {
    static MY_COUNTER: Cell<usize> = Cell::new(0);
    static DROPPED: Cell<bool> = Cell::new(false);
    static HOOK_CALLED: Cell<bool> = Cell::new(false);
}

struct DropTester;

impl Drop for DropTester {
    fn drop(&mut self) {
        DROPPED.with(|c| {
            c.set(true);
        });
    }
}

fn do_panic_counter(do_panic: impl FnOnce(usize) -> !) {
    // If this gets leaked, it will be easy to spot
    // in Miri's leak report
    let _string = "LEAKED FROM do_panic_counter".to_string();

    // When we panic, this should get dropped during unwinding
    let _drop_tester = DropTester;

    // Check for bugs in Miri's panic implementation.
    // If do_panic_counter() somehow gets called more than once,
    // we'll generate a different panic message and stderr will differ.
    let old_val = MY_COUNTER.with(|c| {
        let val = c.get();
        c.set(val + 1);
        val
    });
    do_panic(old_val);
}

fn main() {
    let prev = std::panic::take_hook();
    std::panic::set_hook(Box::new(move |panic_info| {
        HOOK_CALLED.with(|h| h.set(true));
        prev(panic_info)
    }));

    test(|_old_val| std::panic!("Hello from panic: std"));
    test(|old_val| std::panic!(format!("Hello from panic: {:?}", old_val)));
    test(|old_val| std::panic!("Hello from panic: {:?}", old_val));
    test(|_old_val| std::panic!(1337));

    test(|_old_val| core::panic!("Hello from panic: core"));
    test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val)));
    test(|old_val| core::panic!("Hello from panic: {:?}", old_val));

    // Cleanup: reset to default hook.
    drop(std::panic::take_hook());

    eprintln!("Success!"); // Make sure we get this in stderr
}

fn test(do_panic: impl FnOnce(usize) -> !) {
    // Reset test flags.
    DROPPED.with(|c| c.set(false));
    HOOK_CALLED.with(|c| c.set(false));

    // Cause and catch a panic.
    let res = catch_unwind(AssertUnwindSafe(|| {
        let _string = "LEAKED FROM CLOSURE".to_string();
        do_panic_counter(do_panic)
    })).expect_err("do_panic() did not panic!");

    // See if we can extract the panic message.
    if let Some(s) = res.downcast_ref::<String>() {
        eprintln!("Caught panic message (String): {}", s);
    } else if let Some(s) = res.downcast_ref::<&str>() {
        eprintln!("Caught panic message (&str): {}", s);
    } else {
        eprintln!("Failed get caught panic message.");
    }

    // Test flags.
    assert!(DROPPED.with(|c| c.get()));
    assert!(HOOK_CALLED.with(|c| c.get()));
}

<|endoftext|>


<commit_before>use database::models::NewTemporaryRole;
use util::ParsedDuration;

use chrono::{Utc, Duration};

use diesel;
use diesel::prelude::*;

use lalafell::error::*;
use lalafell::commands::prelude::*;
use lalafell::commands::{ChannelOrId, MentionOrId};

use structopt::clap::ArgGroup;

use unicase::UniCase;

use std::sync::Arc;

#[derive(BotCommand)]
pub struct TemporaryRoleCommand;

#[derive(Debug, StructOpt)]
#[structopt(about = "Give a role to a member for a given number of messages or time")]
pub struct Params {
  #[structopt(
    short = "w",
    long = "who",
    help = "The member to assign the role to"
  )]
  who: MentionOrId,
  #[structopt(
    short = "r",
    long = "role",
    help = "The role to assign to the member"
  )]
  role: String,
  #[structopt(
    short = "m",
    long = "messages",
    help = "The amount of messages for the role to last"
  )]
  messages: Option<u32>,
  #[structopt(
    short = "c",
    long = "channel",
    help = "The channel to count messages against, if any",
    conflicts_with = "time"
  )]
  channel: Option<ChannelOrId>,
  #[structopt(
    short = "t",
    long = "time",
    help = "The amount of time for the role to last"
  )]
  time: Option<ParsedDuration>
}

impl HasParams for TemporaryRoleCommand {
  type Params = Params;
}

impl<'a> PublicChannelCommand<'a> for TemporaryRoleCommand {
  fn run(&self, _: &Context, msg: &Message, guild_id: GuildId, _: Arc<RwLock<GuildChannel>>, params: &[&str]) -> CommandResult<'a> {
    let mut member = guild_id.member(&msg.author).chain_err(|| "could not get member")?;
    if !member.permissions().chain_err(|| "could not get permissions")?.manage_roles() {
      return Err(ExternalCommandFailure::default()
        .message(|e: CreateEmbed| e
          .title("Not enough permissions.")
          .description("You don't have enough permissions to use this command."))
        .wrap());
    }

    let params = self.params_then("temporaryrole", params, |a| a
      .setting(::structopt::clap::AppSettings::ArgRequiredElseHelp)
      .group(ArgGroup::with_name("m_or_t")
        .args(&["messages", "time"])
        .required(true)))?;

    let guild = guild_id.find().chain_err(|| "could not find guild in cache")?;

    let role_name = UniCase::new(params.role);
    let role = match guild.read().roles.values().find(|r| UniCase::new(r.name.as_str()) == role_name) {
      Some(r) => r.id,
      None => return Err("No such role.".into())
    };

    let messages = params.messages.map(|m| m as i32);
    let time = params.time
      .as_ref()
      .map(|t| Utc::now() + Duration::seconds(**t as i64))
      .map(|t| t.timestamp());
    let ntr = NewTemporaryRole::new(guild_id.0, params.who.0, role.0, msg.id.0, params.channel.map(|x| x.0), messages, time);
    let temp_role = ::bot::with_connection(|c| {
      use database::schema::temporary_roles::dsl;

      diesel::insert_into(dsl::temporary_roles).values(&ntr).get_result(c)
    }).chain_err(|| "could not store new temporary role")?;

    if let Some(t) = params.time {
      if *t < 600 {
        ::std::thread::spawn(move || {
          ::std::thread::sleep(Duration::seconds(*t as i64).to_std().unwrap());
          ::tasks::temporary_roles::remove_temporary_role(&temp_role);
        });
      }
    }

    member.add_role(role).chain_err(|| "could not add role")?;
    Ok(CommandSuccess::default())
  }
}
<commit_msg>fix: add role to target member<commit_after>use database::models::NewTemporaryRole;
use util::ParsedDuration;

use chrono::{Utc, Duration};

use diesel;
use diesel::prelude::*;

use lalafell::error::*;
use lalafell::commands::prelude::*;
use lalafell::commands::{ChannelOrId, MentionOrId};

use structopt::clap::ArgGroup;

use unicase::UniCase;

use std::sync::Arc;

#[derive(BotCommand)]
pub struct TemporaryRoleCommand;

#[derive(Debug, StructOpt)]
#[structopt(about = "Give a role to a member for a given number of messages or time")]
pub struct Params {
  #[structopt(
    short = "w",
    long = "who",
    help = "The member to assign the role to"
  )]
  who: MentionOrId,
  #[structopt(
    short = "r",
    long = "role",
    help = "The role to assign to the member"
  )]
  role: String,
  #[structopt(
    short = "m",
    long = "messages",
    help = "The amount of messages for the role to last"
  )]
  messages: Option<u32>,
  #[structopt(
    short = "c",
    long = "channel",
    help = "The channel to count messages against, if any",
    conflicts_with = "time"
  )]
  channel: Option<ChannelOrId>,
  #[structopt(
    short = "t",
    long = "time",
    help = "The amount of time for the role to last"
  )]
  time: Option<ParsedDuration>
}

impl HasParams for TemporaryRoleCommand {
  type Params = Params;
}

impl<'a> PublicChannelCommand<'a> for TemporaryRoleCommand {
  fn run(&self, _: &Context, msg: &Message, guild_id: GuildId, _: Arc<RwLock<GuildChannel>>, params: &[&str]) -> CommandResult<'a> {
    let member = guild_id.member(&msg.author).chain_err(|| "could not get member")?;
    if !member.permissions().chain_err(|| "could not get permissions")?.manage_roles() {
      return Err(ExternalCommandFailure::default()
        .message(|e: CreateEmbed| e
          .title("Not enough permissions.")
          .description("You don't have enough permissions to use this command."))
        .wrap());
    }

    let params = self.params_then("temporaryrole", params, |a| a
      .setting(::structopt::clap::AppSettings::ArgRequiredElseHelp)
      .group(ArgGroup::with_name("m_or_t")
        .args(&["messages", "time"])
        .required(true)))?;

    let guild = guild_id.find().chain_err(|| "could not find guild in cache")?;

    let mut target = match guild_id.member(*params.who) {
      Ok(m) => m,
      Err(_) => return Err("That person is not in this guild.".into())
    };

    let role_name = UniCase::new(params.role);
    let role = match guild.read().roles.values().find(|r| UniCase::new(r.name.as_str()) == role_name) {
      Some(r) => r.id,
      None => return Err("No such role.".into())
    };

    let messages = params.messages.map(|m| m as i32);
    let time = params.time
      .as_ref()
      .map(|t| Utc::now() + Duration::seconds(**t as i64))
      .map(|t| t.timestamp());
    let ntr = NewTemporaryRole::new(guild_id.0, params.who.0, role.0, msg.id.0, params.channel.map(|x| x.0), messages, time);
    let temp_role = ::bot::with_connection(|c| {
      use database::schema::temporary_roles::dsl;

      diesel::insert_into(dsl::temporary_roles).values(&ntr).get_result(c)
    }).chain_err(|| "could not store new temporary role")?;

    if let Some(t) = params.time {
      if *t < 600 {
        ::std::thread::spawn(move || {
          ::std::thread::sleep(Duration::seconds(*t as i64).to_std().unwrap());
          ::tasks::temporary_roles::remove_temporary_role(&temp_role);
        });
      }
    }

    target.add_role(role).chain_err(|| "could not add role")?;
    Ok(CommandSuccess::default())
  }
}
<|endoftext|>


<commit_before>use crate::{Lint, LintExtractor};
use std::collections::{BTreeMap, BTreeSet};
use std::error::Error;
use std::fmt::Write;
use std::fs;
use std::process::Command;

/// Descriptions of rustc lint groups.
static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
    ("unused", "Lints that detect things being declared but not used, or excess syntax"),
    ("rustdoc", "Rustdoc-specific lints"),
    ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
    ("nonstandard-style", "Violation of standard naming conventions"),
    ("future-incompatible", "Lints that detect code that has future-compatibility problems"),
    ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
];

type LintGroups = BTreeMap<String, BTreeSet<String>>;

impl<'a> LintExtractor<'a> {
    /// Updates the documentation of lint groups.
    pub(crate) fn generate_group_docs(&self, lints: &[Lint]) -> Result<(), Box<dyn Error>> {
        let groups = self.collect_groups()?;
        let groups_path = self.out_path.join("groups.md");
        let contents = fs::read_to_string(&groups_path)
            .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
        let new_contents =
            contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?);
        // Delete the output because rustbuild uses hard links in its copies.
        let _ = fs::remove_file(&groups_path);
        fs::write(&groups_path, new_contents)
            .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
        Ok(())
    }

    /// Collects the group names from rustc.
    fn collect_groups(&self) -> Result<LintGroups, Box<dyn Error>> {
        let mut result = BTreeMap::new();
        let mut cmd = Command::new(self.rustc_path);
        cmd.arg("-Whelp");
        let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
        if !output.status.success() {
            return Err(format!(
                "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
                output.status,
                std::str::from_utf8(&output.stderr).unwrap(),
                std::str::from_utf8(&output.stdout).unwrap(),
            )
            .into());
        }
        let stdout = std::str::from_utf8(&output.stdout).unwrap();
        let lines = stdout.lines();
        let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
        let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
        for line in table_start {
            if line.is_empty() {
                break;
            }
            let mut parts = line.trim().splitn(2, ' ');
            let name = parts.next().expect("name in group");
            if name == "warnings" {
                // This is special.
                continue;
            }
            let lints = parts
                .next()
                .ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
            let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
            assert!(result.insert(name.to_string(), lints).is_none());
        }
        if result.is_empty() {
            return Err(
                format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
            );
        }
        Ok(result)
    }

    fn make_groups_table(
        &self,
        lints: &[Lint],
        groups: &LintGroups,
    ) -> Result<String, Box<dyn Error>> {
        let mut result = String::new();
        let mut to_link = Vec::new();
        result.push_str("| Group | Description | Lints |\n");
        result.push_str("|-------|-------------|-------|\n");
        result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
        for (group_name, group_lints) in groups {
            let description = match GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) {
                Some((_, desc)) => desc,
                None if self.validate => {
                    return Err(format!(
                        "lint group `{}` does not have a description, \
                         please update the GROUP_DESCRIPTIONS list in \
                         src/tools/lint-docs/src/groups.rs",
                        group_name
                    )
                    .into());
                }
                None => {
                    eprintln!(
                        "warning: lint group `{}` is missing from the GROUP_DESCRIPTIONS list\n\
                         If this is a new lint group, please update the GROUP_DESCRIPTIONS in \
                         src/tools/lint-docs/src/groups.rs",
                        group_name
                    );
                    continue;
                }
            };
            to_link.extend(group_lints);
            let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
            write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", "))
                .unwrap();
        }
        result.push('\n');
        result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
        for lint_name in to_link {
            let lint_def =
                lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| {
                    format!(
                        "`rustc -W help` defined lint `{}` but that lint does not appear to exist",
                        lint_name
                    )
                })?;
            write!(
                result,
                "[{}]: listing/{}#{}\n",
                lint_name,
                lint_def.level.doc_filename(),
                lint_name
            )
            .unwrap();
        }
        Ok(result)
    }
}
<commit_msg>Auto merge of #80395 - ehuss:lint-docs-warn-missing, r=Mark-Simulacrum<commit_after>use crate::{Lint, LintExtractor};
use std::collections::{BTreeMap, BTreeSet};
use std::error::Error;
use std::fmt::Write;
use std::fs;
use std::process::Command;

/// Descriptions of rustc lint groups.
static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
    ("unused", "Lints that detect things being declared but not used, or excess syntax"),
    ("rustdoc", "Rustdoc-specific lints"),
    ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
    ("nonstandard-style", "Violation of standard naming conventions"),
    ("future-incompatible", "Lints that detect code that has future-compatibility problems"),
    ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
];

type LintGroups = BTreeMap<String, BTreeSet<String>>;

impl<'a> LintExtractor<'a> {
    /// Updates the documentation of lint groups.
    pub(crate) fn generate_group_docs(&self, lints: &[Lint]) -> Result<(), Box<dyn Error>> {
        let groups = self.collect_groups()?;
        let groups_path = self.out_path.join("groups.md");
        let contents = fs::read_to_string(&groups_path)
            .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
        let new_contents =
            contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?);
        // Delete the output because rustbuild uses hard links in its copies.
        let _ = fs::remove_file(&groups_path);
        fs::write(&groups_path, new_contents)
            .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
        Ok(())
    }

    /// Collects the group names from rustc.
    fn collect_groups(&self) -> Result<LintGroups, Box<dyn Error>> {
        let mut result = BTreeMap::new();
        let mut cmd = Command::new(self.rustc_path);
        cmd.arg("-Whelp");
        let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
        if !output.status.success() {
            return Err(format!(
                "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
                output.status,
                std::str::from_utf8(&output.stderr).unwrap(),
                std::str::from_utf8(&output.stdout).unwrap(),
            )
            .into());
        }
        let stdout = std::str::from_utf8(&output.stdout).unwrap();
        let lines = stdout.lines();
        let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
        let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
        for line in table_start {
            if line.is_empty() {
                break;
            }
            let mut parts = line.trim().splitn(2, ' ');
            let name = parts.next().expect("name in group");
            if name == "warnings" {
                // This is special.
                continue;
            }
            let lints = parts
                .next()
                .ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
            let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
            assert!(result.insert(name.to_string(), lints).is_none());
        }
        if result.is_empty() {
            return Err(
                format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
            );
        }
        Ok(result)
    }

    fn make_groups_table(
        &self,
        lints: &[Lint],
        groups: &LintGroups,
    ) -> Result<String, Box<dyn Error>> {
        let mut result = String::new();
        let mut to_link = Vec::new();
        result.push_str("| Group | Description | Lints |\n");
        result.push_str("|-------|-------------|-------|\n");
        result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
        for (group_name, group_lints) in groups {
            let description = match GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) {
                Some((_, desc)) => desc,
                None if self.validate => {
                    return Err(format!(
                        "lint group `{}` does not have a description, \
                         please update the GROUP_DESCRIPTIONS list in \
                         src/tools/lint-docs/src/groups.rs",
                        group_name
                    )
                    .into());
                }
                None => {
                    eprintln!(
                        "warning: lint group `{}` is missing from the GROUP_DESCRIPTIONS list\n\
                         If this is a new lint group, please update the GROUP_DESCRIPTIONS in \
                         src/tools/lint-docs/src/groups.rs",
                        group_name
                    );
                    continue;
                }
            };
            to_link.extend(group_lints);
            let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
            write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", "))
                .unwrap();
        }
        result.push('\n');
        result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
        for lint_name in to_link {
            let lint_def = match lints.iter().find(|l| l.name == lint_name.replace("-", "_")) {
                Some(def) => def,
                None => {
                    let msg = format!(
                        "`rustc -W help` defined lint `{}` but that lint does not \
                        appear to exist\n\
                        Check that the lint definition includes the appropriate doc comments.",
                        lint_name
                    );
                    if self.validate {
                        return Err(msg.into());
                    } else {
                        eprintln!("warning: {}", msg);
                        continue;
                    }
                }
            };
            write!(
                result,
                "[{}]: listing/{}#{}\n",
                lint_name,
                lint_def.level.doc_filename(),
                lint_name
            )
            .unwrap();
        }
        Ok(result)
    }
}
<|endoftext|>


<commit_before>use business::db::Repo;
use entities::*;
use rusted_cypher::GraphClient;
use business::error::RepoError;
use std::result;

type Result<T> = result::Result<T, RepoError>;

impl Repo<Entry> for GraphClient {

    fn get(&self, id: &str) -> Result<Entry> {
        let result = self.exec(cypher_stmt!(
        "MATCH (e:Entry)<--(s:EntryState) WHERE e.id = {id}
         WITH max(s.version) as version
         MATCH (e:Entry)<--(s:EntryState)
         WHERE e.id = {id} AND s.version = version
         WITH e, s
         MATCH s<-[:BELONGS_TO]-(c:Category)
         WITH e, s, collect(DISTINCT c.id) as categories
         RETURN {
           id          : e.id,
           created     : s.created,
           version     : s.version,
           title       : s.title,
           description : s.description,
           lat         : s.lat,
           lng         : s.lng,
           street      : s.street,
           zip         : s.zip,
           city        : s.city,
           country     : s.country,
           email       : s.email,
           telephone   : s.telephone,
           homepage    : s.homepage,
           categories  : categories,
           license     : s.license
         } AS e
         ORDER BY e.created DESC", {"id" => &id})?)?;
        let r = result.rows().next().ok_or(RepoError::NotFound)?;
        let e = r.get::<Entry>("e")?;
        Ok(e)
    }

    fn all(&self) -> Result<Vec<Entry>> {
        let result = self.exec(
        "MATCH (e:Entry)<--(x:EntryState)
          WITH distinct e, max(x.created) as max
          MATCH e<--(s:EntryState)
          WHERE s.created = max
          WITH e,s
          MATCH e<-[:BELONGS_TO]-s
          OPTIONAL MATCH (s)<-[:BELONGS_TO]-(c:Category)
          WITH e, s, collect(DISTINCT c.id) as categories
          RETURN {
            id          : e.id,
            created     : s.created,
            version     : s.version,
            title       : s.title,
            description : s.description,
            lat         : s.lat,
            lng         : s.lng,
            street      : s.street,
            zip         : s.zip,
            city        : s.city,
            country     : s.country,
            email       : s.email,
            telephone   : s.telephone,
            homepage    : s.homepage,
            categories  : categories,
            license     : s.license
          } AS e
          ORDER BY e.created DESC")?;
        Ok(result.rows()
            .filter_map(|r| r.get::<Entry>("e").ok())
            .collect::<Vec<Entry>>())
    }

    fn create(&mut self, e: &Entry) -> Result<()> {
        self.exec(cypher_stmt!(
        "MATCH (c:Category)
         WHERE c.id in {categories}
         WITH
            collect(DISTINCT c)    AS cats,
            collect(DISTINCT c.id) AS cat_ids,
            count(c)               AS cnt
         WHERE cnt > 0
         CREATE (e:Entry {id:{id}})
         MERGE e<-[:BELONGS_TO]-(s:EntryState {
           created : timestamp(),
           version : 1
         })
         SET s.title       = {title},
             s.description = {description},
             s.lat         = {lat},
             s.lng         = {lng},
             s.street      = {street},
             s.zip         = {zip},
             s.city        = {city},
             s.country     = {country},
             s.email       = {email},
             s.telephone   = {telephone},
             s.homepage    = {homepage},
             s.license     = {license}
         FOREACH (c IN cats |
           MERGE c-[:BELONGS_TO]->s
         )",
        {
            "id"          => &e.id,
            "title"       => &e.title,
            "description" => &e.description,
            "lat"         => &e.lat,
            "lng"         => &e.lng,
            "street"      => &e.street,
            "zip"         => &e.zip,
            "city"        => &e.city,
            "country"     => &e.country,
            "email"       => &e.email,
            "telephone"   => &e.telephone,
            "homepage"    => &e.homepage,
            "license"     => &e.license,
            "categories"  => &e.categories
        })?)?;
        Ok(())
    }

    fn update(&mut self, e: &Entry) -> Result<()> {
        self.exec(cypher_stmt!(
        "MATCH (e:Entry)<--(s:EntryState) WHERE e.id = {id}
         WITH max(s.version) as v
         MATCH (e:Entry)<--(old:EntryState)
         WHERE e.id = {id} AND old.version = v AND old.version + 1 = {version}
         WITH e
         MATCH (c:Category)
         WHERE c.id in {categories}
         WITH e, collect(DISTINCT c) AS cats, count(c) AS cnt
         WHERE cnt > 0
         MERGE e<-[:BELONGS_TO]-(s:EntryState {
           created : timestamp(),
           version : {version}
         })
         SET s.title       = {title},
             s.description = {description},
             s.lat         = {lat},
             s.lng         = {lng},
             s.street      = {street},
             s.zip         = {zip},
             s.city        = {city},
             s.country     = {country},
             s.email       = {email},
             s.telephone   = {telephone},
             s.homepage    = {homepage},
             s.license     = {license}
         FOREACH (c IN cats |
           MERGE (c)-[:BELONGS_TO]->s
         )
         WITH e, s
         MATCH s<-[:BELONGS_TO]-(c:Category)
         WITH e, s, collect(DISTINCT c.id) as categories",
        {
            "id"          => &e.id,
            "version"     => &e.version,
            "title"       => &e.title,
            "description" => &e.description,
            "lat"         => &e.lat,
            "lng"         => &e.lng,
            "street"      => &e.street,
            "zip"         => &e.zip,
            "city"        => &e.city,
            "country"     => &e.country,
            "email"       => &e.email,
            "telephone"   => &e.telephone,
            "homepage"    => &e.homepage,
            "license"     => &e.license,
            "categories"  => &e.categories
        })?)?;
        Ok(())
    }
}

impl Repo<Category> for GraphClient {

    fn get(&self, id: &str) -> Result<Category> {
        let result = self.exec(cypher_stmt!(
        "MATCH (e:Category)<--(s:CategoryState) WHERE c.id = {id}
         WITH max(s.created) as created
         MATCH (x:Category)<--(s:CategoryState)
         WHERE c.id = {id} AND s.created = created
         WITH c, s
         RETURN {
           id      : c.id,
           version : s.version,
           created : s.created,
           name    : s.name
         } AS c", {"id" => &id})?)?;
        let r = result.rows().next().ok_or(RepoError::NotFound)?;
        let c = r.get::<Category>("c")?;
        Ok(c)

    }

    fn all(&self) -> Result<Vec<Category>> {
        let result = self.exec(
        "MATCH (c:Category)<--(s:CategoryState)
         RETURN {
           id      : c.id,
           version : s.version,
           created : s.created,
           name    : s.name
         } AS c")?;
        Ok(result
            .rows()
            .filter_map(|r| r.get::<Category>("c").ok())
            .collect::<Vec<Category>>())
    }

    fn create(&mut self, c: &Category) -> Result<()> {
        self.exec(cypher_stmt!(
        "CREATE (c:Category {id:{id}})
         MERGE c<-[:BELONGS_TO]-(s:CategoryState {
           created : timestamp(),
           version : 1,
           name    : {name}
         })
         RETURN {
           id      : c.id,
           version : s.version,
           created : s.created,
           name    : s.name
         } AS c", {
           "id"   => &c.id,
           "name" => &c.name
        })?)?;
        Ok(())
    }

    fn update(&mut self, c: &Category) -> Result<()> {
        debug!("update category: {}", c.id);
        self.exec(cypher_stmt!(
        "MATCH (c:Category)<--(s:CategoryState) WHERE c.id = {id}
         WITH max(s.version) as v
         MATCH (c:Category)<--(old:CategoryState)
         WHERE c.id = {id} AND old.version = v AND old.version + 1 = {version}
         WITH c,e
         MERGE c<-[:BELONGS_TO]-(s:CategoryState {
           created : timestamp(),
           version : {version},
           name    : {name}
         })
         RETURN {
           id      : c.id,
           version : s.version,
           created : s.created,
           name    : s.name
         } AS c", {
           "id"      => &c.id,
           "version" => &c.version,
           "name"    => &c.name
         })?)?;
        Ok(())
    }
}
<commit_msg>fix(neo4j): add missing 'RETURN' to cypher statement<commit_after>use business::db::Repo;
use entities::*;
use rusted_cypher::GraphClient;
use business::error::RepoError;
use std::result;

type Result<T> = result::Result<T, RepoError>;

impl Repo<Entry> for GraphClient {

    fn get(&self, id: &str) -> Result<Entry> {
        let result = self.exec(cypher_stmt!(
        "MATCH (e:Entry)<--(s:EntryState) WHERE e.id = {id}
         WITH max(s.version) as version
         MATCH (e:Entry)<--(s:EntryState)
         WHERE e.id = {id} AND s.version = version
         WITH e, s
         MATCH s<-[:BELONGS_TO]-(c:Category)
         WITH e, s, collect(DISTINCT c.id) as categories
         RETURN {
           id          : e.id,
           created     : s.created,
           version     : s.version,
           title       : s.title,
           description : s.description,
           lat         : s.lat,
           lng         : s.lng,
           street      : s.street,
           zip         : s.zip,
           city        : s.city,
           country     : s.country,
           email       : s.email,
           telephone   : s.telephone,
           homepage    : s.homepage,
           categories  : categories,
           license     : s.license
         } AS e
         ORDER BY e.created DESC", {"id" => &id})?)?;
        let r = result.rows().next().ok_or(RepoError::NotFound)?;
        let e = r.get::<Entry>("e")?;
        Ok(e)
    }

    fn all(&self) -> Result<Vec<Entry>> {
        let result = self.exec(
        "MATCH (e:Entry)<--(x:EntryState)
          WITH distinct e, max(x.created) as max
          MATCH e<--(s:EntryState)
          WHERE s.created = max
          WITH e,s
          MATCH e<-[:BELONGS_TO]-s
          OPTIONAL MATCH (s)<-[:BELONGS_TO]-(c:Category)
          WITH e, s, collect(DISTINCT c.id) as categories
          RETURN {
            id          : e.id,
            created     : s.created,
            version     : s.version,
            title       : s.title,
            description : s.description,
            lat         : s.lat,
            lng         : s.lng,
            street      : s.street,
            zip         : s.zip,
            city        : s.city,
            country     : s.country,
            email       : s.email,
            telephone   : s.telephone,
            homepage    : s.homepage,
            categories  : categories,
            license     : s.license
          } AS e
          ORDER BY e.created DESC")?;
        Ok(result.rows()
            .filter_map(|r| r.get::<Entry>("e").ok())
            .collect::<Vec<Entry>>())
    }

    fn create(&mut self, e: &Entry) -> Result<()> {
        self.exec(cypher_stmt!(
        "MATCH (c:Category)
         WHERE c.id in {categories}
         WITH
            collect(DISTINCT c)    AS cats,
            collect(DISTINCT c.id) AS cat_ids,
            count(c)               AS cnt
         WHERE cnt > 0
         CREATE (e:Entry {id:{id}})
         MERGE e<-[:BELONGS_TO]-(s:EntryState {
           created : timestamp(),
           version : 1
         })
         SET s.title       = {title},
             s.description = {description},
             s.lat         = {lat},
             s.lng         = {lng},
             s.street      = {street},
             s.zip         = {zip},
             s.city        = {city},
             s.country     = {country},
             s.email       = {email},
             s.telephone   = {telephone},
             s.homepage    = {homepage},
             s.license     = {license}
         FOREACH (c IN cats |
           MERGE c-[:BELONGS_TO]->s
         )",
        {
            "id"          => &e.id,
            "title"       => &e.title,
            "description" => &e.description,
            "lat"         => &e.lat,
            "lng"         => &e.lng,
            "street"      => &e.street,
            "zip"         => &e.zip,
            "city"        => &e.city,
            "country"     => &e.country,
            "email"       => &e.email,
            "telephone"   => &e.telephone,
            "homepage"    => &e.homepage,
            "license"     => &e.license,
            "categories"  => &e.categories
        })?)?;
        Ok(())
    }

    fn update(&mut self, e: &Entry) -> Result<()> {
        self.exec(cypher_stmt!(
        "MATCH (e:Entry)<--(s:EntryState) WHERE e.id = {id}
         WITH max(s.version) as v
         MATCH (e:Entry)<--(old:EntryState)
         WHERE e.id = {id} AND old.version = v AND old.version + 1 = {version}
         WITH e
         MATCH (c:Category)
         WHERE c.id in {categories}
         WITH e, collect(DISTINCT c) AS cats, count(c) AS cnt
         WHERE cnt > 0
         MERGE e<-[:BELONGS_TO]-(s:EntryState {
           created : timestamp(),
           version : {version}
         })
         SET s.title       = {title},
             s.description = {description},
             s.lat         = {lat},
             s.lng         = {lng},
             s.street      = {street},
             s.zip         = {zip},
             s.city        = {city},
             s.country     = {country},
             s.email       = {email},
             s.telephone   = {telephone},
             s.homepage    = {homepage},
             s.license     = {license}
         FOREACH (c IN cats |
           MERGE (c)-[:BELONGS_TO]->s
         )
         WITH e, s
         MATCH s<-[:BELONGS_TO]-(c:Category)
         WITH e, s, collect(DISTINCT c.id) as categories
         RETURN e, s, categories",
        {
            "id"          => &e.id,
            "version"     => &e.version,
            "title"       => &e.title,
            "description" => &e.description,
            "lat"         => &e.lat,
            "lng"         => &e.lng,
            "street"      => &e.street,
            "zip"         => &e.zip,
            "city"        => &e.city,
            "country"     => &e.country,
            "email"       => &e.email,
            "telephone"   => &e.telephone,
            "homepage"    => &e.homepage,
            "license"     => &e.license,
            "categories"  => &e.categories
        })?)?;
        Ok(())
    }
}

impl Repo<Category> for GraphClient {

    fn get(&self, id: &str) -> Result<Category> {
        let result = self.exec(cypher_stmt!(
        "MATCH (e:Category)<--(s:CategoryState) WHERE c.id = {id}
         WITH max(s.created) as created
         MATCH (x:Category)<--(s:CategoryState)
         WHERE c.id = {id} AND s.created = created
         WITH c, s
         RETURN {
           id      : c.id,
           version : s.version,
           created : s.created,
           name    : s.name
         } AS c", {"id" => &id})?)?;
        let r = result.rows().next().ok_or(RepoError::NotFound)?;
        let c = r.get::<Category>("c")?;
        Ok(c)

    }

    fn all(&self) -> Result<Vec<Category>> {
        let result = self.exec(
        "MATCH (c:Category)<--(s:CategoryState)
         RETURN {
           id      : c.id,
           version : s.version,
           created : s.created,
           name    : s.name
         } AS c")?;
        Ok(result
            .rows()
            .filter_map(|r| r.get::<Category>("c").ok())
            .collect::<Vec<Category>>())
    }

    fn create(&mut self, c: &Category) -> Result<()> {
        self.exec(cypher_stmt!(
        "CREATE (c:Category {id:{id}})
         MERGE c<-[:BELONGS_TO]-(s:CategoryState {
           created : timestamp(),
           version : 1,
           name    : {name}
         })
         RETURN {
           id      : c.id,
           version : s.version,
           created : s.created,
           name    : s.name
         } AS c", {
           "id"   => &c.id,
           "name" => &c.name
        })?)?;
        Ok(())
    }

    fn update(&mut self, c: &Category) -> Result<()> {
        debug!("update category: {}", c.id);
        self.exec(cypher_stmt!(
        "MATCH (c:Category)<--(s:CategoryState) WHERE c.id = {id}
         WITH max(s.version) as v
         MATCH (c:Category)<--(old:CategoryState)
         WHERE c.id = {id} AND old.version = v AND old.version + 1 = {version}
         WITH c,e
         MERGE c<-[:BELONGS_TO]-(s:CategoryState {
           created : timestamp(),
           version : {version},
           name    : {name}
         })
         RETURN {
           id      : c.id,
           version : s.version,
           created : s.created,
           name    : s.name
         } AS c", {
           "id"      => &c.id,
           "version" => &c.version,
           "name"    => &c.name
         })?)?;
        Ok(())
    }
}
<|endoftext|>