<commit_before>//! Trait definitions and type aliases.

use image::{
    Rgb,
    Rgba,
    Luma,
    Pixel,
    Primitive,
    ImageBuffer
};

use std::{
    u8,
    u16
};

/// An ImageBuffer containing Pixels of type P with storage
/// Vec<P::Subpixel>.
// TODO: This produces a compiler warning about trait bounds
// TODO: not being enforced in type definitions. In this case
// TODO: they are. Can we get rid of the warning?
pub type VecBuffer<P: Pixel> = ImageBuffer<P, Vec<P::Subpixel>>;

/// Used to name the type we get by replacing
/// the channel type of a given Pixel type.
pub trait WithChannel<C: Primitive>: Pixel {
    type Pixel: Pixel<Subpixel=C> + 'static;
}

pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;

impl<T, U> WithChannel<U> for Rgb<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgb<U>;
}

impl<T, U> WithChannel<U> for Rgba<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgba<U>;
}

impl<T, U> WithChannel<U> for Luma<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Luma<U>;
}

/// Pixels which have a named Black value.
pub trait HasBlack {
    fn black() -> Self;
}

/// Pixels which have a named White value.
pub trait HasWhite {
    fn white() -> Self;
}

impl HasBlack for Luma<u8> {
    fn black() -> Self {
        Luma([0u8])
    }
}

impl HasWhite for Luma<u8> {
    fn white() -> Self {
        Luma([u8::MAX])
    }
}

impl HasBlack for Luma<u16> {
    fn black() -> Self {
        Luma([0u16])
    }
}

impl HasWhite for Luma<u16> {
    fn white() -> Self {
        Luma([u16::MAX])
    }
}

impl HasBlack for Rgb<u8> {
    fn black() -> Self {
        Rgb([0u8; 3])
    }
}

impl HasWhite for Rgb<u8> {
    fn white() -> Self {
        Rgb([u8::MAX; 3])
    }
}

/// A type to which we can clamp a value of type T.
/// Implementations are not required to handle NaNs gracefully.
// TODO: Switch to using the conv crate when that lets
// TODO: you handle this ergonomically.
pub trait Clamp<T> {
    fn clamp(x: T) -> Self;
}

impl Clamp<f32> for u8 {
    fn clamp(x: f32) -> u8 {
        if x < 0f32 { return 0;}
        if x > 255f32 { return 255; }
        x as u8
    }
}

impl Clamp<f32> for u16 {
    fn clamp(x: f32) -> u16 {
        if x < 0f32 { return 0;}
        if x > 65535f32 { return 65535; }
        x as u16
    }
}

impl Clamp<f64> for u8 {
    fn clamp(x: f64) -> u8 {
        if x < 0f64 { return 0;}
        if x > 255f64 { return 255; }
        x as u8
    }
}

impl Clamp<f64> for u16 {
    fn clamp(x: f64) -> u16 {
        if x < 0f64 { return 0;}
        if x > 65535f64 { return 65535; }
        x as u16
    }
}

impl Clamp<i32> for u8 {
    fn clamp(x: i32) -> u8 {
        if x < 0i32 { return 0;}
        if x > 255i32 { return 255; }
        x as u8
    }
}

impl Clamp<i32> for u16 {
    fn clamp(x: i32) -> u16 {
        if x < 0i32 { return 0;}
        if x > 65535i32 { return 65535; }
        x as u16
    }
}

impl Clamp<i32> for i16 {
    fn clamp(x: i32) -> i16 {
        if x < -32768i32 { return -32768i16;}
        if x > 32767i32 { return 32767i16; }
        x as i16
    }
}

#[cfg(test)]
mod test {

    use super::Clamp;

    #[test]
    fn test_clamp_u8() {
        let t: u8 = Clamp::clamp(255f32);
        assert_eq!(t, 255u8);
        let u: u8 = Clamp::clamp(300f32);
        assert_eq!(u, 255u8);
        let v: u8 = Clamp::clamp(0f32);
        assert_eq!(v, 0u8);
        let w: u8 = Clamp::clamp(-5f32);
        assert_eq!(w, 0u8);
    }

    #[test]
    fn test_clamp_u16() {
        let t: u16 = Clamp::clamp(65535f32);
        assert_eq!(t, 65535u16);
        let u: u16 = Clamp::clamp(300000f32);
        assert_eq!(u, 65535u16);
        let v: u16 = Clamp::clamp(0f32);
        assert_eq!(v, 0u16);
        let w: u16 = Clamp::clamp(-5f32);
        assert_eq!(w, 0u16);
    }
}
<commit_msg>Tidy Clamp implementations<commit_after>//! Trait definitions and type aliases.

use image::{
    Rgb,
    Rgba,
    Luma,
    Pixel,
    Primitive,
    ImageBuffer
};
use num::{
    Bounded,
    NumCast
};
use std::{
    u8,
    u16
};

use std::cmp::Ordering::{
    Equal, Greater, Less
};

/// An ImageBuffer containing Pixels of type P with storage
/// Vec<P::Subpixel>.
// TODO: This produces a compiler warning about trait bounds
// TODO: not being enforced in type definitions. In this case
// TODO: they are. Can we get rid of the warning?
pub type VecBuffer<P: Pixel> = ImageBuffer<P, Vec<P::Subpixel>>;

/// Used to name the type we get by replacing
/// the channel type of a given Pixel type.
pub trait WithChannel<C: Primitive>: Pixel {
    type Pixel: Pixel<Subpixel=C> + 'static;
}

pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;

impl<T, U> WithChannel<U> for Rgb<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgb<U>;
}

impl<T, U> WithChannel<U> for Rgba<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgba<U>;
}

impl<T, U> WithChannel<U> for Luma<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Luma<U>;
}

/// Pixels which have a named Black value.
pub trait HasBlack {
    fn black() -> Self;
}

/// Pixels which have a named White value.
pub trait HasWhite {
    fn white() -> Self;
}

impl HasBlack for Luma<u8> {
    fn black() -> Self {
        Luma([0u8])
    }
}

impl HasWhite for Luma<u8> {
    fn white() -> Self {
        Luma([u8::MAX])
    }
}

impl HasBlack for Luma<u16> {
    fn black() -> Self {
        Luma([0u16])
    }
}

impl HasWhite for Luma<u16> {
    fn white() -> Self {
        Luma([u16::MAX])
    }
}

impl HasBlack for Rgb<u8> {
    fn black() -> Self {
        Rgb([0u8; 3])
    }
}

impl HasWhite for Rgb<u8> {
    fn white() -> Self {
        Rgb([u8::MAX; 3])
    }
}

/// A type to which we can clamp a value of type T.
/// Implementations are not required to handle NaNs gracefully.
pub trait Clamp<T> {
    fn clamp(x: T) -> Self;
}

/// Creates an implementation of Clamp<To> for type From.
macro_rules! implement_clamp {
    ($from:ty, $to:ty) => (
        impl Clamp<$from> for $to {
            fn clamp(x: $from) -> $to {
                clamp_impl(x)
            }
        }
    )
}

implement_clamp!(f32, u8);
implement_clamp!(f32, u16);
implement_clamp!(f64, u8);
implement_clamp!(f64, u16);
implement_clamp!(i32, u8);
implement_clamp!(i32, u16);
implement_clamp!(i32, i16);

/// Clamp a value from a type with larger range to one with
/// a smaller range. Deliberately not exported - should be used
/// via the Clamp trait.
fn clamp_impl<From: NumCast + PartialOrd, To: NumCast + Bounded>(x: From) -> To {
    let to_max = <From as NumCast>::from(To::max_value()).unwrap();
    let to_min = <From as NumCast>::from(To::min_value()).unwrap();
    let clamped = partial_max(partial_min(x, to_max).unwrap(), to_min).unwrap();
    To::from(clamped).unwrap()
}

/// Copied from std::cmp as it's now deprecated.
fn partial_max<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
    match v1.partial_cmp(&v2) {
        Some(Equal) | Some(Less) => Some(v2),
        Some(Greater) => Some(v1),
        None => None
    }
}

/// Copied from std::cmp as it's now deprecated.
fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
    match v1.partial_cmp(&v2) {
        Some(Less) | Some(Equal) => Some(v1),
        Some(Greater) => Some(v2),
        None => None
    }
}

#[cfg(test)]
mod test {

    use super::Clamp;

    #[test]
    fn test_clamp_f32_u8() {
        let t: u8 = Clamp::clamp(255f32);
        assert_eq!(t, 255u8);
        let u: u8 = Clamp::clamp(300f32);
        assert_eq!(u, 255u8);
        let v: u8 = Clamp::clamp(0f32);
        assert_eq!(v, 0u8);
        let w: u8 = Clamp::clamp(-5f32);
        assert_eq!(w, 0u8);
    }

