<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

pub type Float = f64;
pub type Integer = i64;

pub mod specified {
    use std::ascii::StrAsciiExt;
    use cssparser::*;
    use super::{Integer, Float};
    pub use CSSColor = cssparser::Color;

    pub enum Length {
        Au(Integer),  // application units
        Em(Float),
        Ex(Float),
        // XXX uncomment when supported:
//        Ch(Float),
//        Rem(Float),
//        Vw(Float),
//        Vh(Float),
//        Vmin(Float),
//        Vmax(Float),
    }
    static AU_PER_PX: Float = 60.;
    static AU_PER_IN: Float = AU_PER_PX * 96.;
    static AU_PER_CM: Float = AU_PER_IN / 2.54;
    static AU_PER_MM: Float = AU_PER_IN / 25.4;
    static AU_PER_PT: Float = AU_PER_IN / 72.;
    static AU_PER_PC: Float = AU_PER_PT * 12.;
    impl Length {
        #[inline]
        fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Option<Length> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()),
                &Number(ref value) if value.value == 0. =>  Some(Au(0)),
                _ => None
            }
        }
        pub fn parse(input: &ComponentValue) -> Option<Length> {
            Length::parse_internal(input, /* negative_ok = */ true)
        }
        pub fn parse_non_negative(input: &ComponentValue) -> Option<Length> {
            Length::parse_internal(input, /* negative_ok = */ false)
        }
        pub fn parse_dimension(value: Float, unit: &str) -> Option<Length> {
            match unit.to_ascii_lower().as_slice() {
                "px" => Some(Length::from_px(value)),
                "in" => Some(Au((value * AU_PER_IN) as Integer)),
                "cm" => Some(Au((value * AU_PER_CM) as Integer)),
                "mm" => Some(Au((value * AU_PER_MM) as Integer)),
                "pt" => Some(Au((value * AU_PER_PT) as Integer)),
                "pc" => Some(Au((value * AU_PER_PC) as Integer)),
                "em" => Some(Em(value)),
                "ex" => Some(Ex(value)),
                _ => None
            }
        }
        #[inline]
        pub fn from_px(px_value: Float) -> Length {
            Au((px_value * AU_PER_PX) as Integer)
        }
    }

    pub enum LengthOrPercentage {
        LP_Length(Length),
        LP_Percentage(Float),
    }
    impl LengthOrPercentage {
        fn parse_internal(input: &ComponentValue, negative_ok: bool)
                              -> Option<LengthOrPercentage> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()).map_move(LP_Length),
                &ast::Percentage(ref value) if negative_ok || value.value >= 0.
                => Some(LP_Percentage(value.value)),
                &Number(ref value) if value.value == 0. =>  Some(LP_Length(Au(0))),
                _ => None
            }
        }
        #[inline]
        pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentage> {
            LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
        }
        #[inline]
        pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentage> {
            LengthOrPercentage::parse_internal(input, /* negative_ok = */ false)
        }
    }

    pub enum LengthOrPercentageOrAuto {
        LPA_Length(Length),
        LPA_Percentage(Float),
        LPA_Auto,
    }
    impl LengthOrPercentageOrAuto {
        fn parse_internal(input: &ComponentValue, negative_ok: bool)
                     -> Option<LengthOrPercentageOrAuto> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()).map_move(LPA_Length),
                &ast::Percentage(ref value) if negative_ok || value.value >= 0.
                => Some(LPA_Percentage(value.value)),
                &Number(ref value) if value.value == 0. => Some(LPA_Length(Au(0))),
                &Ident(ref value) if value.eq_ignore_ascii_case("auto") => Some(LPA_Auto),
                _ => None
            }
        }
        #[inline]
        pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrAuto> {
            LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ true)
        }
        #[inline]
        pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentageOrAuto> {
            LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ false)
        }
    }
}

pub mod computed {
    use cssparser;
    use super::*;
    use super::super::longhands::font_weight;
    pub struct Context {
        current_color: cssparser::RGBA,
        has_border_top: bool,
        has_border_right: bool,
        has_border_bottom: bool,
        has_border_left: bool,
        font_size: Length,
        font_weight: font_weight::ComputedValue,
        // TODO, as needed: root font size, viewport size, etc.
    }
    pub struct Length(Integer);  // in application units
    impl Length {
        pub fn times(self, factor: Float) -> Length {
            Length(((*self as Float) * factor) as Integer)
        }
    }

    pub fn compute_Length(value: specified::Length, context: &Context) -> Length {
        match value {
            specified::Au(value) => Length(value),
            specified::Em(value) => context.font_size.times(value),
            specified::Ex(value) => {
                let x_height = 0.5;  // TODO: find that from the font
                context.font_size.times(value * x_height)
            },
        }
    }

    pub enum LengthOrPercentage {
        LP_Length(Length),
        LP_Percentage(Float),
    }
    pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context)
                                   -> LengthOrPercentage {
        match value {
            specified::LP_Length(value) => LP_Length(compute_Length(value, context)),
            specified::LP_Percentage(value) => LP_Percentage(value),
        }
    }

    pub enum LengthOrPercentageOrAuto {
        LPA_Length(Length),
        LPA_Percentage(Float),
        LPA_Auto,
    }
    pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto,
                                            context: &Context) -> LengthOrPercentageOrAuto {
        match value {
            specified::LPA_Length(value) => LPA_Length(compute_Length(value, context)),
            specified::LPA_Percentage(value) => LPA_Percentage(value),
            specified::LPA_Auto => LPA_Auto,
        }
    }

    pub struct CSSColor {
        rgba: cssparser::RGBA,
        is_current_color: bool,  // For inheritance
    }
    pub fn compute_CSSColor(color: specified::CSSColor, context: &Context) -> CSSColor {
        match color {
            cssparser::RGBA(rgba) => CSSColor { rgba: rgba, is_current_color: false },
            cssparser::CurrentColor => CSSColor { rgba: context.current_color,
                                                  is_current_color: true },
        }
    }
}
<commit_msg>Revert early resolving of currentColor.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

pub type Float = f64;
pub type Integer = i64;

pub mod specified {
    use std::ascii::StrAsciiExt;
    use cssparser::*;
    use super::{Integer, Float};
    pub use CSSColor = cssparser::Color;

    pub enum Length {
        Au(Integer),  // application units
        Em(Float),
        Ex(Float),
        // XXX uncomment when supported:
//        Ch(Float),
//        Rem(Float),
//        Vw(Float),
//        Vh(Float),
//        Vmin(Float),
//        Vmax(Float),
    }
    static AU_PER_PX: Float = 60.;
    static AU_PER_IN: Float = AU_PER_PX * 96.;
    static AU_PER_CM: Float = AU_PER_IN / 2.54;
    static AU_PER_MM: Float = AU_PER_IN / 25.4;
    static AU_PER_PT: Float = AU_PER_IN / 72.;
    static AU_PER_PC: Float = AU_PER_PT * 12.;
    impl Length {
        #[inline]
        fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Option<Length> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()),
                &Number(ref value) if value.value == 0. =>  Some(Au(0)),
                _ => None
            }
        }
        pub fn parse(input: &ComponentValue) -> Option<Length> {
            Length::parse_internal(input, /* negative_ok = */ true)
        }
        pub fn parse_non_negative(input: &ComponentValue) -> Option<Length> {
            Length::parse_internal(input, /* negative_ok = */ false)
        }
        pub fn parse_dimension(value: Float, unit: &str) -> Option<Length> {
            match unit.to_ascii_lower().as_slice() {
                "px" => Some(Length::from_px(value)),
                "in" => Some(Au((value * AU_PER_IN) as Integer)),
                "cm" => Some(Au((value * AU_PER_CM) as Integer)),
                "mm" => Some(Au((value * AU_PER_MM) as Integer)),
                "pt" => Some(Au((value * AU_PER_PT) as Integer)),
                "pc" => Some(Au((value * AU_PER_PC) as Integer)),
                "em" => Some(Em(value)),
                "ex" => Some(Ex(value)),
                _ => None
            }
        }
        #[inline]
        pub fn from_px(px_value: Float) -> Length {
            Au((px_value * AU_PER_PX) as Integer)
        }
    }

    pub enum LengthOrPercentage {
        LP_Length(Length),
        LP_Percentage(Float),
    }
    impl LengthOrPercentage {
        fn parse_internal(input: &ComponentValue, negative_ok: bool)
                              -> Option<LengthOrPercentage> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()).map_move(LP_Length),
                &ast::Percentage(ref value) if negative_ok || value.value >= 0.
                => Some(LP_Percentage(value.value)),
                &Number(ref value) if value.value == 0. =>  Some(LP_Length(Au(0))),
                _ => None
            }
        }
        #[inline]
        pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentage> {
            LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
        }
        #[inline]
        pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentage> {
            LengthOrPercentage::parse_internal(input, /* negative_ok = */ false)
        }
    }

    pub enum LengthOrPercentageOrAuto {
        LPA_Length(Length),
        LPA_Percentage(Float),
        LPA_Auto,
    }
    impl LengthOrPercentageOrAuto {
        fn parse_internal(input: &ComponentValue, negative_ok: bool)
                     -> Option<LengthOrPercentageOrAuto> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()).map_move(LPA_Length),
                &ast::Percentage(ref value) if negative_ok || value.value >= 0.
                => Some(LPA_Percentage(value.value)),
                &Number(ref value) if value.value == 0. => Some(LPA_Length(Au(0))),
                &Ident(ref value) if value.eq_ignore_ascii_case("auto") => Some(LPA_Auto),
                _ => None
            }
        }
        #[inline]
        pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrAuto> {
            LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ true)
        }
        #[inline]
        pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentageOrAuto> {
            LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ false)
        }
    }
}

pub mod computed {
    use cssparser;
    pub use CSSColor = cssparser::Color;
    pub use compute_CSSColor = std::util::id;
    use super::*;
    use super::super::longhands::font_weight;
    pub struct Context {
        current_color: cssparser::RGBA,
        has_border_top: bool,
        has_border_right: bool,
        has_border_bottom: bool,
        has_border_left: bool,
        font_size: Length,
        font_weight: font_weight::ComputedValue,
        // TODO, as needed: root font size, viewport size, etc.
    }
    pub struct Length(Integer);  // in application units
    impl Length {
        pub fn times(self, factor: Float) -> Length {
            Length(((*self as Float) * factor) as Integer)
        }
    }

    pub fn compute_Length(value: specified::Length, context: &Context) -> Length {
        match value {
            specified::Au(value) => Length(value),
            specified::Em(value) => context.font_size.times(value),
            specified::Ex(value) => {
                let x_height = 0.5;  // TODO: find that from the font
                context.font_size.times(value * x_height)
            },
        }
    }

