<commit_before>//! A CLI tool for inspecting the contents of a DICOM file.
//! Despite the name, this tool may have a different interface and output
//! from other `dcmdump` tools, and does not aim to make a drop-in
//! replacement.
//!
//! Usage:
//!
//! ```none
//! dcmdump <file.dcm>
//! ```
use dicom::core::dictionary::{DataDictionary, DictionaryEntry};
use dicom::core::header::Header;
use dicom::core::value::{PrimitiveValue, Value as DicomValue};
use dicom::core::VR;
use dicom::object::mem::{InMemDicomObject, InMemElement};
use dicom::object::{open_file, DefaultDicomObject, FileMetaTable, StandardDataDictionary};

use std::borrow::Cow;
use std::io::{stdout, ErrorKind, Result as IoResult, Write};

type DynResult<T> = Result<T, Box<dyn std::error::Error>>;

fn main() -> DynResult<()> {
    let filename = ::std::env::args()
        .nth(1)
        .expect("Missing path to DICOM file");

    let obj = open_file(filename)?;

    match dump_file(obj) {
        Err(ref e) if e.kind() == ErrorKind::BrokenPipe => {
            Ok(()) // handle broken pipe separately with a no-op
        }
        Err(e) => Err(e.into()), // raise other errors
        _ => Ok(()),             // all good
    }
}

fn dump_file(obj: DefaultDicomObject) -> IoResult<()> {
    let mut to = stdout();
    write!(to, "# Dicom-File-Format\n\n")?;

    let meta = obj.meta();

    let width = 40;

    meta_dump(&mut to, &meta, width)?;

    dump(&mut to, &obj, width, 0)?;

    Ok(())
}