    #[test]
    fn test_clamp_f32_u16() {
        let t: u16 = Clamp::clamp(65535f32);
        assert_eq!(t, 65535u16);
        let u: u16 = Clamp::clamp(300000f32);
        assert_eq!(u, 65535u16);
        let v: u16 = Clamp::clamp(0f32);
        assert_eq!(v, 0u16);
        let w: u16 = Clamp::clamp(-5f32);
        assert_eq!(w, 0u16);
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::fmt;

use log::trace;

use rustc_span::DUMMY_SP;

use crate::*;

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort(Option<String>),
    UnsupportedInIsolation(String),
    ExperimentalUb { msg: String, url: String },
    Deadlock,
}

impl fmt::Debug for TerminationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TerminationInfo::*;
        match self {
            Exit(code) =>
                write!(f, "the evaluated program completed with exit code {}", code),
            Abort(None) =>
                write!(f, "the evaluated program aborted execution"),
            Abort(Some(msg)) =>
                write!(f, "the evaluated program aborted execution: {}", msg),
            UnsupportedInIsolation(msg) =>
                write!(f, "{}", msg),
            ExperimentalUb { msg, .. } =>
                write!(f, "{}", msg),
            Deadlock =>
                write!(f, "the evaluated program deadlocked"),
        }
    }
}

impl MachineStopType for TerminationInfo {}

/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
    PoppedTrackedPointerTag(Item),
    CreatedAlloc(AllocId),
    FreedAlloc(AllocId),
}

/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
    mut e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    use InterpError::*;

    let (title, helps) = match &e.kind {
        MachineStop(info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            use TerminationInfo::*;
            let title = match info {
                Exit(code) => return Some(*code),
                Abort(_) =>
                    "abnormal termination",
                UnsupportedInIsolation(_) =>
                    "unsupported operation",
                ExperimentalUb { .. } =>
                    "Undefined Behavior",
                Deadlock => "deadlock",
            };
            let helps = match info {
                UnsupportedInIsolation(_) =>
                    vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")],
                ExperimentalUb { url, .. } =>
                    vec![
                        format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"),
                        format!("see {} for further information", url),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
        _ => {
            let title = match e.kind {
                Unsupported(_) =>
                    "unsupported operation",
                UndefinedBehavior(_) =>
                    "Undefined Behavior",
                ResourceExhaustion(_) =>
                    "resource exhaustion",
                _ =>
                    bug!("This error should be impossible in Miri: {}", e),
            };
            let helps = match e.kind {
                Unsupported(UnsupportedOpInfo::NoMirFor(..)) =>
                    vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")],
                Unsupported(_) =>
                    vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")],
                UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) =>
                    vec![
                        format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
                        format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"),
                        format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs")
                    ],
                UndefinedBehavior(_) =>
                    vec![
                        format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"),
                        format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
    };

    e.print_backtrace();
    let msg = e.to_string();
    report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true)
}

/// Report an error or note (depending on the `error` argument) at the current frame's current statement.
/// Also emits a full stacktrace of the interpreter stack.
fn report_msg<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
    title: &str,
    span_msg: String,
    mut helps: Vec<String>,
    error: bool,
) -> Option<i64> {
    let span = if let Some(frame) = ecx.stack().last() {
        frame.current_source_info().unwrap().span
    } else {
        DUMMY_SP
    };
    let mut err = if error {
        ecx.tcx.sess.struct_span_err(span, title)
    } else {
        ecx.tcx.sess.diagnostic().span_note_diag(span, title)
    };
    err.span_label(span, span_msg);
    if !helps.is_empty() {
        // Add visual separator before backtrace.
        helps.last_mut().unwrap().push_str("\n");
        for help in helps {
            err.help(&help);
        }
    }
    // Add backtrace
    let frames = ecx.generate_stacktrace();
    for (idx, frame_info) in frames.iter().enumerate() {
        let is_local = frame_info.instance.def_id().is_local();
        // No span for non-local frames and the first frame (which is the error site).
        if is_local && idx > 0 {
            err.span_note(frame_info.span, &frame_info.to_string());
        } else {
            err.note(&frame_info.to_string());
        }
    }

    err.emit();

    for (i, frame) in ecx.stack().iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }
    // Let the reported error determine the return code.
    return None;
}

thread_local! {
    static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
}

/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
/// The diagnostic will be emitted after the current interpreter step is finished.
pub fn register_diagnostic(e: NonHaltingDiagnostic) {
    DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    /// Emit all diagnostics that were registed with `register_diagnostics`
    fn process_diagnostics(&self) {
        let this = self.eval_context_ref();
        DIAGNOSTICS.with(|diagnostics| {
            for e in diagnostics.borrow_mut().drain(..) {
                use NonHaltingDiagnostic::*;
                let msg = match e {
                    PoppedTrackedPointerTag(item) =>
                        format!("popped tracked tag for item {:?}", item),
                    CreatedAlloc(AllocId(id)) =>
                        format!("created allocation with id {}", id),
                    FreedAlloc(AllocId(id)) =>
                        format!("freed allocation with id {}", id),
                };
                report_msg(this, "tracking was triggered", msg, vec![], false);
            }
        });
    }
}
<commit_msg>Auto merge of #1341 - RalfJung:force-ptr-everywhere, r=oli-obk<commit_after>use std::cell::RefCell;
use std::fmt;

use log::trace;

use rustc_span::DUMMY_SP;

use crate::*;

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort(Option<String>),
    UnsupportedInIsolation(String),
    ExperimentalUb { msg: String, url: String },
    Deadlock,
}

impl fmt::Debug for TerminationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TerminationInfo::*;
        match self {
            Exit(code) =>
                write!(f, "the evaluated program completed with exit code {}", code),
            Abort(None) =>
                write!(f, "the evaluated program aborted execution"),
            Abort(Some(msg)) =>
                write!(f, "the evaluated program aborted execution: {}", msg),
            UnsupportedInIsolation(msg) =>
                write!(f, "{}", msg),
            ExperimentalUb { msg, .. } =>
                write!(f, "{}", msg),
            Deadlock =>
                write!(f, "the evaluated program deadlocked"),
        }
    }
}

impl MachineStopType for TerminationInfo {}

/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
    PoppedTrackedPointerTag(Item),
    CreatedAlloc(AllocId),
    FreedAlloc(AllocId),
}