    pub enum LengthOrPercentage {
        LP_Length(Length),
        LP_Percentage(Float),
    }
    pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context)
                                   -> LengthOrPercentage {
        match value {
            specified::LP_Length(value) => LP_Length(compute_Length(value, context)),
            specified::LP_Percentage(value) => LP_Percentage(value),
        }
    }

    pub enum LengthOrPercentageOrAuto {
        LPA_Length(Length),
        LPA_Percentage(Float),
        LPA_Auto,
    }
    pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto,
                                            context: &Context) -> LengthOrPercentageOrAuto {
        match value {
            specified::LPA_Length(value) => LPA_Length(compute_Length(value, context)),
            specified::LPA_Percentage(value) => LPA_Percentage(value),
            specified::LPA_Auto => LPA_Auto,
        }
    }
}
<|endoftext|>


<commit_before>//! # Synchronizing Widgets
//!
//! You can use signals in order to synchronize the values of widgets. In this example a spin
//! button and a horizontal scale will get interlocked.

extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::Builder;
use gtk::prelude::*;

use std::env::args;

fn build_ui(application: &gtk::Application) {
    let glade_src = include_str!("sync_widgets.glade");
    let builder = Builder::new();
    builder.add_from_string(glade_src).expect("Couldn't add from string");

    let slider: gtk::Scale = builder.get_object("slider").expect("Couldn't get slider");
    let spin_button: gtk::SpinButton = builder.get_object("spin_button")
                                              .expect("Couldn't get spin_button");
    let slider_adj = slider.get_adjustment();
    spin_button.get_adjustment().connect_value_changed(move |adj| {
        slider_adj.set_value(adj.get_value());
    });
    let spin_button_adj = spin_button.get_adjustment();
    slider.get_adjustment().connect_value_changed(move |adj| {
        spin_button_adj.set_value(adj.get_value());
    });

    let window: gtk::ApplicationWindow = builder.get_object("window").expect("Couldn't get window");
    window.set_application(application);
    window.connect_delete_event(move |win, _| {
        win.destroy();
        Inhibit(false)
    });

    window.show_all();
}

fn main() {
    let application = gtk::Application::new("com.github.sync_widgets",
                                            gio::ApplicationFlags::empty())
                                       .expect("Initialization failed...");

    application.connect_startup(move |app| {
        build_ui(app);
    });
    application.connect_activate(|_| {});

    application.run(&args().collect::<Vec<_>>());
}
<commit_msg>Use property bindings instead of signals in the sync_widgets example<commit_after>//! # Synchronizing Widgets
//!
//! You can use property bindings in order to synchronize the values of widgets. In this example a
//! spin button and a horizontal scale will get interlocked.

extern crate glib;
extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::Builder;
use gtk::prelude::*;

use std::env::args;

fn build_ui(application: &gtk::Application) {
    let glade_src = include_str!("sync_widgets.glade");
    let builder = Builder::new();
    builder.add_from_string(glade_src).expect("Couldn't add from string");

    let slider: gtk::Scale = builder.get_object("slider").expect("Couldn't get slider");
    let spin_button: gtk::SpinButton = builder.get_object("spin_button")
                                              .expect("Couldn't get spin_button");
    let slider_adj = slider.get_adjustment();
    let spin_button_adj = spin_button.get_adjustment();
    slider_adj.bind_property("value", &spin_button_adj, "value")
        .flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE | glib::BindingFlags::BIDIRECTIONAL)
        .build();

    let window: gtk::ApplicationWindow = builder.get_object("window").expect("Couldn't get window");
    window.set_application(application);
    window.connect_delete_event(move |win, _| {
        win.destroy();
        Inhibit(false)
    });

    window.show_all();
}

fn main() {
    let application = gtk::Application::new("com.github.sync_widgets",
                                            gio::ApplicationFlags::empty())
                                       .expect("Initialization failed...");

    application.connect_startup(move |app| {
        build_ui(app);
    });
    application.connect_activate(|_| {});

    application.run(&args().collect::<Vec<_>>());
}
<|endoftext|>


<commit_before>

use num::traits::Num;
use core::*;
use super::activation::Sigmoid;
use super::fullmesh::FullMeshBlock;
use super::block::BlockData;

    //use super::block;

    //static input_buf: Vec<f32> = Vec::new();

    //  input_buf: &'static [f32] = &'static[1f32, 2f32, 3f32, 4f32, 5f32];
    // output_buf: & mut 'static [f32] = & mut 'static [1f32, 2f32, 3f32, 4f32, 5f32];

    // let input_buf  : Vec<f32> = Vec::new();
    // let mut output_buf  : Vec<f32> = Vec::new();

    #[test]
    fn it_works3() {
        assert_eq!(5, super::block::add_three(2));
    }

    #[test]
    fn create_fullmesh_bloc ()
    {
        unsafe {
        let id = 5;
        // let input_buf  : Vec<f32> = Vec::new();
        // let mut output_buf  : Vec<f32> = Vec::new();

        //static x: &'static [u8] = &[1,2,3];

        // static input_buf: &'static [f32] = &[1f32, 2f32, 3f32, 4f32, 5f32];
        // static mut output_buf: & 'static mut [f32] = & mut [1f32, 2f32, 3f32, 4f32, 5f32];
        static input_buf: &'static [f32] = &[1f32, 2f32, 3f32, 4f32, 5f32];
        static mut output_buf: & 'static mut [f32] = & mut [1f32, 2f32, 3f32, 4f32, 5f32];
        static  weights: & 'static  [f32] = & [0f32; 500];

        //let weights  : Vec<f32> = Vec::new();
        //let block  =  FullMeshBlock::<f32,f32,Sigmoid>::qnew(1 , 5, 2, &weights[..]) ;
        let block  =  FullMeshBlock::<f32,f32,Sigmoid>::new(BlockData::new(id)
                , weights
                , output_buf
                , input_buf
        );

    };

        //process2::<FullMeshBlock> ( block);
        // process::<f32 , f32 , Sigmoid <f32 , Output = f32>> ( block);
        //http://stackoverflow.com/questions/27567849/what-makes-something-a-trait-object

        assert_eq!(5, super::block::add_three(2));
    }

    // we can alias these !
//Neuron<f32, Output=f32>
    // fn process<W : Num, O : Num ,  T : Neuron< W , Output = O>> ( block : Block<W , T , Output = O>)
    // {
    //
    // }

//IoResult<T> type is an alias for the Result<T, IoError> type.
//type Inch = u64;

// redefine type
    // fn process2< T : Block> ( block : T)
    // {
    //     block.process();
    // }

    // struct C;
    //
    // struct B<'b> {
    //     c: &'b C,2
    // struct A<'a> {
    //     b: B<'a>,
    //     c: &'a C
    // }
    //
    // fn main1() {
    //     let c1 = C;
    //     let _ = A::new(&c1);
    // }

//     [Fact]
// public void size_0_is_illegal()
// {
//     Assert.Throws<System.ArgumentException>(() => new FullMeshNeuronProcessingBehaviour(0));
// }
//
// [Fact]
// public void get_vector_with_no_set_illegal()
// {
//     Assert.Throws<System.InvalidOperationException>(() =>
//     {
//         var mesh = new FullMeshNeuronProcessingBehaviour(10);
//         mesh.GetVectorForNeuron(1);
//
//     });
// }
//
//
// [Fact]
// public void get_vector_with_set()
// {
//     Assert.Throws<System.InvalidOperationException>(() =>
//     {
//         var mesh = new FullMeshNeuronProcessingBehaviour(10);
//         mesh.GetVectorForNeuron(1);
//
//     });
// }
//
//
// [Theory
//     , InlineData(new byte[] {1, 2, 3} ,  0 )
//     , InlineData(new byte[] {  }, 0)
//     , InlineData(new byte[] { 6, 7 , 8, 1, 2, 3 }, 0)
//     , InlineData(new byte[] { 0 }, 0)
//     , InlineData(new byte[] { 1,1,1,1,1,1,1,1,1,1,1,1 }, 0)
//
// ]
// public void set_vector_0_offset(byte[] value , uint offset)
// {2
//     SetAndRetrieve(value, (uint) value.Length, offset);
//
// }
//
// [Theory
// , InlineData(new byte[] { 1, 2, 3 }, 3, 0)
// , InlineData(new byte[] { }, 5, 0)
// , InlineData(new byte[] { 6, 7, 8, 1, 2, 3 }, 20, 0)
// ]
// public void set_vector_0_offset_bigger_size(byte[] value, uint size, uint offset)
// {
//
//     SetAndRetrieve(value, size, offset);
//
// }
//
// [Theory
//     , InlineData(new byte[] {1, 2, 3} , 3,  1 )
//     , InlineData(new byte[] {  }, 5 , 2)
//     , InlineData(new byte[] { 6, 7 , 8, 1, 2, 3 },  20 ,3)
//     , InlineData(new byte[] { 0 }, 1, 4)
//     , InlineData(new byte[] { 1,1,1,1,1,1,1,1,1,1,1,1 }, 100, 5)
//
// ]
// public void set_vector_n_offset(byte[] value , uint size , uint offset)
// {
//
//     SetAndRetrieve(value, size,  offset);
//
// }
//
// void SetAndRetrieve(byte[] value, uint initialLength ,  uint offset)
// {
//     var mesh = new FullMeshNeuronProcessingBehaviour(initialLength);
//     mesh.LoadVector(value, offset);
//     var result = mesh.GetVectorForNeuron(1);
//
//     Assert.Equal(value , result);
// }
<commit_msg>add in module tests<commit_after>use num::traits::Num;
use core::*;

use super::activation::Sigmoid;
use super::fullmesh::FullMeshBlock;
use super::block::BlockData;

    //use super::block;

    //static input_buf: Vec<f32> = Vec::new();

    //  input_buf: &'static [f32] = &'static[1f32, 2f32, 3f32, 4f32, 5f32];
    // output_buf: & mut 'static [f32] = & mut 'static [1f32, 2f32, 3f32, 4f32, 5f32];

    // let input_buf  : Vec<f32> = Vec::new();
    // let mut output_buf  : Vec<f32> = Vec::new();

    #[test]
    fn it_works3() {
        assert_eq!(5, super::block::add_three(2));
    }

    #[test]
    fn create_fullmesh_bloc ()
    {
        unsafe {
        let id = 5;
        // let input_buf  : Vec<f32> = Vec::new();
        // let mut output_buf  : Vec<f32> = Vec::new();

        //static x: &'static [u8] = &[1,2,3];

        // static input_buf: &'static [f32] = &[1f32, 2f32, 3f32, 4f32, 5f32];
        // static mut output_buf: & 'static mut [f32] = & mut [1f32, 2f32, 3f32, 4f32, 5f32];
        static input_buf: &'static [f32] = &[1f32, 2f32, 3f32, 4f32, 5f32];
        static mut output_buf: & 'static mut [f32] = & mut [1f32, 2f32, 3f32, 4f32, 5f32];
        static  weights: & 'static  [f32] = & [0f32; 500];

        //let weights  : Vec<f32> = Vec::new();
        //let block  =  FullMeshBlock::<f32,f32,Sigmoid>::qnew(1 , 5, 2, &weights[..]) ;
        let block  =  FullMeshBlock::<f32,f32,Sigmoid>::new(BlockData::new(id)
                , weights
                , output_buf
                , input_buf
        );

    };

        //process2::<FullMeshBlock> ( block);
        // process::<f32 , f32 , Sigmoid <f32 , Output = f32>> ( block);
        //http://stackoverflow.com/questions/27567849/what-makes-something-a-trait-object

        assert_eq!(5, super::block::add_three(2));
    }

    // we can alias these !