fn meta_dump<W>(to: &mut W, meta: &FileMetaTable, width: u32) -> IoResult<()>
where
    W: ?Sized + Write,
{
    writeln!(
        to,
        "Media Storage SOP Class UID: {}",
        meta.media_storage_sop_class_uid
    )?;
    writeln!(
        to,
        "Media Storage SOP Instance UID: {}",
        meta.media_storage_sop_instance_uid
    )?;
    writeln!(to, "Transfer Syntax: {}", meta.transfer_syntax)?;
    writeln!(to, "Implementation Class UID: {}", meta.transfer_syntax)?;

    if let Some(v) = meta.implementation_version_name.as_ref() {
        writeln!(to, "Implementation version name: {}", v)?;
    }
    if let Some(v) = meta.source_application_entity_title.as_ref() {
        writeln!(to, "Source Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.sending_application_entity_title.as_ref() {
        writeln!(to, "Sending Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.receiving_application_entity_title.as_ref() {
        writeln!(to, "Receiving Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.private_information_creator_uid.as_ref() {
        writeln!(to, "Private Information Creator UID: {}", v)?;
    }

    if let Some(v) = meta.private_information.as_ref() {
        writeln!(
            to,
            "Private Information: {}",
            format_value_list(v.iter().map(|n| format!("{:#x}", n)), width,)
        )?;
    }

    writeln!(to)?;
    Ok(())
}

fn dump<W, D>(to: &mut W, obj: &InMemDicomObject<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    for elem in obj {
        dump_element(&mut *to, &elem, width, depth)?;
    }

    Ok(())
}

fn dump_element<W, D>(to: &mut W, elem: &InMemElement<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    let indent = vec![b' '; (depth * 2) as usize];
    let tag_alias = StandardDataDictionary
        .by_tag(elem.tag())
        .map(DictionaryEntry::alias)
        .unwrap_or("«Unknown Attribute»");
    to.write_all(&indent)?;
    let vm = match elem.vr() {
        VR::OB | VR::OW | VR::UN => 1,
        _ => elem.value().multiplicity(),
    };

    if let DicomValue::Sequence { ref items, .. } = elem.value() {
        writeln!(
            to,
            "{} {}                                # {},    {}",
            elem.tag(),
            elem.vr(),
            vm,
            tag_alias
        )?;
        for item in items {
            dump_item(&mut *to, item, width, depth + 1)?;
        }
    } else {
        let vr = elem.vr();
        let value = elem.value().primitive().unwrap();
        let byte_len = value.calculate_byte_len();
        writeln!(
            to,
            "{} {} {:48} # {}, {} {}",
            elem.tag(),
            vr,
            value_summary(&value, vr, width),
            byte_len,
            vm,
            tag_alias
        )?;
    }

    Ok(())
}

fn dump_item<W, D>(to: &mut W, item: &InMemDicomObject<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    let indent: String = std::iter::repeat(' ').take((depth * 2) as usize).collect();
    let trail: String = std::iter::repeat(' ')
        .take(usize::max(21, width as usize - 21 - indent.len()))
        .collect();
    writeln!(to, "{}(FFFE,E000) na Item {} # 0, 0 Item", indent, trail)?;
    dump(to, item, width, depth + 1)?;
    writeln!(
        to,
        "{}(FFFE,E00D) na (ItemDelimitationItem)  # 0, 0 ItemDelimitationItem",
        indent,
    )?;
    Ok(())
}

fn value_summary(value: &PrimitiveValue, vr: VR, max_characters: u32) -> Cow<str> {
    use PrimitiveValue::*;
    match (value, vr) {
        (F32(values), _) => format_value_list(values, max_characters).into(),
        (F64(values), _) => format_value_list(values, max_characters).into(),
        (I32(values), _) => format_value_list(values, max_characters).into(),
        (I64(values), _) => format_value_list(values, max_characters).into(),
        (U32(values), _) => format_value_list(values, max_characters).into(),
        (U64(values), _) => format_value_list(values, max_characters).into(),
        (I16(values), _) => format_value_list(values, max_characters).into(),
        (U16(values), VR::OW) => format_value_list(
            values.into_iter().map(|n| format!("{:#x}", n)),
            max_characters,
        )
        .into(),
        (U16(values), _) => format_value_list(values, max_characters).into(),
        (U8(values), VR::OB) | (U8(values), VR::UN) => format_value_list(
            values.into_iter().map(|n| format!("{:#x}", n)),
            max_characters,
        )
        .into(),
        (U8(values), _) => format_value_list(values, max_characters).into(),
        (Tags(values), _) => format_value_list(values, max_characters).into(),
        (Strs(values), _) => format_value_list(values, max_characters).into(),
        (Date(values), _) => format_value_list(values, max_characters).into(),
        (Time(values), _) => format_value_list(values, max_characters).into(),
        (DateTime(values), _) => format_value_list(values, max_characters).into(),
        (Str(value), _) => cut_str(&value.to_string(), max_characters)
            .into_owned()
            .into(),
        (Empty, _) => "".into(),
    }
}

fn format_value_list<I>(values: I, max_characters: u32) -> String
where
    I: IntoIterator,
    I::Item: std::fmt::Display,
{
    let pieces = values.into_iter().take(64);
    let max = max_characters as usize;
    let mut o = String::with_capacity(max);
    for piece in pieces {
        o.push_str(&piece.to_string());
        o.push(',');
        if o.len() > max {
            break;
        }
    }
    o.pop();
    cut_str(&o, max_characters).into_owned()
}

fn cut_str(s: &str, max_characters: u32) -> Cow<str> {
    let max = (max_characters - 3) as usize;
    if s.len() > max {
        format!("{}...", &s[..max]).into()
    } else {
        s.into()
    }
}
<commit_msg>[dcmdump] update dcmdump<commit_after>//! A CLI tool for inspecting the contents of a DICOM file.
//! Despite the name, this tool may have a different interface and output
//! from other `dcmdump` tools, and does not aim to make a drop-in
//! replacement.
//!
//! Usage:
//!
//! ```none
//! dcmdump <file.dcm>
//! ```
use dicom::core::dictionary::{DataDictionary, DictionaryEntry};
use dicom::core::header::Header;
use dicom::core::value::{PrimitiveValue, Value as DicomValue};
use dicom::core::VR;
use dicom::object::mem::{InMemDicomObject, InMemElement};
use dicom::object::{open_file, DefaultDicomObject, FileMetaTable, StandardDataDictionary};

use std::borrow::Cow;
use std::io::{stdout, ErrorKind, Result as IoResult, Write};

type DynResult<T> = Result<T, Box<dyn std::error::Error>>;

fn main() -> DynResult<()> {
    let filename = ::std::env::args()
        .nth(1)
        .expect("Missing path to DICOM file");

    let obj = open_file(filename)?;

    match dump_file(obj) {
        Err(ref e) if e.kind() == ErrorKind::BrokenPipe => {
            Ok(()) // handle broken pipe separately with a no-op
        }
        Err(e) => Err(e.into()), // raise other errors
        _ => Ok(()),             // all good
    }
}

fn dump_file(obj: DefaultDicomObject) -> IoResult<()> {
    let mut to = stdout();
    write!(to, "# Dicom-File-Format\n\n")?;

    let meta = obj.meta();

    let width = 48;

    meta_dump(&mut to, &meta, width)?;

    dump(&mut to, &obj, width, 0)?;

    Ok(())
}

fn meta_dump<W>(to: &mut W, meta: &FileMetaTable, width: u32) -> IoResult<()>
where
    W: ?Sized + Write,
{
    writeln!(
        to,
        "Media Storage SOP Class UID: {}",
        meta.media_storage_sop_class_uid
    )?;
    writeln!(
        to,
        "Media Storage SOP Instance UID: {}",
        meta.media_storage_sop_instance_uid
    )?;
    writeln!(to, "Transfer Syntax: {}", meta.transfer_syntax)?;
    writeln!(to, "Implementation Class UID: {}", meta.transfer_syntax)?;

    if let Some(v) = meta.implementation_version_name.as_ref() {
        writeln!(to, "Implementation version name: {}", v)?;
    }
    if let Some(v) = meta.source_application_entity_title.as_ref() {
        writeln!(to, "Source Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.sending_application_entity_title.as_ref() {
        writeln!(to, "Sending Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.receiving_application_entity_title.as_ref() {
        writeln!(to, "Receiving Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.private_information_creator_uid.as_ref() {
        writeln!(to, "Private Information Creator UID: {}", v)?;
    }

    if let Some(v) = meta.private_information.as_ref() {
        writeln!(
            to,
            "Private Information: {}",
            format_value_list(v.iter().map(|n| format!("{:#x}", n)), width,)
        )?;
    }

    writeln!(to)?;
    Ok(())
}

fn dump<W, D>(to: &mut W, obj: &InMemDicomObject<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    for elem in obj {
        dump_element(&mut *to, &elem, width, depth)?;
    }

    Ok(())
}

fn dump_element<W, D>(to: &mut W, elem: &InMemElement<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    let indent = vec![b' '; (depth * 2) as usize];
    let tag_alias = StandardDataDictionary
        .by_tag(elem.tag())
        .map(DictionaryEntry::alias)
        .unwrap_or("«Unknown Attribute»");
    to.write_all(&indent)?;
    let vm = match elem.vr() {
        VR::OB | VR::OW | VR::UN => 1,
        _ => elem.value().multiplicity(),
    };

    match elem.value() {
        DicomValue::Sequence { items, .. } => {
            writeln!(
                to,
                "{} {} {:48} # {},    {}",
                elem.tag(),
                elem.vr(),
                "",
                vm,
                tag_alias
            )?;
            for item in items {
                dump_item(&mut *to, item, width, depth + 2)?;
            }
            writeln!(
                to,
                "(FFFE, E0DD) na (SequenceDelimitationItem) {:20} # 0, SequenceDelimitationItem",
                "",
            )?;
        }
        DicomValue::PixelSequence {
            fragments,
            offset_table,
        } => {
            // write pixel sequence start line
            let vr = elem.vr();
            let num_items = 1 + fragments.len();
            writeln!(
                to,
                "{} {} (PixelSequence=#{}) {:29} # u/l, 1 PixelData",
                elem.tag(),
                vr,
                num_items,
                ""
            )?;

            // write offset table
            let byte_len = offset_table.len();
            writeln!(
                to,
                "  (FFFE,E000) pi {:48} # {}, 1 Item",
                item_value_summary(&offset_table, width),
                byte_len,
            )?;

            // write compressed fragments
            for fragment in fragments {
                let byte_len = fragment.len();
                writeln!(
                    to,
                    "  (FFFE,E000) pi {:48} # {}, 1 Item",
                    item_value_summary(&fragment, width),
                    byte_len,
                )?;
            }
        }
        DicomValue::Primitive(value) => {
            let vr = elem.vr();
            let byte_len = value.calculate_byte_len();
            writeln!(
                to,
                "{} {} {:48} # {}, {} {}",
                elem.tag(),
                vr,
                value_summary(&value, vr, width),
                byte_len,
                vm,
                tag_alias
            )?;
        }
    }

    Ok(())
}

fn dump_item<W, D>(to: &mut W, item: &InMemDicomObject<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    let indent: String = std::iter::repeat(' ').take((depth * 2) as usize).collect();
    let trail: String = std::iter::repeat(' ')
        .take(usize::max(21, width as usize - 4 - indent.len()))
        .collect();
    writeln!(to, "{}(FFFE,E000) na Item {} # 0, 0 Item", indent, trail)?;
    dump(to, item, width, depth + 1)?;
    writeln!(
        to,
        "{}(FFFE,E00D) na (ItemDelimitationItem) {:23} # 0, 0 ItemDelimitationItem",
        indent,
        ""
    )?;
    Ok(())
}

fn value_summary(value: &PrimitiveValue, vr: VR, max_characters: u32) -> Cow<str> {
    use PrimitiveValue::*;
    match (value, vr) {
        (F32(values), _) => format_value_list(values, max_characters).into(),
        (F64(values), _) => format_value_list(values, max_characters).into(),
        (I32(values), _) => format_value_list(values, max_characters).into(),
        (I64(values), _) => format_value_list(values, max_characters).into(),
        (U32(values), _) => format_value_list(values, max_characters).into(),
        (U64(values), _) => format_value_list(values, max_characters).into(),
        (I16(values), _) => format_value_list(values, max_characters).into(),
        (U16(values), VR::OW) => format_value_list(
            values.into_iter().map(|n| format!("{:02X}", n)),
            max_characters,
        )
        .into(),
        (U16(values), _) => format_value_list(values, max_characters).into(),
        (U8(values), VR::OB) | (U8(values), VR::UN) => format_value_list(
            values.into_iter().map(|n| format!("{:02X}", n)),
            max_characters,
        )
        .into(),
        (U8(values), _) => format_value_list(values, max_characters).into(),
        (Tags(values), _) => format_value_list(values, max_characters).into(),
        (Strs(values), _) => format_value_list(values, max_characters).into(),
        (Date(values), _) => format_value_list(values, max_characters).into(),
        (Time(values), _) => format_value_list(values, max_characters).into(),
        (DateTime(values), _) => format_value_list(values, max_characters).into(),
        (Str(value), _) => cut_str(&value.to_string(), max_characters)
            .into_owned()
            .into(),
        (Empty, _) => "".into(),
    }
}

fn item_value_summary(data: &[u8], max_characters: u32) -> String {
    format_value_list(
        data.into_iter().map(|n| format!("{:02X}", n)),
        max_characters,
    )
}

fn format_value_list<I>(values: I, max_characters: u32) -> String
where
    I: IntoIterator,
    I::Item: std::fmt::Display,
{
    let pieces = values.into_iter().take(64);
    let max = max_characters as usize;
    let mut o = String::with_capacity(max);
    for piece in pieces {
        o.push_str(&piece.to_string());
        o.push('\\');
        if o.len() > max {
            break;
        }
    }
    o.pop();
    cut_str(&o, max_characters).into_owned()
}

fn cut_str(s: &str, max_characters: u32) -> Cow<str> {
    let max = (max_characters - 3) as usize;
    if s.len() > max {
        format!("{}...", &s[..max]).into()
    } else {
        s.into()
    }
}
<|endoftext|>


<commit_before>use std::ops;
use std::{f64, i32};

use libc;

use glib::object::ObjectClass;
use glib::subclass;
use glib::subclass::object::ObjectClassSubclassExt;
use glib::subclass::prelude::*;
use glib::translate::*;
use glib::value::{FromValue, FromValueOptional, SetValue};
use glib::{ParamFlags, ParamSpec, StaticType, ToValue, Type, Value};

use glib_sys;
use gobject_sys;

use handle::Handle;

extern "C" {
    fn rsvg_handle_flags_get_type() -> glib_sys::GType;
}

mod handle_flags {
    // The following is entirely stolen from the auto-generated code
    // for GBindingFlags, from gtk-rs/glib/src/gobject/auto/flags.rs

    use super::*;

    // Keep these in sync with rsvg.h:RsvgHandleFlags
    #[cfg_attr(rustfmt, rustfmt_skip)]
    bitflags! {
        pub struct HandleFlags: u32 {
            const NONE            = 0;
            const UNLIMITED       = 1 << 0;
            const KEEP_IMAGE_DATA = 1 << 1;
        }
    }

    pub type RsvgHandleFlags = libc::c_uint;

    impl ToGlib for HandleFlags {
        type GlibType = RsvgHandleFlags;

        fn to_glib(&self) -> RsvgHandleFlags {
            self.bits()
        }
    }

    impl FromGlib<RsvgHandleFlags> for HandleFlags {
        fn from_glib(value: RsvgHandleFlags) -> HandleFlags {
            HandleFlags::from_bits_truncate(value)
        }
    }

    impl StaticType for HandleFlags {
        fn static_type() -> Type {
            unsafe { from_glib(rsvg_handle_flags_get_type()) }
        }
    }

    impl<'a> FromValueOptional<'a> for HandleFlags {
        unsafe fn from_value_optional(value: &Value) -> Option<Self> {
            Some(FromValue::from_value(value))
        }
    }

    impl<'a> FromValue<'a> for HandleFlags {
        unsafe fn from_value(value: &Value) -> Self {
            from_glib(gobject_sys::g_value_get_flags(value.to_glib_none().0))
        }
    }

    impl SetValue for HandleFlags {
        unsafe fn set_value(value: &mut Value, this: &Self) {
            gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, this.to_glib())
        }
    }
}

pub use self::handle_flags::*;

// Keep this in sync with rsvg.h:RsvgHandleClass
#[repr(C)]
pub struct RsvgHandleClass {
    parent: gobject_sys::GObjectClass,

    _abi_padding: [glib_sys::gpointer; 15],
}

// Keep this in sync with rsvg.h:RsvgHandle
#[repr(C)]
pub struct RsvgHandle {
    parent: gobject_sys::GObject,

    _abi_padding: [glib_sys::gpointer; 16],
}

unsafe impl ClassStruct for RsvgHandleClass {
    type Type = Handle;
}

unsafe impl InstanceStruct for RsvgHandle {
    type Type = Handle;
}

impl ops::Deref for RsvgHandleClass {
    type Target = ObjectClass;

    fn deref(&self) -> &Self::Target {
        unsafe { &*(self as *const _ as *const Self::Target) }
    }
}

impl ops::DerefMut for RsvgHandleClass {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *(self as *mut _ as *mut Self::Target) }
    }
}

static PROPERTIES: [subclass::Property; 11] = [
    subclass::Property("flags", |name| {
        ParamSpec::flags(
            name,
            "Flags",
            "Loading flags",
            HandleFlags::static_type(),
            0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT_ONLY,
        )
    }),
    subclass::Property("dpi-x", |name| {
        ParamSpec::double(
            name,
            "Horizontal DPI",
            "Horizontal resolution in dots per inch",
            0.0,
            f64::MAX,
            0.0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("dpi-y", |name| {
        ParamSpec::double(
            name,
            "Vertical DPI",
            "Vertical resolution in dots per inch",
            0.0,
            f64::MAX,
            0.0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("base-uri", |name| {
        ParamSpec::string(
            name,
            "Base URI",
            "Base URI for resolving relative references",
            None,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("width", |name| {
        ParamSpec::int(
            name,
            "Image width",
            "Image width",
            0,
            i32::MAX,
            0,
            ParamFlags::READABLE,
        )
    }),
    subclass::Property("height", |name| {
        ParamSpec::int(
            name,
            "Image height",
            "Image height",
            0,
            i32::MAX,
            0,
            ParamFlags::READABLE,
        )
    }),
    subclass::Property("em", |name| {
        ParamSpec::double(name, "em", "em", 0.0, f64::MAX, 0.0, ParamFlags::READABLE)
    }),
    subclass::Property("ex", |name| {
        ParamSpec::double(name, "ex", "ex", 0.0, f64::MAX, 0.0, ParamFlags::READABLE)
    }),
    subclass::Property("title", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
    subclass::Property("desc", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
    subclass::Property("metadata", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
];

impl ObjectSubclass for Handle {
    const NAME: &'static str = "RsvgHandle";

    type ParentType = glib::Object;

    // We don't use subclass:simple::InstanceStruct and ClassStruct
    // because we need to maintain the respective _abi_padding of each
    // of RsvgHandleClass and RsvgHandle.

    type Instance = RsvgHandle;
    type Class = RsvgHandleClass;

    glib_object_subclass!();

    fn class_init(klass: &mut RsvgHandleClass) {
        klass.install_properties(&PROPERTIES);
    }

    fn new() -> Self {
        Handle::new()
    }
}

impl ObjectImpl for Handle {
    glib_object_impl!();

    fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
        let prop = &PROPERTIES[id];

        match *prop {
            subclass::Property("flags", ..) => {
                let v: HandleFlags = value.get().expect("flags value has incorrect type");

                self.set_load_flags(v);
            }

            subclass::Property("dpi-x", ..) => {
                self.set_dpi_x(value.get().expect("dpi-x value has incorrect type"));
            }

            subclass::Property("dpi-y", ..) => {
                self.set_dpi_y(value.get().expect("dpi-y value has incorrect type"));
            }

            subclass::Property("base-uri", ..) => {
                let v: Option<String> = value.get();;

                // rsvg_handle_set_base_uri() expects non-NULL URI strings,
                // but the "base-uri" property can be set to NULL due to a missing
                // construct-time property.

                if let Some(s) = v {
                    self.set_base_url(&s);
                }
            }

            _ => unreachable!("invalid property id {}", id),
        }
    }

    fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id];

        match *prop {
            subclass::Property("flags", ..) => Ok(self.load_flags.get().to_flags().to_value()),
            subclass::Property("dpi-x", ..) => Ok(self.dpi.get().x().to_value()),
            subclass::Property("dpi-y", ..) => Ok(self.dpi.get().y().to_value()),

            subclass::Property("base-uri", ..) => Ok(self
                .base_url
                .borrow()
                .as_ref()
                .map(|url| url.as_str())
                .to_value()),

            subclass::Property("width", ..) => Ok(self.get_dimensions_no_error().width.to_value()),
            subclass::Property("height", ..) => {
                Ok(self.get_dimensions_no_error().height.to_value())
            }

            subclass::Property("em", ..) => Ok(self.get_dimensions_no_error().em.to_value()),
            subclass::Property("ex", ..) => Ok(self.get_dimensions_no_error().ex.to_value()),

            // the following three are deprecated
            subclass::Property("title", ..) => Ok((None as Option<String>).to_value()),
            subclass::Property("desc", ..) => Ok((None as Option<String>).to_value()),
            subclass::Property("metadata", ..) => Ok((None as Option<String>).to_value()),

            _ => unreachable!("invalid property id={} for RsvgHandle", id),
        }
    }
}

pub fn get_rust_handle<'a>(handle: *const RsvgHandle) -> &'a Handle {
    let handle = unsafe { &*handle };
    handle.get_impl()
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_handle_rust_get_type() -> glib_sys::GType {
    Handle::get_type().to_glib()
}
<commit_msg>Fix typo<commit_after>use std::ops;
use std::{f64, i32};

use libc;

use glib::object::ObjectClass;
use glib::subclass;
use glib::subclass::object::ObjectClassSubclassExt;
use glib::subclass::prelude::*;
use glib::translate::*;
use glib::value::{FromValue, FromValueOptional, SetValue};
use glib::{ParamFlags, ParamSpec, StaticType, ToValue, Type, Value};

use glib_sys;
use gobject_sys;

use handle::Handle;

extern "C" {
    fn rsvg_handle_flags_get_type() -> glib_sys::GType;
}

mod handle_flags {
    // The following is entirely stolen from the auto-generated code
    // for GBindingFlags, from gtk-rs/glib/src/gobject/auto/flags.rs

    use super::*;

    // Keep these in sync with rsvg.h:RsvgHandleFlags
    #[cfg_attr(rustfmt, rustfmt_skip)]
    bitflags! {
        pub struct HandleFlags: u32 {
            const NONE            = 0;
            const UNLIMITED       = 1 << 0;
            const KEEP_IMAGE_DATA = 1 << 1;
        }
    }

    pub type RsvgHandleFlags = libc::c_uint;

    impl ToGlib for HandleFlags {
        type GlibType = RsvgHandleFlags;

        fn to_glib(&self) -> RsvgHandleFlags {
            self.bits()
        }
    }

    impl FromGlib<RsvgHandleFlags> for HandleFlags {
        fn from_glib(value: RsvgHandleFlags) -> HandleFlags {
            HandleFlags::from_bits_truncate(value)
        }
    }

    impl StaticType for HandleFlags {
        fn static_type() -> Type {
            unsafe { from_glib(rsvg_handle_flags_get_type()) }
        }
    }

    impl<'a> FromValueOptional<'a> for HandleFlags {
        unsafe fn from_value_optional(value: &Value) -> Option<Self> {
            Some(FromValue::from_value(value))
        }
    }

    impl<'a> FromValue<'a> for HandleFlags {
        unsafe fn from_value(value: &Value) -> Self {
            from_glib(gobject_sys::g_value_get_flags(value.to_glib_none().0))
        }
    }

    impl SetValue for HandleFlags {
        unsafe fn set_value(value: &mut Value, this: &Self) {
            gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, this.to_glib())
        }
    }
}

pub use self::handle_flags::*;

// Keep this in sync with rsvg.h:RsvgHandleClass
#[repr(C)]
pub struct RsvgHandleClass {
    parent: gobject_sys::GObjectClass,

    _abi_padding: [glib_sys::gpointer; 15],
}

// Keep this in sync with rsvg.h:RsvgHandle
#[repr(C)]
pub struct RsvgHandle {
    parent: gobject_sys::GObject,

    _abi_padding: [glib_sys::gpointer; 16],
}

unsafe impl ClassStruct for RsvgHandleClass {
    type Type = Handle;
}

unsafe impl InstanceStruct for RsvgHandle {
    type Type = Handle;
}

impl ops::Deref for RsvgHandleClass {
    type Target = ObjectClass;

    fn deref(&self) -> &Self::Target {
        unsafe { &*(self as *const _ as *const Self::Target) }
    }
}

impl ops::DerefMut for RsvgHandleClass {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *(self as *mut _ as *mut Self::Target) }
    }
}

static PROPERTIES: [subclass::Property; 11] = [
    subclass::Property("flags", |name| {
        ParamSpec::flags(
            name,
            "Flags",
            "Loading flags",
            HandleFlags::static_type(),
            0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT_ONLY,
        )
    }),
    subclass::Property("dpi-x", |name| {
        ParamSpec::double(
            name,
            "Horizontal DPI",
            "Horizontal resolution in dots per inch",
            0.0,
            f64::MAX,
            0.0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("dpi-y", |name| {
        ParamSpec::double(
            name,
            "Vertical DPI",
            "Vertical resolution in dots per inch",
            0.0,
            f64::MAX,
            0.0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("base-uri", |name| {
        ParamSpec::string(
            name,
            "Base URI",
            "Base URI for resolving relative references",
            None,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("width", |name| {
        ParamSpec::int(
            name,
            "Image width",
            "Image width",
            0,
            i32::MAX,
            0,
            ParamFlags::READABLE,
        )
    }),
    subclass::Property("height", |name| {
        ParamSpec::int(
            name,
            "Image height",
            "Image height",
            0,
            i32::MAX,
            0,
            ParamFlags::READABLE,
        )
    }),
    subclass::Property("em", |name| {
        ParamSpec::double(name, "em", "em", 0.0, f64::MAX, 0.0, ParamFlags::READABLE)
    }),
    subclass::Property("ex", |name| {
        ParamSpec::double(name, "ex", "ex", 0.0, f64::MAX, 0.0, ParamFlags::READABLE)
    }),
    subclass::Property("title", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
    subclass::Property("desc", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
    subclass::Property("metadata", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
];

impl ObjectSubclass for Handle {
    const NAME: &'static str = "RsvgHandle";

    type ParentType = glib::Object;

    // We don't use subclass:simple::InstanceStruct and ClassStruct
    // because we need to maintain the respective _abi_padding of each
    // of RsvgHandleClass and RsvgHandle.

    type Instance = RsvgHandle;
    type Class = RsvgHandleClass;

    glib_object_subclass!();

    fn class_init(klass: &mut RsvgHandleClass) {
        klass.install_properties(&PROPERTIES);
    }

    fn new() -> Self {
        Handle::new()
    }
}

impl ObjectImpl for Handle {
    glib_object_impl!();

    fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
        let prop = &PROPERTIES[id];

        match *prop {
            subclass::Property("flags", ..) => {
                let v: HandleFlags = value.get().expect("flags value has incorrect type");

                self.set_load_flags(v);
            }

            subclass::Property("dpi-x", ..) => {
                self.set_dpi_x(value.get().expect("dpi-x value has incorrect type"));
            }

            subclass::Property("dpi-y", ..) => {
                self.set_dpi_y(value.get().expect("dpi-y value has incorrect type"));
            }

            subclass::Property("base-uri", ..) => {
                let v: Option<String> = value.get();

                // rsvg_handle_set_base_uri() expects non-NULL URI strings,
                // but the "base-uri" property can be set to NULL due to a missing
                // construct-time property.

                if let Some(s) = v {
                    self.set_base_url(&s);
                }
            }

            _ => unreachable!("invalid property id {}", id),
        }
    }

    fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id];

        match *prop {
            subclass::Property("flags", ..) => Ok(self.load_flags.get().to_flags().to_value()),
            subclass::Property("dpi-x", ..) => Ok(self.dpi.get().x().to_value()),
            subclass::Property("dpi-y", ..) => Ok(self.dpi.get().y().to_value()),

            subclass::Property("base-uri", ..) => Ok(self
                .base_url
                .borrow()
                .as_ref()
                .map(|url| url.as_str())
                .to_value()),

            subclass::Property("width", ..) => Ok(self.get_dimensions_no_error().width.to_value()),
            subclass::Property("height", ..) => {
                Ok(self.get_dimensions_no_error().height.to_value())
            }

            subclass::Property("em", ..) => Ok(self.get_dimensions_no_error().em.to_value()),
            subclass::Property("ex", ..) => Ok(self.get_dimensions_no_error().ex.to_value()),

            // the following three are deprecated
            subclass::Property("title", ..) => Ok((None as Option<String>).to_value()),
            subclass::Property("desc", ..) => Ok((None as Option<String>).to_value()),
            subclass::Property("metadata", ..) => Ok((None as Option<String>).to_value()),

            _ => unreachable!("invalid property id={} for RsvgHandle", id),
        }
    }
}

pub fn get_rust_handle<'a>(handle: *const RsvgHandle) -> &'a Handle {
    let handle = unsafe { &*handle };
    handle.get_impl()
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_handle_rust_get_type() -> glib_sys::GType {
    Handle::get_type().to_glib()
}
<|endoftext|>


<commit_before>//! Modules for events in the *m.key.verification* namespace.
//!
//! This module also contains types shared by events in its child namespaces.

use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};

pub mod accept;
pub mod cancel;
pub mod key;
pub mod mac;
pub mod request;
pub mod start;

/// A hash algorithm.
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum HashAlgorithm {
    /// The SHA256 hash algorithm.
    Sha256,
}

/// A key agreement protocol.
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
pub enum KeyAgreementProtocol {
    /// The [Curve25519](https://cr.yp.to/ecdh.html) key agreement protocol.
    Curve25519,
    /// The Curve25519 key agreement protocol with check for public keys.
    Curve25519HkdfSha256,
}

/// A message authentication code algorithm.
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
pub enum MessageAuthenticationCode {
    /// The HKDF-HMAC-SHA256 MAC.
    HkdfHmacSha256,
}

/// A Short Authentication String method.
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum ShortAuthenticationString {
    /// The decimal method.
    Decimal,

    /// The emoji method.
    Emoji,
}

/// A Short Authentication String (SAS) verification method.
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Deserialize, Serialize)]
#[non_exhaustive]
pub enum VerificationMethod {
    /// The *m.sas.v1* verification method.
    #[serde(rename = "m.sas.v1")]
    #[strum(serialize = "m.sas.v1")]
    MSasV1,
}

#[cfg(test)]
mod test {
    use super::KeyAgreementProtocol;

    #[test]
    fn serialize_key_agreement() {
        let serialized =
            serde_json::to_string(&KeyAgreementProtocol::Curve25519HkdfSha256).unwrap();
        assert_eq!(serialized, "\"curve25519-hkdf-sha256\"");

        let deserialized: KeyAgreementProtocol = serde_json::from_str(&serialized).unwrap();
        assert_eq!(deserialized, KeyAgreementProtocol::Curve25519HkdfSha256);
    }
}
<commit_msg>ruma-events: Add the hmac-sha256 MAC method.<commit_after>//! Modules for events in the *m.key.verification* namespace.
//!
//! This module also contains types shared by events in its child namespaces.

use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};

pub mod accept;
pub mod cancel;
pub mod key;
pub mod mac;
pub mod request;
pub mod start;

/// A hash algorithm.
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum HashAlgorithm {
    /// The SHA256 hash algorithm.
    Sha256,
}

/// A key agreement protocol.
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
pub enum KeyAgreementProtocol {
    /// The [Curve25519](https://cr.yp.to/ecdh.html) key agreement protocol.
    Curve25519,
    /// The Curve25519 key agreement protocol with check for public keys.
    Curve25519HkdfSha256,
}

/// A message authentication code algorithm.
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
pub enum MessageAuthenticationCode {
    /// The HKDF-HMAC-SHA256 MAC.
    HkdfHmacSha256,
    /// The HMAC-SHA256 MAC.
    HmacSha256,
}

/// A Short Authentication String method.
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum ShortAuthenticationString {
    /// The decimal method.
    Decimal,

    /// The emoji method.
    Emoji,
}

/// A Short Authentication String (SAS) verification method.
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Deserialize, Serialize)]
#[non_exhaustive]
pub enum VerificationMethod {
    /// The *m.sas.v1* verification method.
    #[serde(rename = "m.sas.v1")]
    #[strum(serialize = "m.sas.v1")]
    MSasV1,
}

#[cfg(test)]
mod test {
    use super::{KeyAgreementProtocol, MessageAuthenticationCode};

    use serde_json::{from_value as from_json_value, json};

    #[test]
    fn serialize_key_agreement() {
        let serialized =
            serde_json::to_string(&KeyAgreementProtocol::Curve25519HkdfSha256).unwrap();
        assert_eq!(serialized, "\"curve25519-hkdf-sha256\"");

        let deserialized: KeyAgreementProtocol = serde_json::from_str(&serialized).unwrap();
        assert_eq!(deserialized, KeyAgreementProtocol::Curve25519HkdfSha256);
    }

    #[test]
    fn deserialize_mac_method() {
        let json = json!(["hkdf-hmac-sha256", "hmac-sha256"]);

        let deserialized: Vec<MessageAuthenticationCode> = from_json_value(json).unwrap();
        assert!(deserialized.contains(&MessageAuthenticationCode::HkdfHmacSha256));
    }

    #[test]
    fn serialize_mac_method() {
        let serialized = serde_json::to_string(&MessageAuthenticationCode::HkdfHmacSha256).unwrap();
        let deserialized: MessageAuthenticationCode = serde_json::from_str(&serialized).unwrap();
        assert_eq!(serialized, "\"hkdf-hmac-sha256\"");
        assert_eq!(deserialized, MessageAuthenticationCode::HkdfHmacSha256);

        let serialized = serde_json::to_string(&MessageAuthenticationCode::HmacSha256).unwrap();
        let deserialized: MessageAuthenticationCode = serde_json::from_str(&serialized).unwrap();
        assert_eq!(serialized, "\"hmac-sha256\"");
        assert_eq!(deserialized, MessageAuthenticationCode::HmacSha256);
    }
}
<|endoftext|>


<commit_before>//! Provides a panic hook with a user-friendly message.
//!
//! When Rust panics, the default message is pretty terse:
//!
//! ```text
//! thread '<unnamed>' panicked at 'Can't obtain a global logger', rust/libnewsboat/src/logger.rs:283:5
//! note: Run with `RUST_BACKTRACE=1` for a backtrace.
//! ```
//!
//! An end user probably won't know what to do with this, and even if they *did* re-run with
//! a backtrace enabled, the crash might not occur again. To fix that, this module provides a hook
//! that will print a more user-friendly message:
//!
//! ```text
//! Newsboat crashed; sorry about that. Please submit a report (below)
//! so we can investigate:
//!
//! - online: https://github.com/newsboat/newsboat/issues/new
//!
//!   You will need a GitHub account.
//!
//! - via email: newsboat@googlegroups.com
//!
//! We might have some follow-up questions, so please check your email
//! periodically. Thank you!
//!
//! The crash report:
//!
//! --->8----->8----->8----->8----->8----->8----->8----->8----->8----->8----->8---
//!
//! Newsboat version: 2.14.0
//! Couldn't determine the crash cause.
//! Message: Can't obtain the global logger
//! Crash location: rust/libnewsboat/src/logger.rs:283
//! stack backtrace:
//!    0:     0x559d490f8245 - backtrace::backtrace::libunwind::trace::ha74bb38523d900bf
//!                         at /home/minoru/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/backtrace/libunwind.rs:53
//!                          - backtrace::backtrace::trace::h22649ed4442cef5c
//!                         at /home/minoru/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/backtrace/mod.rs:42
//!    1:     0x559d490f2e3e - backtrace::capture::Backtrace::new_unresolved::h4fedf8cbb0cc5848
//!                         at /home/minoru/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/capture.rs:88
//!    2:     0x559d490f2d9c - backtrace::capture::Backtrace::new::hd207511a8a11ca29
//!                         at /home/minoru/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/capture.rs:63
//!    3:     0x559d48dcb00a - libnewsboat::human_panic::print_panic_msg::h212b04a7a3a5da8a
//!                         at rust/libnewsboat/src/human_panic.rs:59
//!    4:     0x559d48dca56c - libnewsboat::human_panic::setup::{{closure}}::hf29969d76d6a13df
//!                         at rust/libnewsboat/src/human_panic.rs:23
//!    5:     0x559d4911c593 - std::panicking::rust_panic_with_hook::hafa9461392bef12a
//!    6:     0x559d490c72bf - std::panicking::begin_panic::h76310ac575368f0c
//!                         at libstd/panicking.rs:411
//!    7:     0x559d48dcde7a - libnewsboat::logger::get_instance::h602edda973838b01
//!                         at rust/libnewsboat/src/logger.rs:283
//!    8:     0x559d48dc24f8 - rs_get_loglevel
//!                         at rust/libnewsboat-ffi/src/lib.rs:240
//!    9:     0x559d48a900a1 - _ZN8newsboat6Logger3logIJPcEEEvNS_5LevelERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEDpT_
//!                         at include/logger.h:29
//!   10:     0x559d48b0d2e4 - _ZN8newsboat10Controller3runERKNS_13CliArgsParserE
//!                         at src/controller.cpp:143
//!   11:     0x559d48a71b06 - main
//!                         at /home/minoru/src/newsboat/newsboat.cpp:188
//!   12:     0x7f251efc2b16 - __libc_start_main
//!   13:     0x559d48a6d399 - _start
//!   14:                0x0 - <unknown>
//!
//! --->8----->8----->8----->8----->8----->8----->8----->8----->8----->8----->8---
//! ```
//!
//! All you (the programmer) need to do is run this module's `setup()` somewhere towards the
//! beginning of the program.
use backtrace::Backtrace;
use std::io::{self, stderr, BufWriter, Write};
use std::panic::{self, PanicInfo};

/// Sets up a panic hook with a user-friendly message.
///
/// See module description for details.
pub fn setup() {
    match ::std::env::var("RUST_BACKTRACE") {
        Err(_) => {
            panic::set_hook(Box::new(move |panic_info: &PanicInfo| {
                print_panic_msg(panic_info)
                    .expect("An error occurred while preparing a crash report");
            }));
        }
        Ok(_) => {}
    }
}

fn print_panic_msg(panic_info: &PanicInfo) -> io::Result<()> {
    // Locking the handle to make sure all the messages are printed out in one chunk.
    let stderr = stderr();
    let handle = stderr.lock();
    let mut stderr = BufWriter::new(handle);

    writeln!(
        &mut stderr,
        "Newsboat crashed; sorry about that. Please submit a report (below)\n\
         so we can investigate:\n\
         \n\
         - online: https://github.com/newsboat/newsboat/issues/new\n\
         \n  \
         You will need a GitHub account.\n\
         \n\
         - via email: newsboat@googlegroups.com\n\
         \n\
         We might have some follow-up questions, so please check your email\n\
         periodically. Thank you!\n\
         \n\
         The crash report:\n\
         \n\
         --->8----->8----->8----->8----->8----->8----->8----->8----->8----->8----->8---\n"
    )?;

    writeln!(
        &mut stderr,
        "Newsboat version: {}",
        env!("CARGO_PKG_VERSION")
    )?;
    writeln!(&mut stderr, "{}", get_crash_cause(&panic_info))?;
    writeln!(&mut stderr, "{}", get_error_message(&panic_info))?;
    writeln!(&mut stderr, "{}", get_location(&panic_info))?;

    writeln!(&mut stderr, "{:#?}", Backtrace::new())?;

    writeln!(
        &mut stderr,
        "\n--->8----->8----->8----->8----->8----->8----->8----->8----->8----->8----->8---"
    )?;

    Ok(())
}

#[cfg(feature = "nightly")]
fn get_crash_cause(panic_info: &PanicInfo) -> String {
    match panic_info.message() {
        Some(m) => format!("Crash cause: {}", m),
        None => "Crash cause unknown".into(),
    };
}

#[cfg(not(feature = "nightly"))]
fn get_crash_cause(_panic_info: &PanicInfo) -> String {
    String::from("Couldn't determine the crash cause.")
}

fn get_error_message(panic_info: &PanicInfo) -> String {
    let payload = panic_info.payload().downcast_ref::<&str>();
    if let Some(payload) = payload {
        format!("Message: {}", &payload)
    } else {
        String::from("No error message")
    }
}

fn get_location(panic_info: &PanicInfo) -> String {
    match panic_info.location() {
        Some(location) => format!("Crash location: {}:{}", location.file(), location.line()),
        None => String::from("Crash location unknown"),
    }
}
<commit_msg>Fix Clippy warning: use `if let` instead of `match`<commit_after>//! Provides a panic hook with a user-friendly message.
//!
//! When Rust panics, the default message is pretty terse:
//!
//! ```text
//! thread '<unnamed>' panicked at 'Can't obtain a global logger', rust/libnewsboat/src/logger.rs:283:5
//! note: Run with `RUST_BACKTRACE=1` for a backtrace.
//! ```
//!
//! An end user probably won't know what to do with this, and even if they *did* re-run with
//! a backtrace enabled, the crash might not occur again. To fix that, this module provides a hook
//! that will print a more user-friendly message:
//!
//! ```text
//! Newsboat crashed; sorry about that. Please submit a report (below)
//! so we can investigate:
//!
//! - online: https://github.com/newsboat/newsboat/issues/new
//!
//!   You will need a GitHub account.
//!
//! - via email: newsboat@googlegroups.com
//!
//! We might have some follow-up questions, so please check your email
//! periodically. Thank you!
//!
//! The crash report:
//!
//! --->8----->8----->8----->8----->8----->8----->8----->8----->8----->8----->8---
//!
//! Newsboat version: 2.14.0
//! Couldn't determine the crash cause.
//! Message: Can't obtain the global logger
//! Crash location: rust/libnewsboat/src/logger.rs:283
//! stack backtrace:
//!    0:     0x559d490f8245 - backtrace::backtrace::libunwind::trace::ha74bb38523d900bf
//!                         at /home/minoru/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/backtrace/libunwind.rs:53
//!                          - backtrace::backtrace::trace::h22649ed4442cef5c
//!                         at /home/minoru/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/backtrace/mod.rs:42
//!    1:     0x559d490f2e3e - backtrace::capture::Backtrace::new_unresolved::h4fedf8cbb0cc5848
//!                         at /home/minoru/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/capture.rs:88
//!    2:     0x559d490f2d9c - backtrace::capture::Backtrace::new::hd207511a8a11ca29
//!                         at /home/minoru/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/capture.rs:63
//!    3:     0x559d48dcb00a - libnewsboat::human_panic::print_panic_msg::h212b04a7a3a5da8a
//!                         at rust/libnewsboat/src/human_panic.rs:59
//!    4:     0x559d48dca56c - libnewsboat::human_panic::setup::{{closure}}::hf29969d76d6a13df
//!                         at rust/libnewsboat/src/human_panic.rs:23
//!    5:     0x559d4911c593 - std::panicking::rust_panic_with_hook::hafa9461392bef12a
//!    6:     0x559d490c72bf - std::panicking::begin_panic::h76310ac575368f0c
//!                         at libstd/panicking.rs:411
//!    7:     0x559d48dcde7a - libnewsboat::logger::get_instance::h602edda973838b01
//!                         at rust/libnewsboat/src/logger.rs:283
//!    8:     0x559d48dc24f8 - rs_get_loglevel
//!                         at rust/libnewsboat-ffi/src/lib.rs:240
//!    9:     0x559d48a900a1 - _ZN8newsboat6Logger3logIJPcEEEvNS_5LevelERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEDpT_
//!                         at include/logger.h:29
//!   10:     0x559d48b0d2e4 - _ZN8newsboat10Controller3runERKNS_13CliArgsParserE
//!                         at src/controller.cpp:143
//!   11:     0x559d48a71b06 - main
//!                         at /home/minoru/src/newsboat/newsboat.cpp:188
//!   12:     0x7f251efc2b16 - __libc_start_main
//!   13:     0x559d48a6d399 - _start
//!   14:                0x0 - <unknown>
//!
//! --->8----->8----->8----->8----->8----->8----->8----->8----->8----->8----->8---
//! ```
//!
//! All you (the programmer) need to do is run this module's `setup()` somewhere towards the
//! beginning of the program.
use backtrace::Backtrace;
use std::io::{self, stderr, BufWriter, Write};
use std::panic::{self, PanicInfo};

/// Sets up a panic hook with a user-friendly message.
///
/// See module description for details.
pub fn setup() {
    if ::std::env::var("RUST_BACKTRACE").is_err() {
        panic::set_hook(Box::new(move |panic_info: &PanicInfo| {
            print_panic_msg(panic_info).expect("An error occurred while preparing a crash report");
        }));
    }
}

fn print_panic_msg(panic_info: &PanicInfo) -> io::Result<()> {
    // Locking the handle to make sure all the messages are printed out in one chunk.
    let stderr = stderr();
    let handle = stderr.lock();
    let mut stderr = BufWriter::new(handle);

    writeln!(
        &mut stderr,
        "Newsboat crashed; sorry about that. Please submit a report (below)\n\
         so we can investigate:\n\
         \n\
         - online: https://github.com/newsboat/newsboat/issues/new\n\
         \n  \
         You will need a GitHub account.\n\
         \n\
         - via email: newsboat@googlegroups.com\n\
         \n\
         We might have some follow-up questions, so please check your email\n\
         periodically. Thank you!\n\
         \n\
         The crash report:\n\
         \n\
         --->8----->8----->8----->8----->8----->8----->8----->8----->8----->8----->8---\n"
    )?;

    writeln!(
        &mut stderr,
        "Newsboat version: {}",
        env!("CARGO_PKG_VERSION")
    )?;
    writeln!(&mut stderr, "{}", get_crash_cause(&panic_info))?;
    writeln!(&mut stderr, "{}", get_error_message(&panic_info))?;
    writeln!(&mut stderr, "{}", get_location(&panic_info))?;

    writeln!(&mut stderr, "{:#?}", Backtrace::new())?;

    writeln!(
        &mut stderr,
        "\n--->8----->8----->8----->8----->8----->8----->8----->8----->8----->8----->8---"
    )?;

    Ok(())
}

#[cfg(feature = "nightly")]
fn get_crash_cause(panic_info: &PanicInfo) -> String {
    match panic_info.message() {
        Some(m) => format!("Crash cause: {}", m),
        None => "Crash cause unknown".into(),
    };
}

#[cfg(not(feature = "nightly"))]
fn get_crash_cause(_panic_info: &PanicInfo) -> String {
    String::from("Couldn't determine the crash cause.")
}

fn get_error_message(panic_info: &PanicInfo) -> String {
    let payload = panic_info.payload().downcast_ref::<&str>();
    if let Some(payload) = payload {
        format!("Message: {}", &payload)
    } else {
        String::from("No error message")
    }
}

fn get_location(panic_info: &PanicInfo) -> String {
    match panic_info.location() {
        Some(location) => format!("Crash location: {}:{}", location.file(), location.line()),
        None => String::from("Crash location unknown"),
    }
}
<|endoftext|>


<commit_before><commit_msg>Don't create two DB pools in todo example.<commit_after><|endoftext|>


<commit_before>extern crate gcc;

use std::io::prelude::*;
use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

macro_rules! errln {
    ($($args:tt)*) => {
        let _ = writeln!(&mut ::std::io::stderr(), $($args)* );
    }
}

fn main() {
    let target = env::var("TARGET").expect("cannot get TARGET");
    let host = env::var("HOST").expect("cannot get HOST");
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("cannot get OUT_DIR"));
    let msvc = target.contains("msvc");

    // Check if capstone is already cloned
    if !Path::new("capstone/.git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"]).status();
    }

    if !target.starts_with("x86_64-") && !target.starts_with("i686") {
        compute_place_holders(&out_dir, "capstone/include", msvc);
    }

    let libcapstone = out_dir.join("libcapstone.a");
    if !libcapstone.exists() {
        build_capstone(&out_dir, &target, &host, msvc);
    }
    if !libcapstone.exists() {
        panic!("cannot find libcapstone")
    }

    println!("cargo:rustc-link-search=native={}", out_dir.display());
    println!("cargo:rustc-link-lib=static=capstone")
}

fn compute_place_holders(out_dir: &Path, inc_dir: &str, msvc: bool) {
    let out_rs = out_dir.join("placeholders.rs");
    let out_exe = out_dir.join("compute_placeholders.exe");

    let mut config = gcc::Config::new();
    config.include(inc_dir);

    let mut command = config.get_compiler().to_command();
    command.arg("compute_placeholders.c");
    if msvc {
        command.arg("/OUT");
    } else {
        command.arg("-o");
    }
    command.arg(&out_exe)
        .stdout(Stdio::null())
        .stderr(Stdio::null());

    errln!("{:?}", command);
    if command.status().is_ok() {
        let mut run_cmd = Command::new(&out_exe);
        errln!("{:?}", run_cmd);
        let output = run_cmd.output().expect("cannot run compute_placeholders.exe");
        let mut f = File::create(&out_rs).unwrap();
        f.write_all(output.stdout.as_slice()).unwrap();
    } else {
        panic!("cannot build compute_placeholders.exe");
    }
}

fn build_capstone(out_dir: &Path, target: &str, host: &str, msvc: bool) {

    let host_windows = host.contains("windows");

    if msvc && !host_windows {
        panic!("cannot cross compile to msvc");
    }

    if msvc {
        panic!("msvc build not supported yet");
    }

    let mut cmd = Command::new("bash");
    cmd.current_dir("capstone")
        .arg("make.sh")
        // .env("CFLAGS", "-flto")
        .env("BUILDDIR", out_dir)
        .env("CAPSTONE_BUILD_CORE_ONLY", "yes")
        .env("CAPSTONE_SHARED", "no")
        .env("CAPSTONE_STATIC", "yes");

    if host == target {
        // do nothing
    } else if target == "i686-pc-windows-gnu" {
        cmd.arg("cross-win32");
    } else if target == "x86_64-pc-windows-gnu" {
        cmd.arg("cross-win64");
    } else if host.starts_with("x86_64-") && target.starts_with("i686-") && host[7..] == target[5..] {
        // not perfect but hey
        cmd.arg("nix32");
    } else {
        cmd.env("CROSS", target.to_string() + "-");
    }

    errln!("build capstone: {:?}", cmd);

    let res = cmd.status();
    if let Ok(res) = res {
        if !res.success() {
            panic!("cannot compile capstone");
        }
    } else {
        panic!("cannot start capstone build");
    }

}
<commit_msg>Fix osx build<commit_after>extern crate gcc;

use std::io::prelude::*;
use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

macro_rules! errln {
    ($($args:tt)*) => {
        let _ = writeln!(&mut ::std::io::stderr(), $($args)* );
    }
}

fn main() {
    let target = env::var("TARGET").expect("cannot get TARGET");
    let host = env::var("HOST").expect("cannot get HOST");
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("cannot get OUT_DIR"));
    let msvc = target.contains("msvc");

    // Check if capstone is already cloned
    if !Path::new("capstone/.git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"]).status();
    }

    if !target.starts_with("x86_64-") && !target.starts_with("i686") {
        compute_place_holders(&out_dir, "capstone/include", msvc);
    }

    let libcapstone = out_dir.join("libcapstone.a");
    if !libcapstone.exists() {
        build_capstone(&out_dir, &target, &host, msvc);
    }
    if !libcapstone.exists() {
        panic!("cannot find libcapstone")
    }

    println!("cargo:rustc-link-search=native={}", out_dir.display());
    println!("cargo:rustc-link-lib=static=capstone")
}

fn compute_place_holders(out_dir: &Path, inc_dir: &str, msvc: bool) {
    let out_rs = out_dir.join("placeholders.rs");
    let out_exe = out_dir.join("compute_placeholders.exe");

    let mut config = gcc::Config::new();
    config.include(inc_dir);

    let mut command = config.get_compiler().to_command();
    command.arg("compute_placeholders.c");
    if msvc {
        command.arg("/OUT");
    } else {
        command.arg("-o");
    }
    command.arg(&out_exe)
        .stdout(Stdio::null())
        .stderr(Stdio::null());

    errln!("{:?}", command);
    if command.status().is_ok() {
        let mut run_cmd = Command::new(&out_exe);
        errln!("{:?}", run_cmd);
        let output = run_cmd.output().expect("cannot run compute_placeholders.exe");
        let mut f = File::create(&out_rs).unwrap();
        f.write_all(output.stdout.as_slice()).unwrap();
    } else {
        panic!("cannot build compute_placeholders.exe");
    }
}

fn build_capstone(out_dir: &Path, target: &str, host: &str, msvc: bool) {

    let host_windows = host.contains("windows");

    if msvc && !host_windows {
        panic!("cannot cross compile to msvc");
    }

    if msvc {
        panic!("msvc build not supported yet");
    }

    let mut cmd = Command::new("make");
    cmd.current_dir("capstone")
        // .env("CFLAGS", "-flto")
        .env("BUILDDIR", out_dir)
        .env("CAPSTONE_BUILD_CORE_ONLY", "yes")
        .env("CAPSTONE_SHARED", "no")
        .env("CAPSTONE_STATIC", "yes");

    if host == target {
        // do nothing
    } else if target == "i686-pc-windows-gnu" {
        cmd.arg("cross-win32");
    } else if target == "x86_64-pc-windows-gnu" {
        cmd.arg("cross-win64");
    } else if host.starts_with("x86_64-") && target.starts_with("i686-") && host[7..] == target[5..] {
        // not perfect but hey
        cmd.arg("nix32");
    } else {
        cmd.env("CROSS", target.to_string() + "-");
    }

    errln!("build capstone: {:?}", cmd);

    let res = cmd.status();
    if let Ok(res) = res {
        if !res.success() {
            panic!("cannot compile capstone");
        }
    } else {
        panic!("cannot start capstone build");
    }

}
<|endoftext|>


<commit_before>fn main() {
    use std::path::Path;
    use std::process::Command;
    use std::str::from_utf8;
    use std::io::Write;
    use std::fs::File;
    let mut out = File::create("build.log").unwrap();
    let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("bobyqa-cpp");
    writeln!(&mut out, "cmake").unwrap();
    let cmake = Command::new("cmake").args(&["."]).current_dir(&dir).output().unwrap();
    write!(&mut out, "{}", from_utf8(&cmake.stdout[..]).unwrap()).unwrap();
    write!(&mut out, "{}", from_utf8(&cmake.stderr[..]).unwrap()).unwrap();
    writeln!(&mut out, "{}", cmake.status).unwrap();
    writeln!(&mut out, "make").unwrap();
    let make = Command::new("make").current_dir(&dir).output().unwrap();
    write!(&mut out, "{}", from_utf8(&make.stdout[..]).unwrap()).unwrap();
    write!(&mut out, "{}", from_utf8(&make.stderr[..]).unwrap()).unwrap();
    writeln!(&mut out, "{}", make.status).unwrap();
    println!("cargo:rustc-link-search=native={}", dir.join("lib").display());
    println!("cargo:rustc-link-lib=static=bobyqa");
}
<commit_msg>Use out of source build for bobyqa-cpp, more verbose logging, check build status<commit_after>fn main() {
    use std::path::Path;
    use std::process::Command;
    use std::str::from_utf8;
    use std::io::Write;
    use std::fs::{File, create_dir_all};
    let mut out = File::create("build.log").unwrap();
    let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("bobyqa-cpp").join("build");
    create_dir_all(&dir).unwrap();
    let date = Command::new("date").output().unwrap();
    write!(&mut out, "# {}", from_utf8(&date.stdout[..]).unwrap()).unwrap();
    writeln!(&mut out, "# cmake").unwrap();
    let cmake = Command::new("cmake")
        .arg("-DCMAKE_VERBOSE_MAKEFILE=1").arg("-DCMAKE_BUILD_TYPE=Release").arg("..")
        .current_dir(&dir).output().unwrap();
    write!(&mut out, "{}", from_utf8(&cmake.stdout[..]).unwrap()).unwrap();
    write!(&mut out, "{}", from_utf8(&cmake.stderr[..]).unwrap()).unwrap();
    writeln!(&mut out, "{}", cmake.status).unwrap();
    assert!(cmake.status.success());
    writeln!(&mut out, "# make").unwrap();
    let make = Command::new("make").current_dir(&dir).output().unwrap();
    write!(&mut out, "{}", from_utf8(&make.stdout[..]).unwrap()).unwrap();
    write!(&mut out, "{}", from_utf8(&make.stderr[..]).unwrap()).unwrap();
    writeln!(&mut out, "{}", make.status).unwrap();
    assert!(make.status.success());
    println!("cargo:rustc-link-search=native={}", dir.join("lib").display());
    println!("cargo:rustc-link-lib=static=bobyqa");
}
<|endoftext|>


<commit_before>extern crate capnpc;

use std::env;
use std::path::Path;

fn main() {
    ::capnpc::CompilerCommand::new()
        .src_prefix("schema")
        .file("schema/root.capnp")
        .run().expect("capnp schema compiler failed");
}
<commit_msg>Minor cleanup.<commit_after>extern crate capnpc;

fn main() {
    ::capnpc::CompilerCommand::new()
        .src_prefix("schema")
        .file("schema/root.capnp")
        .run().expect("capnp schema compiler failed");
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::fmt;
use super::Deque;

// copy semantices
//#[derive(Copy, Clone)]
struct Rawlink<T> {
    p: *mut T
}

impl<T> Rawlink<T> {
    fn none() -> Rawlink<T> {
        Rawlink { p: ptr::null_mut() }
    }

    fn some(n: &mut T) -> Rawlink<T> {
        Rawlink { p: n }
    }

    fn take(&mut self) -> Rawlink<T> {
        mem::replace(self, Rawlink::none())
    }
}

struct Node<T> {
    item: T,
    next: Option<Box<Node<T>>>,
    prev: Rawlink<Node<T>>

}

impl<T> Node<T> {
    /// work around for moved value
    fn into_item_and_pointers(self) -> (T, Option<Box<Node<T>>>, Rawlink<Node<T>>) {
        (self.item, self.next, self.prev)
    }

    fn size(&self) -> usize {
        let mut p = self.next.as_ref();
        let mut sz = 0;
        while p.is_some() {
            p = p.unwrap().next.as_ref();
            sz += 1;
        }
        sz
    }
}

/// linked double queue
pub struct LinkedDeque<T> {
    first: Option<Box<Node<T>>>,
    last: Rawlink<Node<T>>
}

impl<T> Deque<T> for LinkedDeque<T> {
    fn new() -> LinkedDeque<T> {
        LinkedDeque {
            first: None,
            last: Rawlink::none()
        }
    }
    fn is_empty(&self) -> bool {
        self.first.is_none()
    }
    fn size(&self) -> usize {
        match self.first {
            None    => 0,
            Some(ref l) => l.size()
        }
    }
    fn add_first(&mut self, item: T) {
        let mut old_first = self.first.take();
        let mut first = Box::new(Node {
            item: item,
            next: None,
            prev: Rawlink::none()
        });

        if old_first.is_some() {
            old_first.as_mut().unwrap().prev = Rawlink::some(&mut first);
        } else {
            self.last = Rawlink::some(&mut first);
        }
        // move in
        first.next = old_first;

        self.first = Some(first)
    }

    fn add_last(&mut self, item: T) {
        if self.first.is_some() {
            let old_last = self.last.take();
            let last = Box::new(Node {
                item: item,
                next: None,
                prev: Rawlink::none(),
            });
            unsafe {
                (*old_last.p).next = Some(last);
            }

        } else {
            self.add_first(item)
        }
    }

    fn remove_first(&mut self) -> Option<T> {
        let old_first = self.first.take();
        if old_first.is_some() {
            let (item, mut first, _) = old_first.unwrap().into_item_and_pointers();
            // update new first's prev field
            first.as_mut().map(|v| v.prev = Rawlink::none());
            self.first = first;
            Some(item)
        } else {
            None
        }
    }

    fn remove_last(&mut self) -> Option<T> {
        let old_last = self.last.take();
        if old_last.p.is_null() {
            return None;
        }
        let last_ref_mut = unsafe { mem::transmute::<_, &mut Node<T>>(old_last.p) };

        let last: Node<T> = mem::replace(last_ref_mut, unsafe { mem::zeroed() });

        if last.prev.p.is_null() {
            self.first = None;
        } else {
            unsafe {
                (*last.prev.p).next = None;
            }
        }
        self.last = last.prev;

        Some(last.item)
    }
    // fn iter(&self) -> Iterator<Item=&T> {
    //     unimplemented!()
    // }

}

impl<T: fmt::Display> fmt::Display for LinkedDeque<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.first {
            None    => {
                try!(write!(f, "<empty deque>"));
            },
            Some(ref l) => {
                try!(write!(f, "("));
                let mut p = Some(l);
                while p.is_some() {
                    try!(write!(f, "{},", p.unwrap().item));
                    p = p.unwrap().next.as_ref();
                }
                try!(write!(f, ")"));

            }
        }
        Ok(())
    }
}

#[test]
fn test_linked_deque() {
    let mut deque: LinkedDeque<i32> = Deque::new();

    assert!(deque.is_empty());
    assert_eq!(deque.remove_first(), None);
    assert_eq!(deque.remove_last(), None);

    let result = vec![4, 0, 3, 2];
    let mut rit = result.iter();
    // -1 remove last
    // -2 remove first
    // extra 2 more -1 -2 will result None
    for s in vec![4, 2, 3, 0, -1, -2, -2, -1, -1, -2] {
        if s == -2 {
            assert_eq!(deque.remove_first(), rit.next().map(|&v| v));
        } else if s == -1 {
            assert_eq!(deque.remove_last(), rit.next().map(|&v| v));
        } else {
            deque.add_first(s);
        }
    }

    assert!(deque.is_empty());
}
<commit_msg>stacks_and_queues/linked_deque: fix error in LinkedDeque::size()<commit_after>use std::mem;
use std::ptr;
use std::fmt;
use super::Deque;

struct Rawlink<T> {
    p: *mut T
}

impl<T> Rawlink<T> {
    fn none() -> Rawlink<T> {
        Rawlink { p: ptr::null_mut() }
    }

    fn some(n: &mut T) -> Rawlink<T> {
        Rawlink { p: n }
    }

    fn take(&mut self) -> Rawlink<T> {
        mem::replace(self, Rawlink::none())
    }
}

struct Node<T> {
    item: T,
    next: Option<Box<Node<T>>>,
    prev: Rawlink<Node<T>>

}

impl<T> Node<T> {
    /// work around for moved value
    fn into_item_and_pointers(self) -> (T, Option<Box<Node<T>>>, Rawlink<Node<T>>) {
        (self.item, self.next, self.prev)
    }

    fn size(&self) -> usize {
        let mut p = self.next.as_ref();
        let mut sz = 1;
        while p.is_some() {
            p = p.unwrap().next.as_ref();
            sz += 1;
        }
        sz
    }
}

/// linked double queue
pub struct LinkedDeque<T> {
    first: Option<Box<Node<T>>>,
    last: Rawlink<Node<T>>
}

impl<T> Deque<T> for LinkedDeque<T> {
    fn new() -> LinkedDeque<T> {
        LinkedDeque {
            first: None,
            last: Rawlink::none()
        }
    }
    fn is_empty(&self) -> bool {
        self.first.is_none()
    }
    fn size(&self) -> usize {
        match self.first {
            None    => 0,
            Some(ref l) => l.size()
        }
    }
    fn add_first(&mut self, item: T) {
        let mut old_first = self.first.take();
        let mut first = Box::new(Node {
            item: item,
            next: None,
            prev: Rawlink::none()
        });

        if old_first.is_some() {
            old_first.as_mut().unwrap().prev = Rawlink::some(&mut first);
        } else {
            self.last = Rawlink::some(&mut first);
        }
        // move in
        first.next = old_first;

        self.first = Some(first)
    }

    fn add_last(&mut self, item: T) {
        if self.first.is_some() {
            let old_last = self.last.take();
            let last = Box::new(Node {
                item: item,
                next: None,
                prev: Rawlink::none(),
            });
            unsafe {
                (*old_last.p).next = Some(last);
            }

        } else {
            self.add_first(item)
        }
    }

    fn remove_first(&mut self) -> Option<T> {
        let old_first = self.first.take();
        if old_first.is_some() {
            let (item, mut first, _) = old_first.unwrap().into_item_and_pointers();
            // update new first's prev field
            first.as_mut().map(|v| v.prev = Rawlink::none());
            self.first = first;
            Some(item)
        } else {
            None
        }
    }

    fn remove_last(&mut self) -> Option<T> {
        let old_last = self.last.take();
        if old_last.p.is_null() {
            return None;
        }
        let last_ref_mut = unsafe { mem::transmute::<_, &mut Node<T>>(old_last.p) };

        let last: Node<T> = mem::replace(last_ref_mut, unsafe { mem::zeroed() });

        if last.prev.p.is_null() {
            self.first = None;
        } else {
            unsafe {
                (*last.prev.p).next = None;
            }
        }
        self.last = last.prev;

        Some(last.item)
    }
    // fn iter(&self) -> Iterator<Item=&T> {
    //     unimplemented!()
    // }

}

impl<T: fmt::Display> fmt::Display for LinkedDeque<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.first {
            None    => {
                try!(write!(f, "<empty deque>"));
            },
            Some(ref l) => {
                try!(write!(f, "("));
                let mut p = Some(l);
                while p.is_some() {
                    try!(write!(f, "{},", p.unwrap().item));
                    p = p.unwrap().next.as_ref();
                }
                try!(write!(f, ")"));

            }
        }
        Ok(())
    }
}

#[test]
fn test_linked_deque_add_remove() {
    let mut deque: LinkedDeque<i32> = Deque::new();

    assert!(deque.is_empty());
    assert_eq!(deque.remove_first(), None);
    assert_eq!(deque.remove_last(), None);

    let result = vec![4, 0, 5, 2, 3];
    let mut rit = result.iter();
    // -1 remove last
    // -2 remove first
    // extra 2 more -1 -2 will result None
    for s in vec![4, 2, 3, 0, -1, -2, 5, -2, -1, -1, -2] {
        if s == -2 {
            assert_eq!(deque.remove_first(), rit.next().map(|&v| v));
        } else if s == -1 {
            assert_eq!(deque.remove_last(), rit.next().map(|&v| v));
        } else {
            deque.add_first(s);
        }
    }

    assert!(deque.is_empty());
}

#[test]
fn test_linked_deque_size() {
    let mut deque: LinkedDeque<i32> = Deque::new();

    assert!(deque.is_empty());

    let result = vec![0, 1, 2, 3, 4, 3, 2, 3, 2, 1, 0, 0];
    let mut rit = result.iter();
    // -1 remove last
    // -2 remove first
    for s in vec![4, 2, 3, 0, -1, -2, 5, -1, -1, -2] {
        if s == -2 {
            assert_eq!(deque.size(), *rit.next().unwrap());
            deque.remove_first();
        } else if s == -1 {
            assert_eq!(deque.size(), *rit.next().unwrap());
            deque.remove_last();
        } else {
            assert_eq!(deque.size(), *rit.next().unwrap());
            deque.add_first(s);
        }
    }

    assert!(deque.is_empty());
}
<|endoftext|>


<commit_before>use crate::error;
use crate::error::Result;
use crate::test_highlight::parse_highlight_test;
use lazy_static::lazy_static;
use regex::Regex;
use std::collections::hash_map::HashMap;
use std::fs;
use tree_sitter::{Language, Parser, Point};

// TODO: It would be cooler to do this with a comments query rather than with a regex
// directly.
lazy_static! {
    static ref METADATA_REGEX: Regex = Regex::new(r#"(\w+): ([^\s,]+), (\d+), (\d+)"#).unwrap();
}

#[derive(Debug, Eq, PartialEq)]
pub struct CaptureInfo {
    pub name: String,
    pub position: Point,
}

#[derive(Debug, Eq, PartialEq)]
struct Assertion {
    position: Point,
    capture_class: String,
    capture_type: String,
}

impl From<regex::Captures<'_>> for Assertion {
    fn from(re: regex::Captures) -> Assertion {
        Assertion {
            capture_class: re.get(1).unwrap().as_str().to_string(),
            capture_type: re.get(2).unwrap().as_str().to_string(),
            position: Point {
                row: re
                    .get(3)
                    .iter()
                    .flat_map(|m| m.as_str().parse::<usize>())
                    .next()
                    .unwrap(),
                column: re
                    .get(4)
                    .iter()
                    .flat_map(|m| m.as_str().parse::<usize>())
                    .next()
                    .unwrap(),
            },
        }
    }
}

pub fn assert_expected_captures(
    infos: Vec<CaptureInfo>,
    path: String,
    parser: &mut Parser,
    language: Language,
) -> Result<()> {
    let contents = fs::read_to_string(path)?;
    let _pairs = parse_highlight_test(parser, language, contents.as_bytes());

    let assertions: Vec<Assertion> = METADATA_REGEX
        .captures_iter(&contents)
        .map(|c| Assertion::from(c))
        .collect();

    let per_position_index: HashMap<Point, &Assertion> =
        assertions.iter().map(|a| (a.position, a)).collect();

    for info in &infos {
        if !per_position_index.contains_key(&info.position) {
            continue;
        }
        let found = per_position_index.get(&info.position).unwrap();
        let joined = format!("{}.{}", found.capture_class, found.capture_type);
        if joined != info.name && info.name != "name" {
            Err(error::Error::new(format!(
                "Assertion failed: at {}, found {}, expected {}",
                info.position, info.name, joined
            )))?
        }
    }
    Ok(())
}
<commit_msg>it works<commit_after>use crate::error;
use crate::error::Result;
use crate::test_highlight::parse_highlight_test;
use lazy_static::lazy_static;
use regex::Regex;
use std::collections::hash_map::HashMap;
use std::fs;
use tree_sitter::{Language, Parser, Point};

// TODO: It would be cooler to do this with a comments query rather than with a regex
// directly.
lazy_static! {
    static ref METADATA_REGEX: Regex = Regex::new(r#"(\w+): ([^\s,]+), (\d+), (\d+)"#).unwrap();
}

#[derive(Debug, Eq, PartialEq)]
pub struct CaptureInfo {
    pub name: String,
    pub position: Point,
}

#[derive(Debug, Eq, PartialEq)]
struct Assertion {
    position: Point,
    expected: String,
}

impl From<&(Point, String)> for Assertion {
    fn from(item: &(Point, String)) -> Assertion {
        let (pos, info) = item;
        Assertion {
            position: *pos,
            expected: info.to_string(),
        }
    }
}

pub fn assert_expected_captures(
    infos: Vec<CaptureInfo>,
    path: String,
    parser: &mut Parser,
    language: Language,
) -> Result<()> {
    let contents = fs::read_to_string(path)?;
    let pairs = parse_highlight_test(parser, language, contents.as_bytes())?;
    println!("{:?}", pairs);

    let assertions: Vec<Assertion> = pairs.iter().map(Assertion::from).collect();

    let per_position_index: HashMap<Point, &Assertion> =
        assertions.iter().map(|a| (a.position, a)).collect();

    for info in &infos {
        if !per_position_index.contains_key(&info.position) {
            continue;
        }
        let found = per_position_index.get(&info.position).unwrap();
        if found.expected != info.name && info.name != "name" {
            Err(error::Error::new(format!(
                "Assertion failed: at {}, found {}, expected {}",
                info.position, info.name, found.expected
            )))?
        }
    }
    Ok(())
}
<|endoftext|>