/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
    mut e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    use InterpError::*;

    let (title, helps) = match &e.kind {
        MachineStop(info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            use TerminationInfo::*;
            let title = match info {
                Exit(code) => return Some(*code),
                Abort(_) =>
                    "abnormal termination",
                UnsupportedInIsolation(_) =>
                    "unsupported operation",
                ExperimentalUb { .. } =>
                    "Undefined Behavior",
                Deadlock => "deadlock",
            };
            let helps = match info {
                UnsupportedInIsolation(_) =>
                    vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")],
                ExperimentalUb { url, .. } =>
                    vec![
                        format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"),
                        format!("see {} for further information", url),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
        _ => {
            let title = match e.kind {
                Unsupported(_) =>
                    "unsupported operation",
                UndefinedBehavior(_) =>
                    "Undefined Behavior",
                ResourceExhaustion(_) =>
                    "resource exhaustion",
                _ =>
                    bug!("This error should be impossible in Miri: {}", e),
            };
            let helps = match e.kind {
                Unsupported(UnsupportedOpInfo::NoMirFor(..)) =>
                    vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")],
                Unsupported(UnsupportedOpInfo::ReadBytesAsPointer) =>
                    panic!("`ReadBytesAsPointer` cannot be raised by Miri"),
                Unsupported(_) =>
                    vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")],
                UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) =>
                    vec![
                        format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
                        format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"),
                        format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs")
                    ],
                UndefinedBehavior(_) =>
                    vec![
                        format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"),
                        format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
    };

    e.print_backtrace();
    let msg = e.to_string();
    report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true)
}

/// Report an error or note (depending on the `error` argument) at the current frame's current statement.
/// Also emits a full stacktrace of the interpreter stack.
fn report_msg<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
    title: &str,
    span_msg: String,
    mut helps: Vec<String>,
    error: bool,
) -> Option<i64> {
    let span = if let Some(frame) = ecx.stack().last() {
        frame.current_source_info().unwrap().span
    } else {
        DUMMY_SP
    };
    let mut err = if error {
        ecx.tcx.sess.struct_span_err(span, title)
    } else {
        ecx.tcx.sess.diagnostic().span_note_diag(span, title)
    };
    err.span_label(span, span_msg);
    if !helps.is_empty() {
        // Add visual separator before backtrace.
        helps.last_mut().unwrap().push_str("\n");
        for help in helps {
            err.help(&help);
        }
    }
    // Add backtrace
    let frames = ecx.generate_stacktrace();
    for (idx, frame_info) in frames.iter().enumerate() {
        let is_local = frame_info.instance.def_id().is_local();
        // No span for non-local frames and the first frame (which is the error site).
        if is_local && idx > 0 {
            err.span_note(frame_info.span, &frame_info.to_string());
        } else {
            err.note(&frame_info.to_string());
        }
    }

    err.emit();

    for (i, frame) in ecx.stack().iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }
    // Let the reported error determine the return code.
    return None;
}

thread_local! {
    static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
}

/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
/// The diagnostic will be emitted after the current interpreter step is finished.
pub fn register_diagnostic(e: NonHaltingDiagnostic) {
    DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    /// Emit all diagnostics that were registed with `register_diagnostics`
    fn process_diagnostics(&self) {
        let this = self.eval_context_ref();
        DIAGNOSTICS.with(|diagnostics| {
            for e in diagnostics.borrow_mut().drain(..) {
                use NonHaltingDiagnostic::*;
                let msg = match e {
                    PoppedTrackedPointerTag(item) =>
                        format!("popped tracked tag for item {:?}", item),
                    CreatedAlloc(AllocId(id)) =>
                        format!("created allocation with id {}", id),
                    FreedAlloc(AllocId(id)) =>
                        format!("freed allocation with id {}", id),
                };
                report_msg(this, "tracking was triggered", msg, vec![], false);
            }
        });
    }
}
<|endoftext|>


<commit_before>/// List of material font icons. Use this to generate a font Icon.
// emacs: use C-x 8 Ret => #xf207 ("BUS"-Glyph)
// pub const FLOPPY_FONT_ICON: &str = "";
// pub const ADD_FONT_ICON: &str = "";
// pub const LOAD_FONT_ICON: &str = "";
// pub const SAVE_FONT_ICON: &str = "";
// pub const KEYBOARD_ARROW_LEFT_FONT_ICON: &str = "";
// pub const KEYBOARD_ARROW_RIGHT_FONT_ICON: &str = "";
// pub const REMOVE_ICON: &str = "";
// pub const ARROW_DOWN_ICON: &str = "";

// pub const MENU_FONT_ICON: &str = "";
// pub const SETTINGS_FONT_ICON: &str = "";
// pub const HELP_OUTLINE_FONT_ICON: &str = "";

// // category: Social
// pub const ANDROID_FONT_ICON: &str = "";
// pub const APPLE_FONT_ICON: &str = "";
// pub const GITHUB_FONT_ICON: &str = "";
// pub const GOOGLE_FONT_ICON: &str = "";
// pub const GOOGLE_DRIVE_FONT_ICON: &str = "";
// pub const GOOGLE_MAPS_FONT_ICON: &str = "";
// pub const LANGUAGE_JAVASCRIPT_FONT_ICON: &str = "";
// pub const LANGUAGE_HTML5_FONT_ICON: &str = "";
// pub const LANGUAGE_PYTHON_ICON: &str = "";
// pub const PAYPAL_FONT_ICON: &str = "";
// pub const POCKET_FONT_ICON: &str = "";
// pub const RSS_FONT_ICON: &str = "";
// pub const SHARE_FONT_ICON: &str = "";
// pub const STEAM_FONT_ICON: &str = "";
// pub const TWITTER_BOX_FONT_ICON: &str = "";
// pub const TWITTER_FONT_ICON: &str = "";
// pub const WIKIPEDIA_FONT_ICON: &str = "";
// pub const LINKEDIN_FONT_ICON: &str = "";
// pub const REDDIT_FONT_ICON: &str = "";
// pub const VIMEO_FONT_ICON: &str = "";
// pub const WINDOWS_FONT_ICON: &str = "";

// // category: Person
// pub const ACCOUNT_FONT_ICON: &str = "";
// pub const ACCOUNT_ADD_FONT_ICON: &str = "";
// pub const ACCOUNT_BOX_FONT_ICON: &str = "";
// pub const ACCOUNT_CIRCLE_FONT_ICON: &str = "";
// pub const ACCOUNTS_ADD_FONT_ICON: &str = "";
// pub const ACCOUNTS_FONT_ICON: &str = "";
// pub const MALE_FONT_ICON: &str = "";
// pub const FEMALE_FONT_ICON: &str = "";
// pub const MALE_FEMALE_FONT_ICON: &str = "";
// pub const RUN_FONT_ICON: &str = "";
// pub const WALK_FONT_ICON: &str = "";

// // category: File
// pub const CLOUD_FONT_ICON: &str = "";
// pub const DOWNLOAD_FONT_ICON: &str = "";
// pub const UPLOAD_FONT_ICON: &str = "";
// pub const FILE_FONT_ICON: &str = "";
// pub const FOLDER_FONT_ICON: &str = "";
// pub const FOLDER_OUTLINE_FONT_ICON: &str = "";
// pub const CLOUD_DONE_FONT_ICON: &str = "";
// pub const CLOUD_OFF_FONT_ICON: &str = "";
// pub const CLOUD_DOWNLOAD_FONT_ICON: &str = "";
// pub const CLOUD_OUTLINE_FONT_ICON: &str = "";
// pub const CLOUD_UPLOAD_FONT_ICON: &str = "";

// // category: Comment
// pub const COMMENT_FONT_ICON: &str = "";
// pub const COMMENT_LIST_FONT_ICON: &str = "";
// pub const COMMENT_IMAGE_FONT_ICON: &str = "";
// pub const COMMENT_EDIT_FONT_ICON: &str = "";
// pub const COMMENT_ALERT_FONT_ICON: &str = "";
// pub const COMMENT_MORE_FONT_ICON: &str = "";
// pub const COMMENT_OUTLINE_FONT_ICON: &str = "";
// pub const COMMENTS_FONT_ICON: &str = "";
// pub const COMMENT_VIDEO_TEXT_FONT_ICON: &str = "";
// pub const COMMENT_TEXT_FONT_ICON: &str = "";

// // category: Form
// pub const CHECK_ALL_FONT_ICON: &str = "";
// pub const CHECK_CIRCLE_U_FONT_ICON: &str = "";
// pub const CHECK_CIRCLE_FONT_ICON: &str = "";
// pub const CHECK_SQUARE_FONT_ICON: &str = "";
// pub const CHECK_FONT_ICON: &str = "";
// //pub const CHECK_FONT_ICON: &str = "";
// pub const CIRCLE_O_FONT_ICON: &str = "";
// pub const CIRCLE_FONT_ICON: &str = "";
// pub const DOT_CIRCLE_ALT_FONT_ICON: &str = "";
// pub const DOT_CIRCLE_FONT_ICON: &str = "";
// pub const MINUS_CIRCLE_OUTLINE_FONT_ICON: &str = "";
// pub const MINUS_CIRCLE_FONT_ICON: &str = "";
// pub const MINUS_SQUARE_FONT_ICON: &str = "";
// pub const MINUS_FONT_ICON: &str = "";
// //pub const MINUS_FONT_ICON: &str = "";
// pub const PLUS_CIRCLE_O_DUPLICATE_FONT_ICON: &str = "";
// pub const PLUS_CIRCLE_O_FONT_ICON: &str = "";
// pub const PLUS_CIRCLE_FONT_ICON: &str = "";
// pub const PLUS_SQUARE_FONT_ICON: &str = "";
// pub const PLUS_FONT_ICON: &str = "";
// pub const SQUARE_O_FONT_ICON: &str = "";
// pub const STAR_CIRCLE_FONT_ICON: &str = "";
// pub const STAR_HALF_FONT_ICON: &str = "";
// pub const STAR_OUTLINE_FONT_ICON: &str = "";
// pub const STAR_STAR_FONT_ICON: &str = "";

/// List of material font icons. Use this to generate a font Icon.
pub const FLOPPY_FONT_ICON: &str = "";
pub const CHECK_FONT_ICON: &str = "";
pub const ADD_FONT_ICON: &str = "";
pub const MINUS_FONT_ICON: &str = "";
pub const LOAD_FONT_ICON: &str = "";
pub const SAVE_FONT_ICON: &str = "";
pub const KEYBOARD_ARROW_LEFT_FONT_ICON: &str = "";
pub const KEYBOARD_ARROW_RIGHT_FONT_ICON: &str = "";
pub const REMOVE_ICON: &str = "";
pub const ARROW_DOWN_ICON: &str = "";<commit_msg>theme: vector_graphics: update material_icons_font_ttf.rs<commit_after>/// List of material font icons. Use this to generate a font Icon.

// This is kept for compability
// Please use meterial_icons_font.rs instead
pub const FLOPPY_FONT_ICON: &str = "";
pub const CHECK_FONT_ICON: &str = "";
pub const ADD_FONT_ICON: &str = "";
pub const MINUS_FONT_ICON: &str = "";
pub const LOAD_FONT_ICON: &str = "";
pub const SAVE_FONT_ICON: &str = "";
pub const KEYBOARD_ARROW_LEFT_FONT_ICON: &str = "";
pub const KEYBOARD_ARROW_RIGHT_FONT_ICON: &str = "";
pub const REMOVE_ICON: &str = "";
pub const ARROW_DOWN_ICON: &str = "";
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! 64-bit Interrupt Descriptor Table implementation.
//!
//! Refer to section 6.10 of the _Intel® 64 and IA-32 Architectures
//! Software Developer’s Manual_ for more information.
use core::mem;
use core::ptr;
use spin::Mutex;
use super::{Registers, DTable, DTablePtr, segment};

#[path = "../../x86_all/interrupts.rs"] mod interrupts_all;
#[path = "../../x86_all/pics.rs"] pub mod pics;
pub use self::interrupts_all::*;

//==------------------------------------------------------------------------==
// Interface into ASM interrupt handling
extern {
    /// Offset of the 64-bit GDT main code segment.
    /// Exported by `boot.asm`
    static gdt64_offset: u16;

    /// Array of interrupt handlers from ASM
    static interrupt_handlers: [*const u8; IDT_ENTRIES];
}

/// State stored when handling an interrupt.
#[allow(dead_code)]
#[repr(C, packed)]
pub struct InterruptCtx64 { /// callee-saved registers
                            pub registers: Registers
                          , /// interrupt ID number
                            pub int_id:  u32
                          , __pad_1: u32
                          , /// error number
                            pub err_no:  u32
                          , __pad_2: u32
                          }

impl InterruptContext for InterruptCtx64 {
    type Registers = Registers;
    // All these inline functions are basically just faking
    // object orientation in a way the Rust compiler understands
    #[inline] fn registers(&self) -> Self::Registers { self.registers }
    #[inline] fn err_no(&self) -> u32 { self.err_no }
    #[inline] fn int_id(&self) -> u32 { self.int_id }
}

//==------------------------------------------------------------------------==
// 64-bit implementation of the IDT gate trait

/// An IDT entry is called a gate.
///
/// Based on code from the OS Dev Wiki
/// http://wiki.osdev.org/Interrupt_Descriptor_Table#Structure
///
/// Refer also to "6.14.1 64-Bit Mode IDT"  and "Table 3-2. System-Segment and
/// Gate-Descriptor Types" in the _Intel® 64 and IA-32 Architectures
/// Software Developer’s Manual_
#[repr(C, packed)]
#[derive(Copy,Clone)]
pub struct Gate64 { /// bits 0 - 15 of the offset
                    pub offset_lower: u16
                  , /// code segment selector (GDT or LDT)
                    pub selector: segment::Selector
                  , /// always zero
                    zero: u8
                  , /// indicates the gate's type and attributes.
                    /// the second half indicates the type:
                    ///   + `0b1100`: Call gate
                    ///   + `0b1110`: Interrupt gate
                    ///   + `0b1111`: Trap Gate
                    pub type_attr: GateType
                  , /// bits 16 - 31 of the offset
                    pub offset_mid: u16
                  , /// bits 32 - 63 of the offset
                    pub offset_upper: u32
                  , /// always zero (according to the spec, this is "reserved")
                    reserved: u32
                  }

impl Gate64 {
    /// Creates a new IDT gate marked as `absent`.
    ///
    /// This is basically just for filling the new IDT table
    /// with valid (but useless) gates upon init.
    ///
    /// This would be in the `Gate` trait, but this has to be a `const fn` so
    /// that it can be usedm in static initializers, and trait functions cannot
    /// be `const`.
    ///
    /// Actually triggering an absent interrupt will send a General Protection
    /// fault (13).
    const fn absent() -> Self {
        Gate64 { offset_lower: 0
               , selector: segment::Selector::from_raw(0)
               , zero: 0
               , type_attr: GateType::Absent
               , offset_mid: 0
               , offset_upper: 0
               , reserved: 0
               }
    }
}

impl Gate for Gate64 {

    /// Creates a new IDT gate pointing at the given handler function.
    ///
    /// The `handler` function must have been created with valid interrupt
    /// calling conventions.
    fn from_handler(handler: Handler) -> Self {
        unsafe { // trust me on this.
                 // `mem::transmute()` is glorious black magic
            let (low, mid, high): (u16, u16, u32)
                = mem::transmute(handler);

            Gate64 { offset_lower: low
                   , selector: segment::Selector::from_raw(gdt64_offset)
                   , zero: 0
                   // Bit 7 is the present bit
                   // Bits 4-0 indicate this is an interrupt gate
                   , type_attr: GateType::Interrupt
                   , offset_mid: mid
                   , offset_upper: high
                   , reserved: 0
                   }
        }
    }

    unsafe fn from_raw(handler: *const u8) -> Self {
        let (low, mid, high): (u16, u16, u32)
            = mem::transmute(handler as u64);

        Gate64 { offset_lower: low
               , selector: segment::Selector::from_raw(gdt64_offset)
               , zero: 0
               , type_attr: GateType::Interrupt
               , offset_mid: mid
               , offset_upper: high
               , reserved: 0
               }
    }
}

//==------------------------------------------------------------------------==
// 64-bit implementation of the IDT trait
struct Idt64([Gate64; IDT_ENTRIES]);

impl Idt for Idt64 {
    // type Ptr = IdtPtr<Self>;
    type Ctx = InterruptCtx64;
    type GateSize = Gate64;
    type PtrSize = u64;

    fn get_ptr(&self) -> DTablePtr<u64>{
        DTablePtr { limit: (mem::size_of::<Self::GateSize>() * IDT_ENTRIES)
                            as u16
                  , base: &self.0[0] as *const Gate64 as u64
                  }
    }

    /// Get the IDT pointer struct to pass to `lidt`
    // fn get_ptr(&self) -> DTablePtr<Self> {
    //     IdtPtr { limit: (mem::size_of::<Gate64>() * IDT_ENTRIES) as u16
    //            , base:  self as *const Idt64
    //            }
    // }

    /// Add an entry for the given handler at the given index
    fn add_gate(&mut self, index: usize, handler: Handler) {
        self.0[index] = Gate64::from_handler(handler)
    }

    /// Assembly interrupt handlers call into this
    #[no_mangle]
    unsafe extern "C" fn handle_interrupt(state: &Self::Ctx) {
        let id = state.int_id();
        match id {
            // interrupts 0 - 16 are CPU exceptions
            0x00...0x0f => Self::handle_cpu_exception(state)
            // System timer
          , 0x20 => { /* TODO: make this work */ }
            // Keyboard
          , 0x21 => { /* TODO: make this work */ }
            // Loonix syscall vector
          , 0x80 => { // TODO: currently, we do nothing here, do we want
                      // our syscalls on this vector as well?
            }
          , _ => panic!("Unknown interrupt: #{} Sorry!", id)
        }
        // send the PICs the end interrupt signal
        pics::end_pic_interrupt(id as u8);
    }
}

impl DTable for Idt64 {
    #[inline] unsafe fn load(&self) {
        print!("Loading IDT...");
        asm!(  "lidt ($0)"
            :: "r"(&self.get_ptr())
            :  "memory" );
        println!("    [DONE]");
    }
}