//Neuron<f32, Output=f32>
    // fn process<W : Num, O : Num ,  T : Neuron< W , Output = O>> ( block : Block<W , T , Output = O>)
    // {
    //
    // }

//IoResult<T> type is an alias for the Result<T, IoError> type.
//type Inch = u64;

// redefine type
    // fn process2< T : Block> ( block : T)
    // {
    //     block.process();
    // }

    // struct C;
    //
    // struct B<'b> {
    //     c: &'b C,2
    // struct A<'a> {
    //     b: B<'a>,
    //     c: &'a C
    // }
    //
    // fn main1() {
    //     let c1 = C;
    //     let _ = A::new(&c1);
    // }

//     [Fact]
// public void size_0_is_illegal()
// {
//     Assert.Throws<System.ArgumentException>(() => new FullMeshNeuronProcessingBehaviour(0));
// }
//
// [Fact]
// public void get_vector_with_no_set_illegal()
// {
//     Assert.Throws<System.InvalidOperationException>(() =>
//     {
//         var mesh = new FullMeshNeuronProcessingBehaviour(10);
//         mesh.GetVectorForNeuron(1);
//
//     });
// }
//
//
// [Fact]
// public void get_vector_with_set()
// {
//     Assert.Throws<System.InvalidOperationException>(() =>
//     {
//         var mesh = new FullMeshNeuronProcessingBehaviour(10);
//         mesh.GetVectorForNeuron(1);
//
//     });
// }
//
//
// [Theory
//     , InlineData(new byte[] {1, 2, 3} ,  0 )
//     , InlineData(new byte[] {  }, 0)
//     , InlineData(new byte[] { 6, 7 , 8, 1, 2, 3 }, 0)
//     , InlineData(new byte[] { 0 }, 0)
//     , InlineData(new byte[] { 1,1,1,1,1,1,1,1,1,1,1,1 }, 0)
//
// ]
// public void set_vector_0_offset(byte[] value , uint offset)
// {2
//     SetAndRetrieve(value, (uint) value.Length, offset);
//
// }
//
// [Theory
// , InlineData(new byte[] { 1, 2, 3 }, 3, 0)
// , InlineData(new byte[] { }, 5, 0)
// , InlineData(new byte[] { 6, 7, 8, 1, 2, 3 }, 20, 0)
// ]
// public void set_vector_0_offset_bigger_size(byte[] value, uint size, uint offset)
// {
//
//     SetAndRetrieve(value, size, offset);
//
// }
//
// [Theory
//     , InlineData(new byte[] {1, 2, 3} , 3,  1 )
//     , InlineData(new byte[] {  }, 5 , 2)
//     , InlineData(new byte[] { 6, 7 , 8, 1, 2, 3 },  20 ,3)
//     , InlineData(new byte[] { 0 }, 1, 4)
//     , InlineData(new byte[] { 1,1,1,1,1,1,1,1,1,1,1,1 }, 100, 5)
//
// ]
// public void set_vector_n_offset(byte[] value , uint size , uint offset)
// {
//
//     SetAndRetrieve(value, size,  offset);
//
// }
//
// void SetAndRetrieve(byte[] value, uint initialLength ,  uint offset)
// {
//     var mesh = new FullMeshNeuronProcessingBehaviour(initialLength);
//     mesh.LoadVector(value, offset);
//     var result = mesh.GetVectorForNeuron(1);
//
//     Assert.Equal(value , result);
// }
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::account_config::constants::{from_currency_code_string, CORE_CODE_ADDRESS};
use move_core_types::{
    identifier::Identifier,
    language_storage::{ModuleId, StructTag, TypeTag},
};
use once_cell::sync::Lazy;

pub const LBR_NAME: &str = "LBR";
pub const COIN1_NAME: &str = "Coin1";
pub const COIN2_NAME: &str = "Coin2";

pub fn coin1_tag() -> TypeTag {
    TypeTag::Struct(StructTag {
        address: CORE_CODE_ADDRESS,
        module: from_currency_code_string(COIN1_NAME).unwrap(),
        name: from_currency_code_string(COIN1_NAME).unwrap(),
        type_params: vec![],
    })
}

pub fn coin2_tag() -> TypeTag {
    TypeTag::Struct(StructTag {
        address: CORE_CODE_ADDRESS,
        module: from_currency_code_string(COIN2_NAME).unwrap(),
        name: from_currency_code_string(COIN2_NAME).unwrap(),
        type_params: vec![],
    })
}

pub static LBR_MODULE: Lazy<ModuleId> =
    Lazy::new(|| ModuleId::new(CORE_CODE_ADDRESS, Identifier::new(LBR_NAME).unwrap()));
pub static LBR_STRUCT_NAME: Lazy<Identifier> = Lazy::new(|| Identifier::new(LBR_NAME).unwrap());

pub fn lbr_type_tag() -> TypeTag {
    TypeTag::Struct(StructTag {
        address: CORE_CODE_ADDRESS,
        module: from_currency_code_string(LBR_NAME).unwrap(),
        name: from_currency_code_string(LBR_NAME).unwrap(),
        type_params: vec![],
    })
}
<commit_msg>[types] utility function for extracting coin name from a TypeTag<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::account_config::constants::{from_currency_code_string, CORE_CODE_ADDRESS};
use move_core_types::{
    identifier::Identifier,
    language_storage::{ModuleId, StructTag, TypeTag},
};
use once_cell::sync::Lazy;

pub const LBR_NAME: &str = "LBR";
pub const COIN1_NAME: &str = "Coin1";
pub const COIN2_NAME: &str = "Coin2";

pub fn coin1_tag() -> TypeTag {
    TypeTag::Struct(StructTag {
        address: CORE_CODE_ADDRESS,
        module: from_currency_code_string(COIN1_NAME).unwrap(),
        name: from_currency_code_string(COIN1_NAME).unwrap(),
        type_params: vec![],
    })
}

pub fn coin2_tag() -> TypeTag {
    TypeTag::Struct(StructTag {
        address: CORE_CODE_ADDRESS,
        module: from_currency_code_string(COIN2_NAME).unwrap(),
        name: from_currency_code_string(COIN2_NAME).unwrap(),
        type_params: vec![],
    })
}

pub static LBR_MODULE: Lazy<ModuleId> =
    Lazy::new(|| ModuleId::new(CORE_CODE_ADDRESS, Identifier::new(LBR_NAME).unwrap()));
pub static LBR_STRUCT_NAME: Lazy<Identifier> = Lazy::new(|| Identifier::new(LBR_NAME).unwrap());

pub fn lbr_type_tag() -> TypeTag {
    TypeTag::Struct(StructTag {
        address: CORE_CODE_ADDRESS,
        module: from_currency_code_string(LBR_NAME).unwrap(),
        name: from_currency_code_string(LBR_NAME).unwrap(),
        type_params: vec![],
    })
}

/// Return `Some(struct_name)` if `t` is a `StructTag` representing one of the current Libra coin
/// types (LBR, Coin1, Coin2), `None` otherwise.
pub fn coin_name(t: &TypeTag) -> Option<String> {
    match t {
        TypeTag::Struct(StructTag {
            address,
            module,
            name,
            ..
        }) if *address == CORE_CODE_ADDRESS && module == name => {
            let name_str = name.to_string();
            if name_str == LBR_NAME || name_str == COIN1_NAME || name_str == COIN2_NAME {
                Some(name_str)
            } else {
                None
            }
        }
        _ => None,
    }
}

#[test]
fn coin_names() {
    assert!(coin_name(&coin1_tag()).unwrap() == COIN1_NAME);
    assert!(coin_name(&coin2_tag()).unwrap() == COIN2_NAME);
    assert!(coin_name(&lbr_type_tag()).unwrap() == LBR_NAME);

    assert!(coin_name(&TypeTag::U64) == None);
    let bad_name = Identifier::new("NotACoin").unwrap();
    let bad_coin = TypeTag::Struct(StructTag {
        address: CORE_CODE_ADDRESS,
        module: bad_name.clone(),
        name: bad_name,
        type_params: vec![],
    });
    assert!(coin_name(&bad_coin) == None);
}
<|endoftext|>


<commit_before>//! Handling of `preserveAspectRatio` values
//!
//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
//! ```ignore
//! assert_eq!(
//!     AspectRatio::parse("xMidYMid", ()),
//!     Ok(AspectRatio {
//!         defer: false,
//!         align: Some(Align {
//!             x: X(Align1D::Mid),
//!             y: Y(Align1D::Mid),
//!             fit: FitMode::Meet,
//!         }),
//!     })
//! );
//! ```
//!
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

use cssparser::Parser;
use error::*;
use parsers::Parse;
use parsers::ParseError;
use std::ops::Deref;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
    defer: bool,
    align: Option<Align>,
}