impl Idt64 {
    fn add_handlers(&mut self) -> &mut Self {
        print!("Adding interrupt handlers to IDT...");
        for (i, &h_ptr) in interrupt_handlers.iter()
            .enumerate()
            .filter(|&(_, &h_ptr)| h_ptr != ptr::null() ) {
                unsafe { self.0[i] = Gate64::from_raw(h_ptr) }
        }
        println!("    [DONE]");
        self
    }
}

// impl IdtPtrOps for IdtPtr<Idt64> {
//     /// Load the IDT at the given location.
//     /// This just calls `lidt`.
//     unsafe fn load(&self) {
//         asm!(  "lidt ($0)"
//             :: "{rax}"(self)
//             :: "volatile" );
//     }
// }

/// Global Interrupt Descriptor Table instance
/// Our global IDT.
static IDT: Mutex<Idt64>
    = Mutex::new(Idt64([Gate64::absent(); IDT_ENTRIES]));

pub unsafe fn initialize() {
    pics::initialize();
    // TODO: load interrupts into IDT
    IDT.lock()
       .add_handlers()
       .load();                 // Load the IDT pointer
    // print!("Testing interrupt handling...");
    // asm!("int $0" :: "N" (0x80));
    // println!("   [DONE]");

    Idt64::enable_interrupts(); // enable interrupts
}
<commit_msg>[x86_64] Removed some dead comments from IDT<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! 64-bit Interrupt Descriptor Table implementation.
//!
//! Refer to section 6.10 of the _Intel® 64 and IA-32 Architectures
//! Software Developer’s Manual_ for more information.
use core::mem;
use core::ptr;
use spin::Mutex;
use super::{Registers, DTable, DTablePtr, segment};

#[path = "../../x86_all/interrupts.rs"] mod interrupts_all;
#[path = "../../x86_all/pics.rs"] pub mod pics;
pub use self::interrupts_all::*;

//==------------------------------------------------------------------------==
// Interface into ASM interrupt handling
extern {
    /// Offset of the 64-bit GDT main code segment.
    /// Exported by `boot.asm`
    static gdt64_offset: u16;

    /// Array of interrupt handlers from ASM
    static interrupt_handlers: [*const u8; IDT_ENTRIES];
}

/// State stored when handling an interrupt.
#[allow(dead_code)]
#[repr(C, packed)]
pub struct InterruptCtx64 { /// callee-saved registers
                            pub registers: Registers
                          , /// interrupt ID number
                            pub int_id:  u32
                          , __pad_1: u32
                          , /// error number
                            pub err_no:  u32
                          , __pad_2: u32
                          }

impl InterruptContext for InterruptCtx64 {
    type Registers = Registers;
    // All these inline functions are basically just faking
    // object orientation in a way the Rust compiler understands
    #[inline] fn registers(&self) -> Self::Registers { self.registers }
    #[inline] fn err_no(&self) -> u32 { self.err_no }
    #[inline] fn int_id(&self) -> u32 { self.int_id }
}

//==------------------------------------------------------------------------==
// 64-bit implementation of the IDT gate trait

/// An IDT entry is called a gate.
///
/// Based on code from the OS Dev Wiki
/// http://wiki.osdev.org/Interrupt_Descriptor_Table#Structure
///
/// Refer also to "6.14.1 64-Bit Mode IDT"  and "Table 3-2. System-Segment and
/// Gate-Descriptor Types" in the _Intel® 64 and IA-32 Architectures
/// Software Developer’s Manual_
#[repr(C, packed)]
#[derive(Copy,Clone)]
pub struct Gate64 { /// bits 0 - 15 of the offset
                    pub offset_lower: u16
                  , /// code segment selector (GDT or LDT)
                    pub selector: segment::Selector
                  , /// always zero
                    zero: u8
                  , /// indicates the gate's type and attributes.
                    /// the second half indicates the type:
                    ///   + `0b1100`: Call gate
                    ///   + `0b1110`: Interrupt gate
                    ///   + `0b1111`: Trap Gate
                    pub type_attr: GateType
                  , /// bits 16 - 31 of the offset
                    pub offset_mid: u16
                  , /// bits 32 - 63 of the offset
                    pub offset_upper: u32
                  , /// always zero (according to the spec, this is "reserved")
                    reserved: u32
                  }

impl Gate64 {
    /// Creates a new IDT gate marked as `absent`.
    ///
    /// This is basically just for filling the new IDT table
    /// with valid (but useless) gates upon init.
    ///
    /// This would be in the `Gate` trait, but this has to be a `const fn` so
    /// that it can be usedm in static initializers, and trait functions cannot
    /// be `const`.
    ///
    /// Actually triggering an absent interrupt will send a General Protection
    /// fault (13).
    const fn absent() -> Self {
        Gate64 { offset_lower: 0
               , selector: segment::Selector::from_raw(0)
               , zero: 0
               , type_attr: GateType::Absent
               , offset_mid: 0
               , offset_upper: 0
               , reserved: 0
               }
    }
}

impl Gate for Gate64 {

    /// Creates a new IDT gate pointing at the given handler function.
    ///
    /// The `handler` function must have been created with valid interrupt
    /// calling conventions.
    fn from_handler(handler: Handler) -> Self {
        unsafe { // trust me on this.
                 // `mem::transmute()` is glorious black magic
            let (low, mid, high): (u16, u16, u32)
                = mem::transmute(handler);

            Gate64 { offset_lower: low
                   , selector: segment::Selector::from_raw(gdt64_offset)
                   , zero: 0
                   // Bit 7 is the present bit
                   // Bits 4-0 indicate this is an interrupt gate
                   , type_attr: GateType::Interrupt
                   , offset_mid: mid
                   , offset_upper: high
                   , reserved: 0
                   }
        }
    }

    unsafe fn from_raw(handler: *const u8) -> Self {
        let (low, mid, high): (u16, u16, u32)
            = mem::transmute(handler as u64);

        Gate64 { offset_lower: low
               , selector: segment::Selector::from_raw(gdt64_offset)
               , zero: 0
               , type_attr: GateType::Interrupt
               , offset_mid: mid
               , offset_upper: high
               , reserved: 0
               }
    }
}

//==------------------------------------------------------------------------==
// 64-bit implementation of the IDT trait
struct Idt64([Gate64; IDT_ENTRIES]);

impl Idt for Idt64 {
    type Ctx = InterruptCtx64;
    type GateSize = Gate64;
    type PtrSize = u64;

    fn get_ptr(&self) -> DTablePtr<u64>{
        DTablePtr { limit: (mem::size_of::<Self::GateSize>() * IDT_ENTRIES)
                            as u16
                  , base: &self.0[0] as *const Gate64 as u64
                  }
    }

    /// Add an entry for the given handler at the given index
    fn add_gate(&mut self, index: usize, handler: Handler) {
        self.0[index] = Gate64::from_handler(handler)
    }

    /// Assembly interrupt handlers call into this
    #[no_mangle]
    unsafe extern "C" fn handle_interrupt(state: &Self::Ctx) {
        let id = state.int_id();
        match id {
            // interrupts 0 - 16 are CPU exceptions
            0x00...0x0f => Self::handle_cpu_exception(state)
            // System timer
          , 0x20 => { /* TODO: make this work */ }
            // Keyboard
          , 0x21 => { /* TODO: make this work */ }
            // Loonix syscall vector
          , 0x80 => { // TODO: currently, we do nothing here, do we want
                      // our syscalls on this vector as well?
            }
          , _ => panic!("Unknown interrupt: #{} Sorry!", id)
        }
        // send the PICs the end interrupt signal
        pics::end_pic_interrupt(id as u8);
    }
}

impl DTable for Idt64 {
    #[inline] unsafe fn load(&self) {
        print!("Loading IDT...");
        asm!(  "lidt ($0)"
            :: "r"(&self.get_ptr())
            :  "memory" );
        println!("    [DONE]");
    }
}

impl Idt64 {
    fn add_handlers(&mut self) -> &mut Self {
        print!("Adding interrupt handlers to IDT...");
        for (i, &h_ptr) in interrupt_handlers.iter()
            .enumerate()
            .filter(|&(_, &h_ptr)| h_ptr != ptr::null() ) {
                unsafe { self.0[i] = Gate64::from_raw(h_ptr) }
        }
        println!("    [DONE]");
        self
    }
}

/// Global Interrupt Descriptor Table instance
/// Our global IDT.
static IDT: Mutex<Idt64>
    = Mutex::new(Idt64([Gate64::absent(); IDT_ENTRIES]));

pub unsafe fn initialize() {
    pics::initialize();
    IDT.lock()
       .add_handlers()
       .load();                 // Load the IDT pointer
    // print!("Testing interrupt handling...");
    // asm!("int $0" :: "N" (0x80));
    // println!("   [DONE]");

    Idt64::enable_interrupts(); // enable interrupts
}
<|endoftext|>


<commit_before>// Copyright 2020, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use proc_macro2::{Ident, Span, TokenStream};
use proc_macro_error::abort_call_site;
use proc_macro_crate::crate_name;
use quote::quote;

use crate::utils::{find_attribute_meta, find_nested_meta, parse_type_name};

fn gen_option_to_ptr(nullable: bool) -> TokenStream {
    if nullable {
        quote! {
            match this {
                Some(this) => Box::into_raw(Box::new(this.clone())),
                None => std::ptr::null_mut(),
            };
        }
    } else {
        quote! {
            Box::into_raw(Box::new(this.expect("None not allowed").clone()));
        }
    }
}

fn gen_ptr_to_option(name: &Ident, nullable: bool) -> TokenStream {
    if nullable {
        quote! {
            if ptr.is_null() {
                None
            } else {
                Some(&*(ptr as *mut #name))
            }
        }
    } else {
        quote! {
            assert!(!ptr.is_null());
            Some(&*(ptr as *mut #name))
        }
    }
}

fn gen_impl_from_value(name: &Ident, crate_ident: &Ident) -> TokenStream {
    quote! {
        impl<'a> #crate_ident::value::FromValue<'a> for &'a #name {
            unsafe fn from_value(value: &'a #crate_ident::value::Value) -> Self {
                let ptr = #crate_ident::gobject_sys::g_value_get_boxed(
                    #crate_ident::translate::ToGlibPtr::to_glib_none(value).0,
                );
                assert!(!ptr.is_null());
                &*(ptr as *mut #name)
            }
        }
    }
}

pub fn impl_gboxed(input: &syn::DeriveInput) -> TokenStream {
    let name = &input.ident;

    let gtype_name = match parse_type_name(&input, "gboxed") {
        Ok(v) => v,
        Err(e) => abort_call_site!(
            "{}: derive(GBoxed) requires #[gboxed(type_name = \"BoxedTypeName\")]",
            e
        ),
    };

    let crate_name = match crate_name("glib") {
        Ok(x) => x,
	Err(_) => {
            // In case we use it directly from glib itself (it cannot find glib as a dependency
	    // in this case)
            "glib".to_owned()
	}
    };
    let crate_ident = Ident::new(&crate_name, Span::call_site());

    let meta = find_attribute_meta(&input.attrs, "gboxed")
        .unwrap()
        .unwrap();
    let nullable = find_nested_meta(&meta, "nullable").is_some();

    let option_to_ptr = gen_option_to_ptr(nullable);
    let ptr_to_option = gen_ptr_to_option(name, nullable);
    let impl_from_value = if !nullable {
        gen_impl_from_value(name, &crate_ident)
    } else {
        quote! {}
    };

    quote! {
        impl BoxedType for #name {
            const NAME: &'static str = #gtype_name;

            fn get_type() -> #crate_ident::Type {
                static mut TYPE_: #crate_ident::Type = #crate_ident::Type::Invalid;
                static ONCE: ::std::sync::Once = ::std::sync::Once::new();

                ONCE.call_once(|| {
                    let type_ = #crate_ident::subclass::register_boxed_type::<Self>();
                    unsafe {
                        TYPE_ = type_;
                    }
                });

                unsafe { TYPE_ }
            }
        }

        impl #crate_ident::StaticType for #name {
            fn static_type() -> #crate_ident::Type {
                <#name as #crate_ident::subclass::boxed::BoxedType>::get_type()
            }
        }

        impl #crate_ident::value::SetValue for #name {
            unsafe fn set_value(value: &mut #crate_ident::value::Value, this: &Self) {
                let ptr: *mut #name = Box::into_raw(Box::new(this.clone()));
                #crate_ident::gobject_sys::g_value_take_boxed(
                    #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(value).0,
                    ptr as *mut _,
                );
            }
        }

        impl #crate_ident::value::SetValueOptional for #name {
            unsafe fn set_value_optional(value: &mut #crate_ident::value::Value, this: Option<&Self>) {
                let ptr: *mut #name = #option_to_ptr;
                #crate_ident::gobject_sys::g_value_take_boxed(
                    #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(value).0,
                    ptr as *mut _,
                );
            }
        }

        impl<'a> #crate_ident::value::FromValueOptional<'a> for &'a #name {
            unsafe fn from_value_optional(value: &'a #crate_ident::value::Value) -> Option<Self> {
                let ptr = #crate_ident::gobject_sys::g_value_get_boxed(
                    #crate_ident::translate::ToGlibPtr::to_glib_none(value).0,
                );
                #ptr_to_option
            }
        }

        #impl_from_value
    }
}
<commit_msg>glib-macros: cargo fmt<commit_after>// Copyright 2020, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use proc_macro2::{Ident, Span, TokenStream};
use proc_macro_crate::crate_name;
use proc_macro_error::abort_call_site;
use quote::quote;