impl Default for AspectRatio {
    fn default() -> AspectRatio {
        AspectRatio {
            defer: false,
            align: Some(Align::default()),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum FitMode {
    Meet,
    Slice,
}

impl Default for FitMode {
    fn default() -> FitMode {
        FitMode::Meet
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Align {
    x: X,
    y: Y,
    fit: FitMode,
}

impl Default for Align {
    fn default() -> Align {
        Align {
            x: X(Align1D::Mid),
            y: Y(Align1D::Mid),
            fit: FitMode::default(),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Align1D {
    Min,
    Mid,
    Max,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct X(Align1D);
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Y(Align1D);

impl Deref for X {
    type Target = Align1D;

    fn deref(&self) -> &Align1D {
        &self.0
    }
}

impl Deref for Y {
    type Target = Align1D;

    fn deref(&self) -> &Align1D {
        &self.0
    }
}

impl Align1D {
    fn compute(self, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
        match self {
            Align1D::Min => dest_pos,
            Align1D::Mid => dest_pos + (dest_size - obj_size) / 2.0,
            Align1D::Max => dest_pos + dest_size - obj_size,
        }
    }
}

impl AspectRatio {
    pub fn is_slice(&self) -> bool {
        match self.align {
            Some(Align {
                fit: FitMode::Slice,
                ..
            }) => true,

            _ => false,
        }
    }

    pub fn compute(
        &self,
        object_width: f64,
        object_height: f64,
        dest_x: f64,
        dest_y: f64,
        dest_width: f64,
        dest_height: f64,
    ) -> (f64, f64, f64, f64) {
        match self.align {
            None => (dest_x, dest_y, dest_width, dest_height),

            Some(Align { x, y, fit }) => {
                let w_factor = dest_width / object_width;
                let h_factor = dest_height / object_height;
                let factor = match fit {
                    FitMode::Meet => w_factor.min(h_factor),
                    FitMode::Slice => w_factor.max(h_factor),
                };

                let w = object_width * factor;
                let h = object_height * factor;

                let xpos = x.compute(dest_x, dest_width, w);
                let ypos = y.compute(dest_y, dest_height, h);

                (xpos, ypos, w, h)
            }
        }
    }
}

impl Align {
    fn parse_xy(s: &str) -> Result<Option<(X, Y)>, ValueErrorKind> {
        use self::Align1D::*;

        match s {
            "none" => Ok(None),

            "xMinYMin" => Ok(Some((X(Min), Y(Min)))),
            "xMidYMin" => Ok(Some((X(Mid), Y(Min)))),
            "xMaxYMin" => Ok(Some((X(Max), Y(Min)))),

            "xMinYMid" => Ok(Some((X(Min), Y(Mid)))),
            "xMidYMid" => Ok(Some((X(Mid), Y(Mid)))),
            "xMaxYMid" => Ok(Some((X(Max), Y(Mid)))),

            "xMinYMax" => Ok(Some((X(Min), Y(Max)))),
            "xMidYMax" => Ok(Some((X(Mid), Y(Max)))),
            "xMaxYMax" => Ok(Some((X(Max), Y(Max)))),

            _ => Err(ValueErrorKind::Parse(ParseError::new("invalid alignment"))),
        }
    }
}

impl FitMode {
    fn parse(s: &str) -> Result<FitMode, ValueErrorKind> {
        match s {
            "meet" => Ok(FitMode::Meet),
            "slice" => Ok(FitMode::Slice),
            _ => Err(ValueErrorKind::Parse(ParseError::new("invalid fit mode"))),
        }
    }
}

impl Parse for AspectRatio {
    type Data = ();
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>, _: ()) -> Result<AspectRatio, ValueErrorKind> {
        let defer = parser.try(|p| p.expect_ident_matching("defer")).is_ok();

        let align_xy = parser.try(|p| {
            p.expect_ident()
                .map_err(|_| ValueErrorKind::Parse(ParseError::new("expected identifier")))
                .and_then(|ident| Align::parse_xy(ident))
        })?;

        let fit = parser
            .try(|p| {
                p.expect_ident()
                    .map_err(|_| ValueErrorKind::Parse(ParseError::new("expected identifier")))
                    .and_then(|ident| FitMode::parse(ident))
            }).unwrap_or(FitMode::default());

        parser
            .expect_exhausted()
            .map_err(|_| ValueErrorKind::Parse(ParseError::new("extra data in AspectRatio")))?;

        let align = align_xy.map(|(x, y)| Align { x, y, fit });

        Ok(AspectRatio { defer, align })
    }
}

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

    #[test]
    fn parsing_invalid_strings_yields_error() {
        assert!(AspectRatio::parse_str("", ()).is_err());
        assert!(AspectRatio::parse_str("defer", ()).is_err());
        assert!(AspectRatio::parse_str("defer foo", ()).is_err());
        assert!(AspectRatio::parse_str("defer xmidymid", ()).is_err());
        assert!(AspectRatio::parse_str("defer xMidYMid foo", ()).is_err());
        assert!(AspectRatio::parse_str("xmidymid", ()).is_err());
        assert!(AspectRatio::parse_str("xMidYMid foo", ()).is_err());
        assert!(AspectRatio::parse_str("defer xMidYMid meet foo", ()).is_err());
    }

    #[test]
    fn parses_valid_strings() {
        assert_eq!(
            AspectRatio::parse_str("defer none", ()),
            Ok(AspectRatio {
                defer: true,
                align: None,
            },)
        );

        assert_eq!(
            AspectRatio::parse_str("xMidYMid", ()),
            Ok(AspectRatio {
                defer: false,
                align: Some(Align {
                    x: X(Align1D::Mid),
                    y: Y(Align1D::Mid),
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse_str("defer xMidYMid", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: X(Align1D::Mid),
                    y: Y(Align1D::Mid),
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse_str("defer xMinYMax", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: X(Align1D::Min),
                    y: Y(Align1D::Max),
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse_str("defer xMaxYMid meet", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: X(Align1D::Max),
                    y: Y(Align1D::Mid),
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse_str("defer xMinYMax slice", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: X(Align1D::Min),
                    y: Y(Align1D::Max),
                    fit: FitMode::Slice,
                },),
            },)
        );
    }

    #[test]
    fn aligns() {
        let foo = AspectRatio::parse_str("xMinYMin meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMinYMin slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMinYMid meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMinYMid slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);

        assert_eq!(foo, (0.0, -49.5, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMinYMax meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMinYMax slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -99.0, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMidYMin meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (4.95, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMidYMin slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMidYMid meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (4.95, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMidYMid slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -49.5, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMidYMax meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (4.95, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMidYMax slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -99.0, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMaxYMin meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (9.9, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMaxYMin slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMaxYMid meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (9.9, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMaxYMid slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -49.5, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMaxYMax meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (9.9, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMaxYMax slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -99.0, 10.0, 100.0));
    }
}
<commit_msg>Align::parse_xy() - Take the full ident, not the &str version<commit_after>//! Handling of `preserveAspectRatio` values
//!
//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
//! ```ignore
//! assert_eq!(
//!     AspectRatio::parse("xMidYMid", ()),
//!     Ok(AspectRatio {
//!         defer: false,
//!         align: Some(Align {
//!             x: X(Align1D::Mid),
//!             y: Y(Align1D::Mid),
//!             fit: FitMode::Meet,
//!         }),
//!     })
//! );
//! ```
//!
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

use cssparser::{CowRcStr, Parser};
use error::ValueErrorKind;
use parsers::Parse;
use parsers::ParseError;
use std::ops::Deref;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
    defer: bool,
    align: Option<Align>,
}

impl Default for AspectRatio {
    fn default() -> AspectRatio {
        AspectRatio {
            defer: false,
            align: Some(Align::default()),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum FitMode {
    Meet,
    Slice,
}

impl Default for FitMode {
    fn default() -> FitMode {
        FitMode::Meet
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Align {
    x: X,
    y: Y,
    fit: FitMode,
}

impl Default for Align {
    fn default() -> Align {
        Align {
            x: X(Align1D::Mid),
            y: Y(Align1D::Mid),
            fit: FitMode::default(),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Align1D {
    Min,
    Mid,
    Max,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct X(Align1D);
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Y(Align1D);

impl Deref for X {
    type Target = Align1D;

    fn deref(&self) -> &Align1D {
        &self.0
    }
}

impl Deref for Y {
    type Target = Align1D;

    fn deref(&self) -> &Align1D {
        &self.0
    }
}

impl Align1D {
    fn compute(self, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
        match self {
            Align1D::Min => dest_pos,
            Align1D::Mid => dest_pos + (dest_size - obj_size) / 2.0,
            Align1D::Max => dest_pos + dest_size - obj_size,
        }
    }
}

impl AspectRatio {
    pub fn is_slice(&self) -> bool {
        match self.align {
            Some(Align {
                fit: FitMode::Slice,
                ..
            }) => true,

            _ => false,
        }
    }

    pub fn compute(
        &self,
        object_width: f64,
        object_height: f64,
        dest_x: f64,
        dest_y: f64,
        dest_width: f64,
        dest_height: f64,
    ) -> (f64, f64, f64, f64) {
        match self.align {
            None => (dest_x, dest_y, dest_width, dest_height),

            Some(Align { x, y, fit }) => {
                let w_factor = dest_width / object_width;
                let h_factor = dest_height / object_height;
                let factor = match fit {
                    FitMode::Meet => w_factor.min(h_factor),
                    FitMode::Slice => w_factor.max(h_factor),
                };

                let w = object_width * factor;
                let h = object_height * factor;

                let xpos = x.compute(dest_x, dest_width, w);
                let ypos = y.compute(dest_y, dest_height, h);

                (xpos, ypos, w, h)
            }
        }
    }
}

impl Align {
    fn parse_xy(ident: &CowRcStr) -> Result<Option<(X, Y)>, ValueErrorKind> {
        use self::Align1D::*;

        match ident.as_ref() {
            "none" => Ok(None),

            "xMinYMin" => Ok(Some((X(Min), Y(Min)))),
            "xMidYMin" => Ok(Some((X(Mid), Y(Min)))),
            "xMaxYMin" => Ok(Some((X(Max), Y(Min)))),

            "xMinYMid" => Ok(Some((X(Min), Y(Mid)))),
            "xMidYMid" => Ok(Some((X(Mid), Y(Mid)))),
            "xMaxYMid" => Ok(Some((X(Max), Y(Mid)))),

            "xMinYMax" => Ok(Some((X(Min), Y(Max)))),
            "xMidYMax" => Ok(Some((X(Mid), Y(Max)))),
            "xMaxYMax" => Ok(Some((X(Max), Y(Max)))),

            _ => Err(ValueErrorKind::Parse(ParseError::new("invalid alignment"))),
        }
    }
}

impl FitMode {
    fn parse(s: &str) -> Result<FitMode, ValueErrorKind> {
        match s {
            "meet" => Ok(FitMode::Meet),
            "slice" => Ok(FitMode::Slice),
            _ => Err(ValueErrorKind::Parse(ParseError::new("invalid fit mode"))),
        }
    }
}

impl Parse for AspectRatio {
    type Data = ();
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>, _: ()) -> Result<AspectRatio, ValueErrorKind> {
        let defer = parser.try(|p| p.expect_ident_matching("defer")).is_ok();

        let align_xy = parser.try(|p| {
            p.expect_ident()
                .map_err(|_| ValueErrorKind::Parse(ParseError::new("expected identifier")))
                .and_then(|ident| Align::parse_xy(ident))
        })?;

        let fit = parser
            .try(|p| {
                p.expect_ident()
                    .map_err(|_| ValueErrorKind::Parse(ParseError::new("expected identifier")))
                    .and_then(|ident| FitMode::parse(ident))
            }).unwrap_or(FitMode::default());

        parser
            .expect_exhausted()
            .map_err(|_| ValueErrorKind::Parse(ParseError::new("extra data in AspectRatio")))?;

        let align = align_xy.map(|(x, y)| Align { x, y, fit });

        Ok(AspectRatio { defer, align })
    }
}

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

    #[test]
    fn parsing_invalid_strings_yields_error() {
        assert!(AspectRatio::parse_str("", ()).is_err());
        assert!(AspectRatio::parse_str("defer", ()).is_err());
        assert!(AspectRatio::parse_str("defer foo", ()).is_err());
        assert!(AspectRatio::parse_str("defer xmidymid", ()).is_err());
        assert!(AspectRatio::parse_str("defer xMidYMid foo", ()).is_err());
        assert!(AspectRatio::parse_str("xmidymid", ()).is_err());
        assert!(AspectRatio::parse_str("xMidYMid foo", ()).is_err());
        assert!(AspectRatio::parse_str("defer xMidYMid meet foo", ()).is_err());
    }

    #[test]
    fn parses_valid_strings() {
        assert_eq!(
            AspectRatio::parse_str("defer none", ()),
            Ok(AspectRatio {
                defer: true,
                align: None,
            },)
        );

        assert_eq!(
            AspectRatio::parse_str("xMidYMid", ()),
            Ok(AspectRatio {
                defer: false,
                align: Some(Align {
                    x: X(Align1D::Mid),
                    y: Y(Align1D::Mid),
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse_str("defer xMidYMid", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: X(Align1D::Mid),
                    y: Y(Align1D::Mid),
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse_str("defer xMinYMax", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: X(Align1D::Min),
                    y: Y(Align1D::Max),
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse_str("defer xMaxYMid meet", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: X(Align1D::Max),
                    y: Y(Align1D::Mid),
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse_str("defer xMinYMax slice", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: X(Align1D::Min),
                    y: Y(Align1D::Max),
                    fit: FitMode::Slice,
                },),
            },)
        );
    }

    #[test]
    fn aligns() {
        let foo = AspectRatio::parse_str("xMinYMin meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMinYMin slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMinYMid meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMinYMid slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);

        assert_eq!(foo, (0.0, -49.5, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMinYMax meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMinYMax slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -99.0, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMidYMin meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (4.95, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMidYMin slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMidYMid meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (4.95, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMidYMid slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -49.5, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMidYMax meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (4.95, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMidYMax slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -99.0, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMaxYMin meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (9.9, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMaxYMin slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMaxYMid meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (9.9, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMaxYMid slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -49.5, 10.0, 100.0));

        let foo = AspectRatio::parse_str("xMaxYMax meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (9.9, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse_str("xMaxYMax slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -99.0, 10.0, 100.0));
    }
}
<|endoftext|>


<commit_before>use core::mem;
use syscall::data::IntRegisters;

/// Print to console
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
        use core::fmt::Write;
        let _ = write!($crate::arch::debug::Writer::new(), $($arg)*);
    });
}

/// Print with new line to console
#[macro_export]
macro_rules! println {
    () => (print!("\n"));
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

#[allow(dead_code)]
#[repr(packed)]
pub struct ScratchRegisters {
    pub r11: usize,
    pub r10: usize,
    pub r9: usize,
    pub r8: usize,
    pub rsi: usize,
    pub rdi: usize,
    pub rdx: usize,
    pub rcx: usize,
    pub rax: usize,
}

impl ScratchRegisters {
    pub fn dump(&self) {
        println!("RAX:   {:>016X}", { self.rax });
        println!("RCX:   {:>016X}", { self.rcx });
        println!("RDX:   {:>016X}", { self.rdx });
        println!("RDI:   {:>016X}", { self.rdi });
        println!("RSI:   {:>016X}", { self.rsi });
        println!("R8:    {:>016X}", { self.r8 });
        println!("R9:    {:>016X}", { self.r9 });
        println!("R10:   {:>016X}", { self.r10 });
        println!("R11:   {:>016X}", { self.r11 });
    }
}

macro_rules! scratch_push {
    () => (asm!(
        "push rax
        push rcx
        push rdx
        push rdi
        push rsi
        push r8
        push r9
        push r10
        push r11"
        : : : : "intel", "volatile"
    ));
}

macro_rules! scratch_pop {
    () => (asm!(
        "pop r11
        pop r10
        pop r9
        pop r8
        pop rsi
        pop rdi
        pop rdx
        pop rcx
        pop rax"
        : : : : "intel", "volatile"
    ));
}

#[allow(dead_code)]
#[repr(packed)]
pub struct PreservedRegisters {
    pub r15: usize,
    pub r14: usize,
    pub r13: usize,
    pub r12: usize,
    pub rbp: usize,
    pub rbx: usize,
}

impl PreservedRegisters {
    pub fn dump(&self) {
        println!("RBX:   {:>016X}", { self.rbx });
        println!("RBP:   {:>016X}", { self.rbp });
        println!("R12:   {:>016X}", { self.r12 });
        println!("R13:   {:>016X}", { self.r13 });
        println!("R14:   {:>016X}", { self.r14 });
        println!("R15:   {:>016X}", { self.r15 });
    }
}

macro_rules! preserved_push {
    () => (asm!(
        "push rbx
        push rbp
        push r12
        push r13
        push r14
        push r15"
        : : : : "intel", "volatile"
    ));
}

macro_rules! preserved_pop {
    () => (asm!(
        "pop r15
        pop r14
        pop r13
        pop r12
        pop rbp
        pop rbx"
        : : : : "intel", "volatile"
    ));
}

macro_rules! fs_push {
    () => (asm!(
        "push fs
        mov rax, 0x18
        mov fs, ax"
        : : : : "intel", "volatile"
    ));
}

macro_rules! fs_pop {
    () => (asm!(
        "pop fs"
        : : : : "intel", "volatile"
    ));
}

#[allow(dead_code)]
#[repr(packed)]
pub struct IretRegisters {
    pub rip: usize,
    pub cs: usize,
    pub rflags: usize,
    // Will only be present if interrupt is raised from another
    // privilege ring
    pub rsp: usize,
    pub ss: usize
}

impl IretRegisters {
    pub fn dump(&self) {
        println!("RFLAG: {:>016X}", { self.rflags });
        println!("CS:    {:>016X}", { self.cs });
        println!("RIP:   {:>016X}", { self.rip });
    }
}

macro_rules! iret {
    () => (asm!(
        "iretq"
        : : : : "intel", "volatile"
    ));
}

/// Create an interrupt function that can safely run rust code
#[macro_export]
macro_rules! interrupt {
    ($name:ident, $func:block) => {
        #[naked]
        pub unsafe extern fn $name () {
            #[inline(never)]
            unsafe fn inner() {
                $func
            }

            // Push scratch registers
            scratch_push!();
            fs_push!();

            // Map kernel
            $crate::arch::x86_64::pti::map();

            // Call inner rust function
            inner();

            // Unmap kernel
            $crate::arch::x86_64::pti::unmap();

            // Pop scratch registers and return
            fs_pop!();
            scratch_pop!();
            iret!();
        }
    };
}

#[allow(dead_code)]
#[repr(packed)]
pub struct InterruptStack {
    pub fs: usize,
    pub preserved: PreservedRegisters,
    pub scratch: ScratchRegisters,
    pub iret: IretRegisters,
}

impl InterruptStack {
    pub fn dump(&self) {
        self.iret.dump();
        self.scratch.dump();
        self.preserved.dump();
        println!("FS:    {:>016X}", { self.fs });
    }
    /// Saves all registers to a struct used by the proc:
    /// scheme to read/write registers.
    pub fn save(&self, all: &mut IntRegisters) {
        all.fs = self.fs;

        all.r15 = self.preserved.r15;
        all.r14 = self.preserved.r14;
        all.r13 = self.preserved.r13;
        all.r12 = self.preserved.r12;
        all.rbp = self.preserved.rbp;
        all.rbx = self.preserved.rbx;
        all.r11 = self.scratch.r11;
        all.r10 = self.scratch.r10;
        all.r9 = self.scratch.r9;
        all.r8 = self.scratch.r8;
        all.rsi = self.scratch.rsi;
        all.rdi = self.scratch.rdi;
        all.rdx = self.scratch.rdx;
        all.rcx = self.scratch.rcx;
        all.rax = self.scratch.rax;
        all.rip = self.iret.rip;
        all.cs = self.iret.cs;
        all.rflags = self.iret.rflags;

        // Set rsp and ss:

        const CPL_MASK: usize = 0b11;

        let cs: usize;
        unsafe {
            asm!("mov $0, cs" : "=r"(cs) ::: "intel");
        }

        if self.iret.cs & CPL_MASK == cs & CPL_MASK {
            // Privilege ring didn't change, so neither did the stack
            all.rsp = self as *const Self as usize // rsp after Self was pushed to the stack
                + mem::size_of::<Self>() // disregard Self
                - mem::size_of::<usize>() * 2; // well, almost: rsp and ss need to be excluded as they aren't present
            unsafe {
                asm!("mov $0, ss" : "=r"(all.ss) ::: "intel");
            }
        } else {
            all.rsp = self.iret.rsp;
            all.ss = self.iret.ss;
        }
    }
    /// Loads all registers from a struct used by the proc:
    /// scheme to read/write registers.
    pub fn load(&mut self, all: &IntRegisters) {
        // TODO: Which of these should be allowed to change?

        // self.fs = all.fs;
        self.preserved.r15 = all.r15;
        self.preserved.r14 = all.r14;
        self.preserved.r13 = all.r13;
        self.preserved.r12 = all.r12;
        self.preserved.rbp = all.rbp;
        self.preserved.rbx = all.rbx;
        self.scratch.r11 = all.r11;
        self.scratch.r10 = all.r10;
        self.scratch.r9 = all.r9;
        self.scratch.r8 = all.r8;
        self.scratch.rsi = all.rsi;
        self.scratch.rdi = all.rdi;
        self.scratch.rdx = all.rdx;
        self.scratch.rcx = all.rcx;
        self.scratch.rax = all.rax;
        // self.iret.rip = all.rip;
        // self.iret.cs = all.cs;
        // self.iret.rflags = all.eflags;
    }
    /// Enables the "Trap Flag" in the FLAGS register, causing the CPU
    /// to send a Debug exception after the next instruction. This is
    /// used for singlestep in the proc: scheme.
    pub fn set_singlestep(&mut self, enabled: bool) {
        if enabled {
            self.iret.rflags |= 1 << 8;
        } else {
            self.iret.rflags &= !(1 << 8);
        }
    }
}

#[macro_export]
macro_rules! interrupt_stack {
    ($name:ident, $stack: ident, $func:block) => {
        #[naked]
        pub unsafe extern fn $name () {
            #[inline(never)]
            unsafe fn inner($stack: &mut $crate::arch::x86_64::macros::InterruptStack) {
                $func
            }

            // Push scratch registers
            scratch_push!();
            preserved_push!();
            fs_push!();

            // Get reference to stack variables
            let rsp: usize;
            asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");

            // Map kernel
            $crate::arch::x86_64::pti::map();

            // Call inner rust function
            inner(&mut *(rsp as *mut $crate::arch::x86_64::macros::InterruptStack));

            // Unmap kernel
            $crate::arch::x86_64::pti::unmap();

            // Pop scratch registers and return
            fs_pop!();
            preserved_pop!();
            scratch_pop!();
            iret!();
        }
    };
}

#[allow(dead_code)]
#[repr(packed)]
pub struct InterruptErrorStack {
    pub fs: usize,
    pub preserved: PreservedRegisters,
    pub scratch: ScratchRegisters,
    pub code: usize,
    pub iret: IretRegisters,
}

impl InterruptErrorStack {
    pub fn dump(&self) {
        self.iret.dump();
        println!("CODE:  {:>016X}", { self.code });
        self.scratch.dump();
        self.preserved.dump();
        println!("FS:    {:>016X}", { self.fs });
    }
}

#[macro_export]
macro_rules! interrupt_error {
    ($name:ident, $stack:ident, $func:block) => {
        #[naked]
        pub unsafe extern fn $name () {
            #[inline(never)]
            unsafe fn inner($stack: &$crate::arch::x86_64::macros::InterruptErrorStack) {
                $func
            }

            // Push scratch registers
            scratch_push!();
            preserved_push!();
            fs_push!();

            // Get reference to stack variables
            let rsp: usize;
            asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");

            // Map kernel
            $crate::arch::x86_64::pti::map();

            // Call inner rust function
            inner(&*(rsp as *const $crate::arch::x86_64::macros::InterruptErrorStack));

            // Unmap kernel
            $crate::arch::x86_64::pti::unmap();

            // Pop scratch registers, error code, and return
            fs_pop!();
            preserved_pop!();
            scratch_pop!();
            asm!("add rsp, 8" : : : : "intel", "volatile");
            iret!();
        }
    };
}
<commit_msg>WIP(ptrace): Allow setting RIP<commit_after>use core::mem;
use syscall::data::IntRegisters;

/// Print to console
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
        use core::fmt::Write;
        let _ = write!($crate::arch::debug::Writer::new(), $($arg)*);
    });
}

/// Print with new line to console
#[macro_export]
macro_rules! println {
    () => (print!("\n"));
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

#[allow(dead_code)]
#[repr(packed)]
pub struct ScratchRegisters {
    pub r11: usize,
    pub r10: usize,
    pub r9: usize,
    pub r8: usize,
    pub rsi: usize,
    pub rdi: usize,
    pub rdx: usize,
    pub rcx: usize,
    pub rax: usize,
}

impl ScratchRegisters {
    pub fn dump(&self) {
        println!("RAX:   {:>016X}", { self.rax });
        println!("RCX:   {:>016X}", { self.rcx });
        println!("RDX:   {:>016X}", { self.rdx });
        println!("RDI:   {:>016X}", { self.rdi });
        println!("RSI:   {:>016X}", { self.rsi });
        println!("R8:    {:>016X}", { self.r8 });
        println!("R9:    {:>016X}", { self.r9 });
        println!("R10:   {:>016X}", { self.r10 });
        println!("R11:   {:>016X}", { self.r11 });
    }
}

macro_rules! scratch_push {
    () => (asm!(
        "push rax
        push rcx
        push rdx
        push rdi
        push rsi
        push r8
        push r9
        push r10
        push r11"
        : : : : "intel", "volatile"
    ));
}

macro_rules! scratch_pop {
    () => (asm!(
        "pop r11
        pop r10
        pop r9
        pop r8
        pop rsi
        pop rdi
        pop rdx
        pop rcx
        pop rax"
        : : : : "intel", "volatile"
    ));
}

#[allow(dead_code)]
#[repr(packed)]
pub struct PreservedRegisters {
    pub r15: usize,
    pub r14: usize,
    pub r13: usize,
    pub r12: usize,
    pub rbp: usize,
    pub rbx: usize,
}

impl PreservedRegisters {
    pub fn dump(&self) {
        println!("RBX:   {:>016X}", { self.rbx });
        println!("RBP:   {:>016X}", { self.rbp });
        println!("R12:   {:>016X}", { self.r12 });
        println!("R13:   {:>016X}", { self.r13 });
        println!("R14:   {:>016X}", { self.r14 });
        println!("R15:   {:>016X}", { self.r15 });
    }
}

macro_rules! preserved_push {
    () => (asm!(
        "push rbx
        push rbp
        push r12
        push r13
        push r14
        push r15"
        : : : : "intel", "volatile"
    ));
}

macro_rules! preserved_pop {
    () => (asm!(
        "pop r15
        pop r14
        pop r13
        pop r12
        pop rbp
        pop rbx"
        : : : : "intel", "volatile"
    ));
}

macro_rules! fs_push {
    () => (asm!(
        "push fs
        mov rax, 0x18
        mov fs, ax"
        : : : : "intel", "volatile"
    ));
}

macro_rules! fs_pop {
    () => (asm!(
        "pop fs"
        : : : : "intel", "volatile"
    ));
}

#[allow(dead_code)]
#[repr(packed)]
pub struct IretRegisters {
    pub rip: usize,
    pub cs: usize,
    pub rflags: usize,
    // Will only be present if interrupt is raised from another
    // privilege ring
    pub rsp: usize,
    pub ss: usize
}

impl IretRegisters {
    pub fn dump(&self) {
        println!("RFLAG: {:>016X}", { self.rflags });
        println!("CS:    {:>016X}", { self.cs });
        println!("RIP:   {:>016X}", { self.rip });
    }
}

macro_rules! iret {
    () => (asm!(
        "iretq"
        : : : : "intel", "volatile"
    ));
}

/// Create an interrupt function that can safely run rust code
#[macro_export]
macro_rules! interrupt {
    ($name:ident, $func:block) => {
        #[naked]
        pub unsafe extern fn $name () {
            #[inline(never)]
            unsafe fn inner() {
                $func
            }

            // Push scratch registers
            scratch_push!();
            fs_push!();

            // Map kernel
            $crate::arch::x86_64::pti::map();

            // Call inner rust function
            inner();

            // Unmap kernel
            $crate::arch::x86_64::pti::unmap();

            // Pop scratch registers and return
            fs_pop!();
            scratch_pop!();
            iret!();
        }
    };
}

#[allow(dead_code)]
#[repr(packed)]
pub struct InterruptStack {
    pub fs: usize,
    pub preserved: PreservedRegisters,
    pub scratch: ScratchRegisters,
    pub iret: IretRegisters,
}

impl InterruptStack {
    pub fn dump(&self) {
        self.iret.dump();
        self.scratch.dump();
        self.preserved.dump();
        println!("FS:    {:>016X}", { self.fs });
    }
    /// Saves all registers to a struct used by the proc:
    /// scheme to read/write registers.
    pub fn save(&self, all: &mut IntRegisters) {
        all.fs = self.fs;

        all.r15 = self.preserved.r15;
        all.r14 = self.preserved.r14;
        all.r13 = self.preserved.r13;
        all.r12 = self.preserved.r12;
        all.rbp = self.preserved.rbp;
        all.rbx = self.preserved.rbx;
        all.r11 = self.scratch.r11;
        all.r10 = self.scratch.r10;
        all.r9 = self.scratch.r9;
        all.r8 = self.scratch.r8;
        all.rsi = self.scratch.rsi;
        all.rdi = self.scratch.rdi;
        all.rdx = self.scratch.rdx;
        all.rcx = self.scratch.rcx;
        all.rax = self.scratch.rax;
        all.rip = self.iret.rip;
        all.cs = self.iret.cs;
        all.rflags = self.iret.rflags;

        // Set rsp and ss:

        const CPL_MASK: usize = 0b11;

        let cs: usize;
        unsafe {
            asm!("mov $0, cs" : "=r"(cs) ::: "intel");
        }

        if self.iret.cs & CPL_MASK == cs & CPL_MASK {
            // Privilege ring didn't change, so neither did the stack
            all.rsp = self as *const Self as usize // rsp after Self was pushed to the stack
                + mem::size_of::<Self>() // disregard Self
                - mem::size_of::<usize>() * 2; // well, almost: rsp and ss need to be excluded as they aren't present
            unsafe {
                asm!("mov $0, ss" : "=r"(all.ss) ::: "intel");
            }
        } else {
            all.rsp = self.iret.rsp;
            all.ss = self.iret.ss;
        }
    }
    /// Loads all registers from a struct used by the proc:
    /// scheme to read/write registers.
    pub fn load(&mut self, all: &IntRegisters) {
        // TODO: Which of these should be allowed to change?

        // self.fs = all.fs;
        self.preserved.r15 = all.r15;
        self.preserved.r14 = all.r14;
        self.preserved.r13 = all.r13;
        self.preserved.r12 = all.r12;
        self.preserved.rbp = all.rbp;
        self.preserved.rbx = all.rbx;
        self.scratch.r11 = all.r11;
        self.scratch.r10 = all.r10;
        self.scratch.r9 = all.r9;
        self.scratch.r8 = all.r8;
        self.scratch.rsi = all.rsi;
        self.scratch.rdi = all.rdi;
        self.scratch.rdx = all.rdx;
        self.scratch.rcx = all.rcx;
        self.scratch.rax = all.rax;
        self.iret.rip = all.rip;
        self.iret.cs = all.cs;
        // self.iret.rflags = all.eflags;
    }
    /// Enables the "Trap Flag" in the FLAGS register, causing the CPU
    /// to send a Debug exception after the next instruction. This is
    /// used for singlestep in the proc: scheme.
    pub fn set_singlestep(&mut self, enabled: bool) {
        if enabled {
            self.iret.rflags |= 1 << 8;
        } else {
            self.iret.rflags &= !(1 << 8);
        }
    }
}

#[macro_export]
macro_rules! interrupt_stack {
    ($name:ident, $stack: ident, $func:block) => {
        #[naked]
        pub unsafe extern fn $name () {
            #[inline(never)]
            unsafe fn inner($stack: &mut $crate::arch::x86_64::macros::InterruptStack) {
                $func
            }

            // Push scratch registers
            scratch_push!();
            preserved_push!();
            fs_push!();

            // Get reference to stack variables
            let rsp: usize;
            asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");

            // Map kernel
            $crate::arch::x86_64::pti::map();

            // Call inner rust function
            inner(&mut *(rsp as *mut $crate::arch::x86_64::macros::InterruptStack));

            // Unmap kernel
            $crate::arch::x86_64::pti::unmap();

            // Pop scratch registers and return
            fs_pop!();
            preserved_pop!();
            scratch_pop!();
            iret!();
        }
    };
}

#[allow(dead_code)]
#[repr(packed)]
pub struct InterruptErrorStack {
    pub fs: usize,
    pub preserved: PreservedRegisters,
    pub scratch: ScratchRegisters,
    pub code: usize,
    pub iret: IretRegisters,
}

impl InterruptErrorStack {
    pub fn dump(&self) {
        self.iret.dump();
        println!("CODE:  {:>016X}", { self.code });
        self.scratch.dump();
        self.preserved.dump();
        println!("FS:    {:>016X}", { self.fs });
    }
}

#[macro_export]
macro_rules! interrupt_error {
    ($name:ident, $stack:ident, $func:block) => {
        #[naked]
        pub unsafe extern fn $name () {
            #[inline(never)]
            unsafe fn inner($stack: &$crate::arch::x86_64::macros::InterruptErrorStack) {
                $func
            }

            // Push scratch registers
            scratch_push!();
            preserved_push!();
            fs_push!();

            // Get reference to stack variables
            let rsp: usize;
            asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");

            // Map kernel
            $crate::arch::x86_64::pti::map();

            // Call inner rust function
            inner(&*(rsp as *const $crate::arch::x86_64::macros::InterruptErrorStack));

            // Unmap kernel
            $crate::arch::x86_64::pti::unmap();

            // Pop scratch registers, error code, and return
            fs_pop!();
            preserved_pop!();
            scratch_pop!();
            asm!("add rsp, 8" : : : : "intel", "volatile");
            iret!();
        }
    };
}
<|endoftext|>


<commit_before>use autograd::Variable;
use tensor::Tensor;
use torch;
use itertools::zip;

type Var64List = Vec<Variable<f64>>;

pub fn get_numerical_jacobian(func: fn(&Variable<f64>) -> Variable<f64>,
                              input: &Variable<f64>,
                              target: &Var64List,
                              eps: Option<f64>)
                              -> Vec<Tensor<f64>> {

    let eps = match eps {
        Some(e) => e,
        None => 1e-3,
    };
    let input = input.contiguous();
    let output_size = func(&input).numel();
    // XXX look at when this may not be a flat vector
    let jacobian: Vec<Tensor<f64>> = target
        .iter()
        .map(|v| ::torch::zeros([v.numel(), output_size]))
        .collect();

    let x_tensors: Vec<Tensor<f64>> = target
        .iter()
        .filter_map(|v| if v.requires_grad() {
                        Some(v.data_borrow().clone())
                    } else {
                        None
                    })
        .collect();
    let j_tensors = jacobian.clone();

    let mut outa = torch::double_tensor(output_size);
    let mut outb = torch::double_tensor(output_size);

    for (ref x_tensor_, ref mut d_tensor) in zip(x_tensors, j_tensors) {
        let x_tensor: &Tensor<f64> = x_tensor_;
        let mut flat_tensor = x_tensor.view([-1]);
        for i in 0..flat_tensor.numel() {
            let orig = flat_tensor[i];
            flat_tensor[i] = orig - eps;
            outa.copy_(func(&input).data_borrow());
            flat_tensor[i] = orig + eps;
            outb.copy_(func(&input).data_borrow());
            flat_tensor[i] = orig;

            outb.addt_(-1., &outa).div_(2. * eps);
            d_tensor.s([i as isize]).copy_(&outb);
        }
    }
    jacobian
}

pub fn zero_gradients(input: &mut Var64List) {
    for v in input {
        if let &mut Some(ref mut grad) = v.grad() {
            grad.detach_();
            grad.data().zero_();
        }
    }
}

pub fn iter_gradients(input: &mut Var64List) -> Vec<Option<Tensor<f64>>> {
    input
        .iter_mut()
        .map(|v| if v.requires_grad() {
                 if let &mut Some(ref mut grad) = v.grad() {
                     Some(grad.data().clone())
                 } else {
                     None
                 }
             } else {
                 None
             })
        .collect()

}

pub fn get_analytical_jacobian(input: &mut Var64List, output: &Variable<f64>) -> Vec<Tensor<f64>> {
    let mut jacobian: Vec<Tensor<f64>> = input
        .iter()
        .map(|v| ::torch::zeros([v.numel(), output.numel()]))
        .collect();
    let grad_output: Tensor<f64> = torch::zeros(output.data_borrow().size());
    let mut flat_grad_output = grad_output.view([-1]);

    for i in 0..flat_grad_output.numel() {
        flat_grad_output.zero_();
        flat_grad_output[i] = 1.;
        zero_gradients(input);
        for (ref mut jacobian_x, ref d_x_) in zip(jacobian.iter_mut(), iter_gradients(input)) {
            let d_x_: &Option<Tensor<f64>> = d_x_;
            if let &Some(ref d_x) = d_x_ {
                jacobian_x.s([-1, i as isize]).copy_(d_x);
            }

        }

    }

    jacobian
}
<commit_msg>checkpoint gradcheck<commit_after>use autograd::Variable;
use tensor::{NumLimits, Tensor};
use std::slice::{Iter, IterMut};
use torch;
use itertools::zip;

type Var64List = Vec<Variable<f64>>;

type Layer = fn(&Var64List) -> Var64List;
type PartialLayer = FnMut(&Var64List) -> Tensor<f64>;

pub fn contiguous(v: &Var64List) -> Var64List {
    v.iter().map(|v| v.contiguous()).collect()
}

pub fn get_numerical_jacobian(func: &mut PartialLayer,
                              input: &Var64List,
                              target: &Var64List,
                              eps: Option<f64>)
                              -> Vec<Tensor<f64>> {

    let eps = match eps {
        Some(e) => e,
        None => 1e-3,
    };
    let input = contiguous(input);
    let output_size = func(&input).numel();
    // XXX look at when this may not be a flat vector
    let jacobian: Vec<Tensor<f64>> = target
        .iter()
        .map(|v| ::torch::zeros([v.numel(), output_size]))
        .collect();

    let x_tensors: Vec<Tensor<f64>> = target
        .iter()
        .filter_map(|v| if v.requires_grad() {
                        Some(v.data_borrow().clone())
                    } else {
                        None
                    })
        .collect();
    let j_tensors = jacobian.clone();

    let mut outa = torch::double_tensor(output_size);
    let mut outb = torch::double_tensor(output_size);

    for (ref x_tensor_, ref mut d_tensor) in zip(x_tensors, j_tensors) {
        let x_tensor: &Tensor<f64> = x_tensor_;
        let mut flat_tensor = x_tensor.view([-1]);
        for i in 0..flat_tensor.numel() {
            let orig = flat_tensor[i];
            flat_tensor[i] = orig - eps;
            outa.copy_(&(*func)(&input));
            flat_tensor[i] = orig + eps;
            outb.copy_(&func(&input));
            flat_tensor[i] = orig;

            outb.addt_(-1., &outa).div_(2. * eps);
            d_tensor.s([i as isize]).copy_(&outb);
        }
    }
    jacobian
}

pub fn zero_gradients(input: &mut Var64List) {
    for v in input {
        if let &mut Some(ref mut grad) = v.grad() {
            grad.detach_();
            grad.data().zero_();
        }
    }
}

pub fn iter_gradients(input: &mut Var64List) -> Vec<Option<Tensor<f64>>> {
    input
        .iter_mut()
        .map(|v| if v.requires_grad() {
                 if let &mut Some(ref mut grad) = v.grad() {
                     Some(grad.data().clone())
                 } else {
                     None
                 }
             } else {
                 None
             })
        .collect()
}

pub fn get_analytical_jacobian(input: &mut Var64List, output: &Variable<f64>) -> Vec<Tensor<f64>> {
    let mut jacobian: Vec<Tensor<f64>> = input
        .iter()
        .map(|v| ::torch::zeros([v.numel(), output.numel()]))
        .collect();
    let grad_output: Tensor<f64> = torch::zeros(output.data_borrow().size());
    let mut flat_grad_output = grad_output.view([-1]);

    for i in 0..flat_grad_output.numel() {
        flat_grad_output.zero_();
        flat_grad_output[i] = 1.;
        zero_gradients(input);
        for (ref mut jacobian_x, ref d_x_) in zip(jacobian.iter_mut(), iter_gradients(input)) {
            let d_x_: &Option<Tensor<f64>> = d_x_;
            if let &Some(ref d_x) = d_x_ {
                jacobian_x.s([-1, i as isize]).copy_(d_x);
            }

        }

    }
    jacobian
}

//
//       Check gradients computed via small finite differences
//       against analytical gradients
//
//    The check between numerical and analytical has the same behaviour as
//    numpy.allclose https://docs.scipy.org/doc/numpy/reference/generated/numpy.allclose.html
//    meaning it check that
//        absolute(a - n) <= (atol + rtol * absolute(n))
//    is true for all elements of analytical jacobian a and numerical jacobian n.
//
//    Args:
//        func: function that takes Vec<Variable> inputs and returns
//            a Vec<Variable>
//        inputs: Vec<Variable>
//        eps: perturbation for finite differences
//        atol: absolute tolerance
//        rtol: relative tolerance
//
//    Returns:
//        True if all differences satisfy allclose condition

pub fn gradcheck(func: Layer,
                 inputs: &mut Var64List,
                 eps: Option<f64>,
                 atol: Option<f64>,
                 rtol: Option<f64>)
                 -> bool {
    let eps = match eps {
        Some(e) => e,
        None => 1e-6,
    };
    let atol = match atol {
        Some(e) => e,
        None => 1e-5,
    };
    let rtol = match rtol {
        Some(e) => e,
        None => 1e-3,
    };
    let output = func(inputs);
    for (i, ref o) in output.iter().enumerate() {
        if !o.requires_grad() {
            continue;
        }
        let mut f = move |input: &Var64List| func(input)[i].data().clone();
        let analytical = get_analytical_jacobian(inputs, o);
        let numerical = get_numerical_jacobian(&mut f, inputs, inputs, Some(eps));
        for (ref a, ref n) in zip(analytical, numerical) {
            if !zip(a.sub(n).abs().iter(), n.abs().mul(rtol).add(rtol).iter())
                    .all(|(a, b)| a <= b) {
                return false;
            }
        }
    }
    zero_gradients(inputs);
    let output = func(inputs);
    true
}
<|endoftext|>


<commit_before>// Iterates over every crate versions ever uploaded and (re-)renders their
// readme using the Markdown renderer from the cargo_registry crate.
//
// Warning: this can take a lot of time.
//
// Usage:
//     cargo run --bin render-readmes [page-size: optional = 25]
// The page-size argument dictate how much versions should be queried and processed at once.

#![deny(warnings)]

#[macro_use]
extern crate serde_derive;

extern crate cargo_registry;
extern crate curl;
extern crate diesel;
extern crate flate2;
extern crate postgres;
extern crate s3;
extern crate tar;
extern crate time;
extern crate toml;
extern crate url;

use curl::easy::{Easy, List};
use diesel::prelude::*;
use flate2::read::GzDecoder;
use std::env;
use std::io::{Cursor, Read};
use std::path::Path;
use std::sync::Arc;
use std::thread;
use tar::Archive;
use url::Url;

use cargo_registry::{App, Config, Version};
use cargo_registry::version::EncodableVersion;
use cargo_registry::schema::*;
use cargo_registry::render::markdown_to_html;

const DEFAULT_PAGE_SIZE: i64 = 25;

fn main() {
    let config: Config = Default::default();
    let app = Arc::new(App::new(&config));
    let conn = cargo_registry::db::connect_now().unwrap();
    let versions_count = versions::table
        .select(versions::all_columns)
        .count()
        .get_result::<i64>(&conn)
        .expect("error counting versions");
    let page_size = match env::args().nth(1) {
        None => DEFAULT_PAGE_SIZE,
        Some(s) => s.parse::<i64>().unwrap_or(DEFAULT_PAGE_SIZE),
    };
    let pages = if versions_count % page_size == 0 {
        versions_count / page_size
    } else {
        versions_count / page_size + 1
    };
    for current_page in 0..pages {
        let versions: Vec<EncodableVersion> = versions::table
            .inner_join(crates::table)
            .select((versions::all_columns, crates::name))
            .limit(page_size)
            .offset(current_page * page_size)
            .load::<(Version, String)>(&conn)
            .expect("error loading versions")
            .into_iter()
            .map(|(version, crate_name)| version.encodable(&crate_name))
            .collect();
        let mut tasks = Vec::with_capacity(page_size as usize);
        for version in versions {
            let app = app.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", version.krate, version.num);
                let readme = get_readme(app.clone(), &version);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let readme_path = format!(
                    "readmes/{}/{}-{}.html",
                    version.krate,
                    version.krate,
                    version.num
                );
                let readme_len = readme.len();
                let mut body = Cursor::new(readme.into_bytes());
                app.config
                    .uploader
                    .upload(
                        Easy::new(),
                        &readme_path,
                        &mut body,
                        "text/html",
                        readme_len as u64,
                    )
                    .expect(&format!(
                        "[{}-{}] Couldn't upload file to S3",
                        version.krate,
                        version.num
                    ));
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thead panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(app: Arc<App>, version: &EncodableVersion) -> Option<String> {
    let mut handle = Easy::new();
    let location = match app.config.uploader.crate_location(
        &version.krate,
        &version.num,
    ) {
        Some(l) => l,
        None => return None,
    };
    let date = time::now().rfc822z().to_string();
    let url = Url::parse(&location).expect(&format!(
        "[{}-{}] Couldn't parse crate URL",
        version.krate,
        version.num
    ));

    let mut headers = List::new();
    headers
        .append(&format!("Host: {}", url.host().unwrap()))
        .unwrap();
    headers.append(&format!("Date: {}", date)).unwrap();

    handle.url(url.as_str()).unwrap();
    handle.get(true).unwrap();
    handle.http_headers(headers).unwrap();

    let mut response = Vec::new();
    {
        let mut req = handle.transfer();
        req.write_function(|data| {
            response.extend(data);
            Ok(data.len())
        }).unwrap();
        if let Err(err) = req.perform() {
            println!(
                "[{}-{}] Unable to fetch crate: {}",
                version.krate,
                version.num,
                err
            );
            return None;
        }
    }
    if handle.response_code().unwrap() != 200 {
        let response = String::from_utf8_lossy(&response);
        println!(
            "[{}-{}] Failed to get a 200 response: {}",
            version.krate,
            version.num,
            response
        );
        return None;
    }
    let reader = Cursor::new(response);
    let reader = GzDecoder::new(reader).expect(&format!(
        "[{}-{}] Invalid gzip header",
        version.krate,
        version.num
    ));
    let mut archive = Archive::new(reader);
    let mut entries = archive.entries().expect(&format!(
        "[{}-{}] Invalid tar archive entries",
        version.krate,
        version.num
    ));
    let manifest: Manifest = {
        let path = format!("{}-{}/Cargo.toml", version.krate, version.num);
        let contents = find_file_by_path(&mut entries, Path::new(&path), &version);
        toml::from_str(&contents).expect(&format!(
            "[{}-{}] Syntax error in manifest file",
            version.krate,
            version.num
        ))
    };
    if manifest.package.readme.is_none() {
        return None;
    }
    let rendered = {
        let path = format!(
            "{}-{}/{}",
            version.krate,
            version.num,
            manifest.package.readme.unwrap()
        );
        let contents = find_file_by_path(&mut entries, Path::new(&path), &version);
        markdown_to_html(&contents).expect(&format!(
            "[{}-{}] Couldn't render README",
            version.krate,
            version.num
        ))
    };
    return Some(rendered);
    #[derive(Deserialize)]
    struct Package {
        readme: Option<String>,
    }
    #[derive(Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    mut entries: &mut tar::Entries<R>,
    path: &Path,
    version: &EncodableVersion,
) -> String {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                return filepath == path;
            }
        })
        .expect(&format!(
            "[{}-{}] couldn't open file: {}",
            version.krate,
            version.num,
            path.display()
        ))
        .expect(&format!(
            "[{}-{}] file is not present: {}",
            version.krate,
            version.num,
            path.display()
        ));
    let mut contents = String::new();
    file.read_to_string(&mut contents).expect(&format!(
        "[{}-{}] Couldn't read file contents",
        version.krate,
        version.num
    ));
    contents
}
<commit_msg>Get uploader from config instead of app<commit_after>// Iterates over every crate versions ever uploaded and (re-)renders their
// readme using the Markdown renderer from the cargo_registry crate.
//
// Warning: this can take a lot of time.
//
// Usage:
//     cargo run --bin render-readmes [page-size: optional = 25]
// The page-size argument dictate how much versions should be queried and processed at once.

#![deny(warnings)]

#[macro_use]
extern crate serde_derive;

extern crate cargo_registry;
extern crate curl;
extern crate diesel;
extern crate flate2;
extern crate postgres;
extern crate s3;
extern crate tar;
extern crate time;
extern crate toml;
extern crate url;

use curl::easy::{Easy, List};
use diesel::prelude::*;
use flate2::read::GzDecoder;
use std::env;
use std::io::{Cursor, Read};
use std::path::Path;
use std::thread;
use tar::Archive;
use url::Url;

use cargo_registry::{Config, Version};
use cargo_registry::version::EncodableVersion;
use cargo_registry::schema::*;
use cargo_registry::render::markdown_to_html;

const DEFAULT_PAGE_SIZE: i64 = 25;

fn main() {
    let config: Config = Default::default();
    let conn = cargo_registry::db::connect_now().unwrap();
    let versions_count = versions::table
        .select(versions::all_columns)
        .count()
        .get_result::<i64>(&conn)
        .expect("error counting versions");
    let page_size = match env::args().nth(1) {
        None => DEFAULT_PAGE_SIZE,
        Some(s) => s.parse::<i64>().unwrap_or(DEFAULT_PAGE_SIZE),
    };
    let pages = if versions_count % page_size == 0 {
        versions_count / page_size
    } else {
        versions_count / page_size + 1
    };
    for current_page in 0..pages {
        let versions: Vec<EncodableVersion> = versions::table
            .inner_join(crates::table)
            .select((versions::all_columns, crates::name))
            .limit(page_size)
            .offset(current_page * page_size)
            .load::<(Version, String)>(&conn)
            .expect("error loading versions")
            .into_iter()
            .map(|(version, crate_name)| version.encodable(&crate_name))
            .collect();
        let mut tasks = Vec::with_capacity(page_size as usize);
        for version in versions {
            let config = config.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", version.krate, version.num);
                let readme = get_readme(&config, &version);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let readme_path = format!(
                    "readmes/{}/{}-{}.html",
                    version.krate,
                    version.krate,
                    version.num
                );
                let readme_len = readme.len();
                let mut body = Cursor::new(readme.into_bytes());
                config
                    .uploader
                    .upload(
                        Easy::new(),
                        &readme_path,
                        &mut body,
                        "text/html",
                        readme_len as u64,
                    )
                    .expect(&format!(
                        "[{}-{}] Couldn't upload file to S3",
                        version.krate,
                        version.num
                    ));
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thead panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(config: &Config, version: &EncodableVersion) -> Option<String> {
    let mut handle = Easy::new();
    let location = match config.uploader.crate_location(
        &version.krate,
        &version.num,
    ) {
        Some(l) => l,
        None => return None,
    };
    let date = time::now().rfc822z().to_string();
    let url = Url::parse(&location).expect(&format!(
        "[{}-{}] Couldn't parse crate URL",
        version.krate,
        version.num
    ));

    let mut headers = List::new();
    headers
        .append(&format!("Host: {}", url.host().unwrap()))
        .unwrap();
    headers.append(&format!("Date: {}", date)).unwrap();

    handle.url(url.as_str()).unwrap();
    handle.get(true).unwrap();
    handle.http_headers(headers).unwrap();

    let mut response = Vec::new();
    {
        let mut req = handle.transfer();
        req.write_function(|data| {
            response.extend(data);
            Ok(data.len())
        }).unwrap();
        if let Err(err) = req.perform() {
            println!(
                "[{}-{}] Unable to fetch crate: {}",
                version.krate,
                version.num,
                err
            );
            return None;
        }
    }
    if handle.response_code().unwrap() != 200 {
        let response = String::from_utf8_lossy(&response);
        println!(
            "[{}-{}] Failed to get a 200 response: {}",
            version.krate,
            version.num,
            response
        );
        return None;
    }
    let reader = Cursor::new(response);
    let reader = GzDecoder::new(reader).expect(&format!(
        "[{}-{}] Invalid gzip header",
        version.krate,
        version.num
    ));
    let mut archive = Archive::new(reader);
    let mut entries = archive.entries().expect(&format!(
        "[{}-{}] Invalid tar archive entries",
        version.krate,
        version.num
    ));
    let manifest: Manifest = {
        let path = format!("{}-{}/Cargo.toml", version.krate, version.num);
        let contents = find_file_by_path(&mut entries, Path::new(&path), &version);
        toml::from_str(&contents).expect(&format!(
            "[{}-{}] Syntax error in manifest file",
            version.krate,
            version.num
        ))
    };
    if manifest.package.readme.is_none() {
        return None;
    }
    let rendered = {
        let path = format!(
            "{}-{}/{}",
            version.krate,
            version.num,
            manifest.package.readme.unwrap()
        );
        let contents = find_file_by_path(&mut entries, Path::new(&path), &version);
        markdown_to_html(&contents).expect(&format!(
            "[{}-{}] Couldn't render README",
            version.krate,
            version.num
        ))
    };
    return Some(rendered);
    #[derive(Deserialize)]
    struct Package {
        readme: Option<String>,
    }
    #[derive(Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    mut entries: &mut tar::Entries<R>,
    path: &Path,
    version: &EncodableVersion,
) -> String {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                return filepath == path;
            }
        })
        .expect(&format!(
            "[{}-{}] couldn't open file: {}",
            version.krate,
            version.num,
            path.display()
        ))
        .expect(&format!(
            "[{}-{}] file is not present: {}",
            version.krate,
            version.num,
            path.display()
        ));
    let mut contents = String::new();
    file.read_to_string(&mut contents).expect(&format!(
        "[{}-{}] Couldn't read file contents",
        version.krate,
        version.num
    ));
    contents
}
<|endoftext|>