use crate::utils::{find_attribute_meta, find_nested_meta, parse_type_name};

fn gen_option_to_ptr(nullable: bool) -> TokenStream {
    if nullable {
        quote! {
            match this {
                Some(this) => Box::into_raw(Box::new(this.clone())),
                None => std::ptr::null_mut(),
            };
        }
    } else {
        quote! {
            Box::into_raw(Box::new(this.expect("None not allowed").clone()));
        }
    }
}

fn gen_ptr_to_option(name: &Ident, nullable: bool) -> TokenStream {
    if nullable {
        quote! {
            if ptr.is_null() {
                None
            } else {
                Some(&*(ptr as *mut #name))
            }
        }
    } else {
        quote! {
            assert!(!ptr.is_null());
            Some(&*(ptr as *mut #name))
        }
    }
}

fn gen_impl_from_value(name: &Ident, crate_ident: &Ident) -> TokenStream {
    quote! {
        impl<'a> #crate_ident::value::FromValue<'a> for &'a #name {
            unsafe fn from_value(value: &'a #crate_ident::value::Value) -> Self {
                let ptr = #crate_ident::gobject_sys::g_value_get_boxed(
                    #crate_ident::translate::ToGlibPtr::to_glib_none(value).0,
                );
                assert!(!ptr.is_null());
                &*(ptr as *mut #name)
            }
        }
    }
}

pub fn impl_gboxed(input: &syn::DeriveInput) -> TokenStream {
    let name = &input.ident;

    let gtype_name = match parse_type_name(&input, "gboxed") {
        Ok(v) => v,
        Err(e) => abort_call_site!(
            "{}: derive(GBoxed) requires #[gboxed(type_name = \"BoxedTypeName\")]",
            e
        ),
    };

    let crate_name = match crate_name("glib") {
        Ok(x) => x,
        Err(_) => {
            // In case we use it directly from glib itself (it cannot find glib as a dependency
            // in this case)
            "glib".to_owned()
        }
    };
    let crate_ident = Ident::new(&crate_name, Span::call_site());

    let meta = find_attribute_meta(&input.attrs, "gboxed")
        .unwrap()
        .unwrap();
    let nullable = find_nested_meta(&meta, "nullable").is_some();

    let option_to_ptr = gen_option_to_ptr(nullable);
    let ptr_to_option = gen_ptr_to_option(name, nullable);
    let impl_from_value = if !nullable {
        gen_impl_from_value(name, &crate_ident)
    } else {
        quote! {}
    };

    quote! {
        impl BoxedType for #name {
            const NAME: &'static str = #gtype_name;

            fn get_type() -> #crate_ident::Type {
                static mut TYPE_: #crate_ident::Type = #crate_ident::Type::Invalid;
                static ONCE: ::std::sync::Once = ::std::sync::Once::new();

                ONCE.call_once(|| {
                    let type_ = #crate_ident::subclass::register_boxed_type::<Self>();
                    unsafe {
                        TYPE_ = type_;
                    }
                });

                unsafe { TYPE_ }
            }
        }

        impl #crate_ident::StaticType for #name {
            fn static_type() -> #crate_ident::Type {
                <#name as #crate_ident::subclass::boxed::BoxedType>::get_type()
            }
        }

        impl #crate_ident::value::SetValue for #name {
            unsafe fn set_value(value: &mut #crate_ident::value::Value, this: &Self) {
                let ptr: *mut #name = Box::into_raw(Box::new(this.clone()));
                #crate_ident::gobject_sys::g_value_take_boxed(
                    #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(value).0,
                    ptr as *mut _,
                );
            }
        }

        impl #crate_ident::value::SetValueOptional for #name {
            unsafe fn set_value_optional(value: &mut #crate_ident::value::Value, this: Option<&Self>) {
                let ptr: *mut #name = #option_to_ptr;
                #crate_ident::gobject_sys::g_value_take_boxed(
                    #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(value).0,
                    ptr as *mut _,
                );
            }
        }

        impl<'a> #crate_ident::value::FromValueOptional<'a> for &'a #name {
            unsafe fn from_value_optional(value: &'a #crate_ident::value::Value) -> Option<Self> {
                let ptr = #crate_ident::gobject_sys::g_value_get_boxed(
                    #crate_ident::translate::ToGlibPtr::to_glib_none(value).0,
                );
                #ptr_to_option
            }
        }

        #impl_from_value
    }
}
<|endoftext|>


<commit_before>
#[macro_use] extern crate tera;
#[macro_use] extern crate lazy_static;
extern crate serde_json;

use tera::{Tera, ast};

lazy_static! {
    pub static ref TERA: Tera = compile_templates!("examples/templates/**/*");
}

fn main() {
    for node in TERA.get_template("users/profile.html").unwrap().ast.get_children() {
        match node {
            ast::Node::Extends(ref name) => println!("Extending {}", name),
            _ => println!("Another node")
        }
    }
}
<commit_msg>Update ast example<commit_after>
#[macro_use] extern crate tera;
#[macro_use] extern crate lazy_static;
extern crate serde_json;

use tera::{Tera, ast};

lazy_static! {
    pub static ref TERA: Tera = compile_templates!("examples/templates/**/*");
}

// Very basic fn to find identifier names
fn find_identifiers(node: ast::Node, names: &mut Vec<String>) {
    match node {
        ast::Node::Block {ref body, ..} => {
          for n in body.get_children() {
              find_identifiers(n, names);
          }
        },
        ast::Node::VariableBlock(n) => match *n {
            ast::Node::Identifier {ref name, ..} => names.push(name.clone()),
            _ => ()
        },
        _ => ()
    }
}

fn main() {
    let mut var_names = vec![];

    for node in TERA.get_template("users/profile.html").unwrap().ast.get_children() {
        find_identifiers(node, &mut var_names);
    }

    println!("Variables used: {:?}", var_names);
}
<|endoftext|>


<commit_before>//! A simple application that downloads the data dictionary and creates code or
//! data to reproduce it in the core library.
//!
//! ### How to use
//!
//! Simply run the application. It will automatically retrieve the dictionary
//! from the DCMTK data dictionary and store the result in "tags.rs".
//! Future versions will enable different kinds of outputs.
//!
//! Please use the `--help` flag for the full usage information.

use clap::{App, Arg};
use regex::Regex;
use serde::Serialize;

use heck::ShoutySnakeCase;
use std::io::{BufRead, BufReader, Write};
use std::path::Path;
use std::{
    fs::{create_dir_all, File},
    io::BufWriter,
};

/// url to DCMTK dic file
const DEFAULT_LOCATION: &str =
    "https://raw.githubusercontent.com/DCMTK/dcmtk/master/dcmdata/data/dicom.dic";

#[derive(Debug, Copy, Clone, PartialEq)]
enum RetiredOptions {
    /// ignore retired data attributes
    Ignore,
    /// include retired data attributes
    Include {
        /// mark constants as deprecated
        deprecate: bool,
    },
}

fn main() {
    let matches = App::new("DICOM Dictionary Builder")
        .version("0.1.0")
        .arg(
            Arg::with_name("FROM")
                .default_value(DEFAULT_LOCATION)
                .help("Where to fetch the dictionary from"),
        )
        .arg(
            Arg::with_name("no-retired")
                .long("no-retired")
                .help("Whether to ignore retired tags")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("deprecate-retired")
                .long("deprecate-retired")
                .help("Whether to mark tag constants as deprecated")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("OUTPUT")
                .short("o")
                .help("The path to the output file")
                .default_value("tags.rs")
                .takes_value(true),
        )
        .get_matches();

    let ignore_retired = matches.is_present("no-retired");

    let retired = if ignore_retired {
        RetiredOptions::Ignore
    } else {
        RetiredOptions::Include {
            deprecate: matches.is_present("deprecate-retired"),
        }
    };

    let src = matches.value_of("FROM").unwrap();

    let dst = Path::new(matches.value_of("OUTPUT").unwrap());

    if src.starts_with("http:") || src.starts_with("https:") {
        // read from URL
        println!("Downloading DICOM dictionary ...");
        let mut resp = reqwest::blocking::get(src).unwrap();
        let mut data = vec![];
        resp.copy_to(&mut data).unwrap();

        let preamble = data
            .split(|&b| b == b'\n')
            .filter_map(|l| std::str::from_utf8(l).ok())
            .find(|l| l.contains("Copyright"))
            .unwrap_or("");
        let preamble = format!(
            "Adapted from the DCMTK project.\nURL: {}\nLicense: {}\n{}",
            src, "https://github.com/DCMTK/dcmtk/blob/master/COPYRIGHT", preamble,
        );

        let entries = parse_entries(&*data).unwrap();
        println!("Writing to file ...");
        to_code_file(dst, entries, retired, &preamble).expect("Failed to write file");
    } else {
        // read from File
        let file = File::open(src).unwrap();
        let entries = parse_entries(BufReader::new(file)).unwrap();
        println!("Writing to file ...");
        to_code_file(dst, entries, retired, "").expect("Failed to write file");
    }
}

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

fn parse_entries<R: BufRead>(source: R) -> DynResult<Vec<Entry>> {
    let mut result = vec![];

    for line in source.lines() {
        let line = line?;
        if line.starts_with('#') {
            continue;
        }

        // (0010,0010)	PN	PatientName	1	DICOM
        let parts: Vec<&str> = line.split('\t').collect();

        if parts[4] == "ILLEGAL" || parts[4] == "PRIVATE" || parts[4] == "GENERIC" {
            continue;
        }

        let mut vr = parts[1].to_string();

        // Some fields are dependent upon context.
        // We may want to support this at some point, but for now,
        // let's just choose some good defaults.
        if vr == "up" {
            vr = "UL".to_string();
        }
        if vr == "xs" {
            vr = "US".to_string();
        }
        if vr == "ox" {
            vr = "OB".to_string();
        }
        if vr == "px" {
            vr = "OB".to_string();
        }
        if vr == "lt" {
            vr = "OW".to_string();
        }
        if vr == "na" {
            // These are the "Item", "ItemDelimitationItem", "SequenceDelimitationItem", etc, values.
            // Question, should we generate const values for these, and use them internally?
            continue;
        }

        let mut alias = parts[2];
        if alias.starts_with("RETIRED_") {
            alias = alias.trim_start_matches("RETIRED_");
        }
        let alias = alias.to_string();

        let tag = parts[0].to_string();

        let regex_tag = Regex::new(r"^\(([0-9A-F]{4}),([0-9A-F]{4})\)$")?;
        let regex_tag_group100 = Regex::new(r"^\(([0-9A-F]{2})00-[0-9A-F]{2}FF,([0-9A-F]{4})\)$")?;
        let regex_tag_element100 =
            Regex::new(r"^\(([0-9A-F]{4}),([0-9A-F]{2})00-[0-9A-F]{2}FF\)$")?;

        let cap = regex_tag.captures(tag.as_str());
        let tag_type;
        let tag_declaration = if let Some(cap) = cap {
            // single tag
            let group = cap.get(1).expect("capture group 1: group").as_str();
            let elem = cap.get(2).expect("capture group 2: element").as_str();
            tag_type = TagType::Single;
            format!("Tag(0x{}, 0x{})", group, elem)
        } else if let Some(cap) = regex_tag_group100.captures(tag.as_str()) {
            // tag range over groups: (ggxx, eeee)
            let group = cap.get(1).expect("capture group 1: group portion").as_str();
            let elem = cap.get(2).expect("capture group 2: element").as_str();
            tag_type = TagType::Group100;
            format!("Tag(0x{}00, 0x{})", group, elem)
        } else if let Some(cap) = regex_tag_element100.captures(tag.as_str()) {
            // tag range over elements: (gggg, eexx)
            let group = cap.get(1).expect("capture group 1: group").as_str();
            let elem = cap
                .get(2)
                .expect("capture group 2: element portion")
                .as_str();
            tag_type = TagType::Element100;
            format!("Tag(0x{}, 0x{}00)", group, elem)
        } else {
            panic!("invalid tag: {}", alias);
        };

        result.push(Entry {
            tag,
            vr,
            alias,
            vm: parts[3].to_string(),
            obs: parts[4].to_string(),
            is_retired: parts[4].contains("retired"),
            tag_declaration,
            tag_type,
        });
    }

    Ok(result)
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Serialize)]
enum TagType {
    Single,
    Group100,
    Element100,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Serialize)]
struct Entry {
    /// Tag. example: (0010,0010)
    tag: String,
    /// VR. example: PN
    vr: String,
    /// alias. example: PatientName
    alias: String,
    /// VM. example: 1
    vm: String,
    /// observation (usually "DICOM")
    obs: String,
    /// Retired field?
    is_retired: bool,
    /// Tag declaration. Example: "Tag(0x6000, 0x1102)"
    tag_declaration: String,
    /// The type the tag represents
    tag_type: TagType,
}

/// Write the tag dictionary as Rust code.
fn to_code_file<P>(
    dest_path: P,
    entries: Vec<Entry>,
    retired_options: RetiredOptions,
    preamble: &str,
) -> DynResult<()>
where
    P: AsRef<Path>,
{
    if let Some(p_dir) = dest_path.as_ref().parent() {
        create_dir_all(&p_dir)?;
    }
    let mut f = BufWriter::new(File::create(&dest_path)?);

    f.write_all(b"//! Automatically generated. Edit at your own risk.\n")?;

    for line in preamble.split('\n') {
        writeln!(f, "//! {}", line)?;
    }

    if matches!(retired_options, RetiredOptions::Include { deprecate: true }) {
        f.write_all(b"#![allow(deprecated)]\n")?;
    }

    f.write_all(
        b"\n\
    use dicom_core::dictionary::{DictionaryEntryRef, TagRange, TagRange::*};\n\
    use dicom_core::Tag;\n\
    use dicom_core::VR::*;\n\n",
    )?;

    for e in &entries {
        if retired_options == RetiredOptions::Ignore && e.is_retired {
            continue;
        }

        writeln!(f, "/// {} {} {} {} {}", e.alias, e.tag, e.vr, e.vm, e.obs)?;

        let tag_type = match e.tag_type {
            TagType::Single => "Tag",
            _ => "TagRange",
        };

        let tag_set = match e.tag_type {
            TagType::Single => e.tag_declaration.clone(),
            TagType::Group100 => format!("Group100({})", e.tag_declaration),
            TagType::Element100 => format!("Element100({})", e.tag_declaration),
        };

        if e.is_retired
            && matches!(
                retired_options,
                RetiredOptions::Include {
                    deprecate: true,
                    ..
                }
            )
        {
            writeln!(f, "#[deprecated(note = \"Retired DICOM tag\")]")?;
        }

        writeln!(
            f,
            "#[rustfmt::skip]\npub const {}: {} = {};",
            e.alias.to_shouty_snake_case(),
            tag_type,
            tag_set,
        )?;
    }

    f.write_all(
        b"\n\n\
    type E = DictionaryEntryRef<'static>;\n\n\
    #[rustfmt::skip]\n\
    pub(crate) const ENTRIES: &[E] = &[\n",
    )?;
    for e in &entries {
        if retired_options == RetiredOptions::Ignore && e.is_retired {
            continue;
        }

        let (vr1, vr2) = e.vr.split_at(2);

        let second_vr = if vr2.is_empty() {
            format!(" /*{} */", vr2)
        } else {
            vr2.to_string()
        };

        let tag_set = match e.tag_type {
            TagType::Single => format!("Single({})", e.alias.to_shouty_snake_case()),
            _ => e.alias.to_shouty_snake_case(),
        };

        writeln!(
            f,
            "    E {{ tag: {}, alias: \"{}\", vr: {}{} }}, // {}",
            tag_set, e.alias, vr1, second_vr, e.obs
        )?;
    }
    f.write_all(b"];\n")?;

    Ok(())
}
<commit_msg>[dictionary-builder] Update comment links in generated tags.rs<commit_after>//! A simple application that downloads the data dictionary and creates code or
//! data to reproduce it in the core library.
//!
//! ### How to use
//!
//! Simply run the application. It will automatically retrieve the dictionary
//! from the DCMTK data dictionary and store the result in "tags.rs".
//! Future versions will enable different kinds of outputs.
//!
//! Please use the `--help` flag for the full usage information.

use clap::{App, Arg};
use regex::Regex;
use serde::Serialize;

use heck::ShoutySnakeCase;
use std::io::{BufRead, BufReader, Write};
use std::path::Path;
use std::{
    fs::{create_dir_all, File},
    io::BufWriter,
};

/// url to DCMTK dic file
const DEFAULT_LOCATION: &str =
    "https://raw.githubusercontent.com/DCMTK/dcmtk/master/dcmdata/data/dicom.dic";

#[derive(Debug, Copy, Clone, PartialEq)]
enum RetiredOptions {
    /// ignore retired data attributes
    Ignore,
    /// include retired data attributes
    Include {
        /// mark constants as deprecated
        deprecate: bool,
    },
}

fn main() {
    let matches = App::new("DICOM Dictionary Builder")
        .version("0.1.0")
        .arg(
            Arg::with_name("FROM")
                .default_value(DEFAULT_LOCATION)
                .help("Where to fetch the dictionary from"),
        )
        .arg(
            Arg::with_name("no-retired")
                .long("no-retired")
                .help("Whether to ignore retired tags")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("deprecate-retired")
                .long("deprecate-retired")
                .help("Whether to mark tag constants as deprecated")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("OUTPUT")
                .short("o")
                .help("The path to the output file")
                .default_value("tags.rs")
                .takes_value(true),
        )
        .get_matches();

    let ignore_retired = matches.is_present("no-retired");

    let retired = if ignore_retired {
        RetiredOptions::Ignore
    } else {
        RetiredOptions::Include {
            deprecate: matches.is_present("deprecate-retired"),
        }
    };

    let src = matches.value_of("FROM").unwrap();

    let dst = Path::new(matches.value_of("OUTPUT").unwrap());

    if src.starts_with("http:") || src.starts_with("https:") {
        // read from URL
        println!("Downloading DICOM dictionary ...");
        let mut resp = reqwest::blocking::get(src).unwrap();
        let mut data = vec![];
        resp.copy_to(&mut data).unwrap();

        let preamble = data
            .split(|&b| b == b'\n')
            .filter_map(|l| std::str::from_utf8(l).ok())
            .find(|l| l.contains("Copyright"))
            .unwrap_or("");
        let preamble = format!(
            "Adapted from the DCMTK project.\nURL: <{}>\nLicense: <{}>\n{}",
            src, "https://github.com/DCMTK/dcmtk/blob/master/COPYRIGHT", preamble,
        );

        let entries = parse_entries(&*data).unwrap();
        println!("Writing to file ...");
        to_code_file(dst, entries, retired, &preamble).expect("Failed to write file");
    } else {
        // read from File
        let file = File::open(src).unwrap();
        let entries = parse_entries(BufReader::new(file)).unwrap();
        println!("Writing to file ...");
        to_code_file(dst, entries, retired, "").expect("Failed to write file");
    }
}

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

fn parse_entries<R: BufRead>(source: R) -> DynResult<Vec<Entry>> {
    let mut result = vec![];

    for line in source.lines() {
        let line = line?;
        if line.starts_with('#') {
            continue;
        }

        // (0010,0010)	PN	PatientName	1	DICOM
        let parts: Vec<&str> = line.split('\t').collect();

        if parts[4] == "ILLEGAL" || parts[4] == "PRIVATE" || parts[4] == "GENERIC" {
            continue;
        }

        let mut vr = parts[1].to_string();

        // Some fields are dependent upon context.
        // We may want to support this at some point, but for now,
        // let's just choose some good defaults.
        if vr == "up" {
            vr = "UL".to_string();
        }
        if vr == "xs" {
            vr = "US".to_string();
        }
        if vr == "ox" {
            vr = "OB".to_string();
        }
        if vr == "px" {
            vr = "OB".to_string();
        }
        if vr == "lt" {
            vr = "OW".to_string();
        }
        if vr == "na" {
            // These are the "Item", "ItemDelimitationItem", "SequenceDelimitationItem", etc, values.
            // Question, should we generate const values for these, and use them internally?
            continue;
        }

        let mut alias = parts[2];
        if alias.starts_with("RETIRED_") {
            alias = alias.trim_start_matches("RETIRED_");
        }
        let alias = alias.to_string();

        let tag = parts[0].to_string();

        let regex_tag = Regex::new(r"^\(([0-9A-F]{4}),([0-9A-F]{4})\)$")?;
        let regex_tag_group100 = Regex::new(r"^\(([0-9A-F]{2})00-[0-9A-F]{2}FF,([0-9A-F]{4})\)$")?;
        let regex_tag_element100 =
            Regex::new(r"^\(([0-9A-F]{4}),([0-9A-F]{2})00-[0-9A-F]{2}FF\)$")?;

        let cap = regex_tag.captures(tag.as_str());
        let tag_type;
        let tag_declaration = if let Some(cap) = cap {
            // single tag
            let group = cap.get(1).expect("capture group 1: group").as_str();
            let elem = cap.get(2).expect("capture group 2: element").as_str();
            tag_type = TagType::Single;
            format!("Tag(0x{}, 0x{})", group, elem)
        } else if let Some(cap) = regex_tag_group100.captures(tag.as_str()) {
            // tag range over groups: (ggxx, eeee)
            let group = cap.get(1).expect("capture group 1: group portion").as_str();
            let elem = cap.get(2).expect("capture group 2: element").as_str();
            tag_type = TagType::Group100;
            format!("Tag(0x{}00, 0x{})", group, elem)
        } else if let Some(cap) = regex_tag_element100.captures(tag.as_str()) {
            // tag range over elements: (gggg, eexx)
            let group = cap.get(1).expect("capture group 1: group").as_str();
            let elem = cap
                .get(2)
                .expect("capture group 2: element portion")
                .as_str();
            tag_type = TagType::Element100;
            format!("Tag(0x{}, 0x{}00)", group, elem)
        } else {
            panic!("invalid tag: {}", alias);
        };

        result.push(Entry {
            tag,
            vr,
            alias,
            vm: parts[3].to_string(),
            obs: parts[4].to_string(),
            is_retired: parts[4].contains("retired"),
            tag_declaration,
            tag_type,
        });
    }

    Ok(result)
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Serialize)]
enum TagType {
    Single,
    Group100,
    Element100,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Serialize)]
struct Entry {
    /// Tag. example: (0010,0010)
    tag: String,
    /// VR. example: PN
    vr: String,
    /// alias. example: PatientName
    alias: String,
    /// VM. example: 1
    vm: String,
    /// observation (usually "DICOM")
    obs: String,
    /// Retired field?
    is_retired: bool,
    /// Tag declaration. Example: "Tag(0x6000, 0x1102)"
    tag_declaration: String,
    /// The type the tag represents
    tag_type: TagType,
}

/// Write the tag dictionary as Rust code.
fn to_code_file<P>(
    dest_path: P,
    entries: Vec<Entry>,
    retired_options: RetiredOptions,
    preamble: &str,
) -> DynResult<()>
where
    P: AsRef<Path>,
{
    if let Some(p_dir) = dest_path.as_ref().parent() {
        create_dir_all(&p_dir)?;
    }
    let mut f = BufWriter::new(File::create(&dest_path)?);

    f.write_all(b"//! Automatically generated. Edit at your own risk.\n")?;

    for line in preamble.split('\n') {
        writeln!(f, "//! {}", line)?;
    }

    if matches!(retired_options, RetiredOptions::Include { deprecate: true }) {
        f.write_all(b"#![allow(deprecated)]\n")?;
    }

    f.write_all(
        b"\n\
    use dicom_core::dictionary::{DictionaryEntryRef, TagRange, TagRange::*};\n\
    use dicom_core::Tag;\n\
    use dicom_core::VR::*;\n\n",
    )?;

    for e in &entries {
        if retired_options == RetiredOptions::Ignore && e.is_retired {
            continue;
        }

        writeln!(f, "/// {} {} {} {} {}", e.alias, e.tag, e.vr, e.vm, e.obs)?;

        let tag_type = match e.tag_type {
            TagType::Single => "Tag",
            _ => "TagRange",
        };

        let tag_set = match e.tag_type {
            TagType::Single => e.tag_declaration.clone(),
            TagType::Group100 => format!("Group100({})", e.tag_declaration),
            TagType::Element100 => format!("Element100({})", e.tag_declaration),
        };

        if e.is_retired
            && matches!(
                retired_options,
                RetiredOptions::Include {
                    deprecate: true,
                    ..
                }
            )
        {
            writeln!(f, "#[deprecated(note = \"Retired DICOM tag\")]")?;
        }

        writeln!(
            f,
            "#[rustfmt::skip]\npub const {}: {} = {};",
            e.alias.to_shouty_snake_case(),
            tag_type,
            tag_set,
        )?;
    }

    f.write_all(
        b"\n\n\
    type E = DictionaryEntryRef<'static>;\n\n\
    #[rustfmt::skip]\n\
    pub(crate) const ENTRIES: &[E] = &[\n",
    )?;
    for e in &entries {
        if retired_options == RetiredOptions::Ignore && e.is_retired {
            continue;
        }

        let (vr1, vr2) = e.vr.split_at(2);

        let second_vr = if vr2.is_empty() {
            format!(" /*{} */", vr2)
        } else {
            vr2.to_string()
        };

        let tag_set = match e.tag_type {
            TagType::Single => format!("Single({})", e.alias.to_shouty_snake_case()),
            _ => e.alias.to_shouty_snake_case(),
        };

        writeln!(
            f,
            "    E {{ tag: {}, alias: \"{}\", vr: {}{} }}, // {}",
            tag_set, e.alias, vr1, second_vr, e.obs
        )?;
    }
    f.write_all(b"];\n")?;

    Ok(())
}
<|endoftext|>