<commit_before>use bar::Bar;
use std::rc::Rc;
use error::{Result, ErrorKind};
use item_state::ItemState;
use bar_properties::BarProperties;
use futures::Stream;
use pango::FontDescription;
use xcb_event_stream::XcbEventStream;
use tokio_core::reactor::{Core, Handle};
use component::{Slot, ComponentUpdate, ComponentCreator};
use xcb::{self, Visualtype, Screen, Window, Rectangle, Connection, randr};

#[derive(Clone)]
/// Defines a color by it's red, green and blue components.
pub struct Color {
    pub red: f64,
    pub green: f64,
    pub blue: f64,
}

impl Color {
    pub fn new(red: f64, green: f64, blue: f64) -> Color {
        Color { red, green, blue }
    }

    /// Transforms this struct into a u32, which is in reality C-packed struct
    /// with the red, green, blue and alpha fields.
    /// Colors represented in this form are required by XCB.
    pub fn as_u32(&self) -> u32 {
        (((255. * self.red).round() as u32) << 16) + (((255. * self.green).round() as u32) << 8) +
            (((255. * self.blue).round() as u32) << 0)
    }
}

/// Bar position relative to the screen.
#[derive(Clone)]
pub enum Position {
    Top,
    Bottom,
}

/// Bar geometry.
#[derive(Clone)]
pub enum Geometry {
    /// Define bar's geometry with absolute coordinates.
    Absolute(Rectangle),
    /// Define bar's geometry relative to the screen.
    Relative {
        /// The bar's position relative to the screen.
        position: Position,
        /// The bar's height in pixels.
        height: u16,
        /// Space between the bar and the top or bottom side of the screen in pixels.
        padding_x: u16,
        /// Space between the bar and the left and right side of the screen in pixels.
        padding_y: u16,
    },
}

impl Default for Geometry {
    fn default() -> Geometry {
        Geometry::Relative {
            position: Position::Top,
            height: 20,
            padding_y: 0,
            padding_x: 0,
        }
    }
}

pub type UpdateStream = Box<Stream<Item = ComponentUpdate, Error = ::error::Error>>;

/// Struct implementing the builder pattern for `Bar`.
pub struct BarBuilder {
    output: String,
    geometry: Geometry,
    bg_color: Color,
    fg_color: Color,
    font_name: String,
    items: Vec<(Slot, Box<ComponentCreator>)>,
}

impl BarBuilder {
    /// Create a new `BarBuilder` with default properties.
    pub fn new<T: Into<String>>(output: T) -> BarBuilder {
        BarBuilder {
            output: output.into(),
            geometry: Default::default(),
            bg_color: Color::new(1., 1., 1.),
            fg_color: Color::new(0., 0., 0.),
            items: vec![],
            font_name: String::new(),
        }
    }

    /// Create a `tokio` event loop and run launch the bar on it.
    pub fn run(self) -> Result<()> {
        let mut core = Core::new()?;
        let bar = self.build(core.handle())?;
        let future = bar.run();
        core.run(future).map_err(|()| "event loop error".into())
    }

    /// Adds a component to the bar into the specified slot.
    pub fn add_component<C>(mut self, slot: Slot, component: C) -> Self
    where
        C: ComponentCreator + 'static,
    {
        self.items.push((slot, Box::new(component)));
        self
    }

    /// Set the bar's position and size.
    pub fn geometry(mut self, geometry: Geometry) -> Self {
        self.geometry = geometry;
        self
    }

    /// Set the default font.
    pub fn font<S: AsRef<str>>(mut self, font: S) -> Self {
        self.font_name = font.as_ref().to_string();
        self
    }

    /// Set the default foreground color. (The text color)
    pub fn foreground(mut self, color: Color) -> Self {
        self.fg_color = color;
        self
    }

    /// Set the default background color.
    pub fn background(mut self, color: Color) -> Self {
        self.bg_color = color;
        self
    }

    /// Consumes and splits self into `self.items` and `BarProperties` struct,
    /// containing everything else relevant.
    fn into_items_and_props(
        self,
        area: &Rectangle,
    ) -> (Vec<(Slot, Box<ComponentCreator>)>, BarProperties) {
        let props = BarProperties {
            geometry: self.geometry,
            area: area.clone(),
            accent_color: None,
            fg_color: self.fg_color,
            bg_color: self.bg_color,
            font: FontDescription::from_string(&*self.font_name),
        };
        (self.items, props)
    }

    /// Builds and returns the bar.
    pub fn build(self, handle: Handle) -> Result<Bar> {
        let (window_conn, _) = Connection::connect(None)
            .map_err(|e| ErrorKind::XcbConnection(e))?;
        let (conn, _) = Connection::connect(None)
            .map_err(|e| ErrorKind::XcbConnection(e))?;

        let geometry;
        let window;
        let visualtype;
        let foreground = conn.generate_id();

        // Scope for `screen`
        {
            let setup = conn.get_setup();
            let screen = setup.roots().next().unwrap();

            geometry = calculate_geometry(&screen, &self.geometry, &self.output, &conn)?;
            window = create_window(&window_conn, &screen, &geometry, self.bg_color.as_u32())?;
            visualtype = find_visualtype(&screen).unwrap();

            // Create xcb graphics context for drawin te background
            try_xcb!(
                xcb::create_gc_checked,
                "failed to create gcontext",
                &conn,
                foreground,
                screen.root(),
                &[
                    (xcb::GC_FOREGROUND, self.bg_color.as_u32()),
                    (xcb::GC_GRAPHICS_EXPOSURES, 0)
                ]
            );
        }

        let conn = Rc::new(conn);

        let item_count = self.items.len();
        let mut left_items = vec![];
        let mut center_items = vec![];
        let mut right_items = vec![];
        let mut updates: Option<UpdateStream> = None;

        // Consumes self
        let (items, properties) = self.into_items_and_props(&geometry);
        let properties = Rc::new(properties);

        // Initiate components and convert them into a stream of
        // updates.  The sream also carries information about the
        // source component such as the id, slot and the index of
        // the component in the said slot.
        for (id, (slot, creator)) in items.into_iter().enumerate() {
            let vec = match slot {
                Slot::Left => &mut left_items,
                Slot::Center => &mut center_items,
                Slot::Right => &mut right_items,
            };
            let index = vec.len();

            vec.push(ItemState::new(
                id,
                properties.clone(),
                0,
                visualtype,
                conn.clone(),
                window,
            ));

            let stream = creator.create(handle.clone())?.map(move |value| {
                ComponentUpdate {
                    slot: slot,
                    index,
                    id,
                    value,
                }
            });
            updates = match updates {
                None => Some(Box::new(stream)),
                Some(other) => Some(Box::new(other.select(stream))),
            }
        }

        // Join the component update stream with
        // a stream carrying events from XCB.
        let stream = updates
            .unwrap_or_else(|| Box::new(::futures::stream::empty()))
            .merge(XcbEventStream::new(window_conn));

        Ok(Bar {
            center_items,
            conn,
            foreground,
            geometry,
            item_positions: vec![(0, 0); item_count],
            left_items,
            right_items,
            stream: Some(stream),
            window,
        })
    }
}

/// Finds a visual type matching the one of the screen provided.
fn find_visualtype<'s>(screen: &Screen<'s>) -> Option<Visualtype> {
    'DEPTH: for depth in screen.allowed_depths() {
        for visual in depth.visuals() {
            if visual.visual_id() == screen.root_visual() {
                return Some(visual);
            }
        }
    }
    None
}

/// Calculates the position and size of the bar on
/// screen given the Geometry struct and screen dimensions.
fn calculate_geometry<'s>(
    screen: &Screen<'s>,
    geometry: &Geometry,
    output: &str,
    conn: &Connection,
) -> Result<Rectangle> {
    let screen_info = get_screen_info(screen, conn, output)?;
    let screen_w = screen_info.width();
    let screen_h = screen_info.height();

    match geometry {
        &Geometry::Absolute(ref rect) => Ok(rect.clone()),
        &Geometry::Relative {
            ref position,
            height: bar_height,
            padding_x,
            padding_y,
        } => {
            let x;
            let y;
            let width;
            let height;

            match *position {
                Position::Top => {
                    x = padding_x as i16;
                    y = padding_y as i16;
                    width = screen_w - 2 * padding_x;
                    height = bar_height;
                }
                Position::Bottom => {
                    x = padding_x as i16;
                    y = (screen_h - bar_height - padding_y) as i16;
                    width = screen_w - 2 * padding_x;
                    height = bar_height;
                }
            };

            Ok(Rectangle::new(x, y, width, height))
        }
    }
}

// Get informatio about specified output
fn get_screen_info<'s>(
    screen: &Screen<'s>,
    conn: &Connection,
    query_output_name: &str,
) -> Result<xcb::Reply<xcb::ffi::randr::xcb_randr_get_crtc_info_reply_t>> {
    // Load screen resources of the root window
    // Return result on error
    let res_cookie = randr::get_screen_resources(conn, screen.root());
    let res_reply = res_cookie
        .get_reply()
        .map_err(|_| "Unable to get screen resources")?;

    // Get all crtcs from the reply
    let crtcs = res_reply.crtcs();

    for crtc in crtcs {
        // Get info about crtc
        let crtc_info_cookie = randr::get_crtc_info(conn, *crtc, 0);
        let crtc_info_reply = crtc_info_cookie.get_reply();

        if let Ok(reply) = crtc_info_reply {
            // Skip this crtc if it has no width or output
            if reply.width() == 0 || reply.num_outputs() == 0 {
                continue;
            }

            // Get info of crtc's first output for output name
            let output = reply.outputs()[0];
            let output_info_cookie = randr::get_output_info(conn, output, 0);
            let output_info_reply = output_info_cookie.get_reply();

            // Get the name of the first output
            let mut output_name = String::new();
            if let Ok(output_info_reply) = output_info_reply {
                output_name = String::from_utf8_lossy(output_info_reply.name()).into();
            }

            // If the output name is the requested name, return the dimensions
            if output_name == query_output_name {
                return Ok(reply);
            }
        }
    }
    let error_msg = ["Unable to find output ", query_output_name].concat();
    Err(error_msg.into())
}

/// Convinience macro for setting EWHM properites.
macro_rules! set_ewhm_prop {
    ($conn:expr, $window:expr, $name:expr, @atom $value:expr) => {
        {
            let value_atom = xcb::intern_atom($conn, true, $value)
                .get_reply().unwrap().atom();
            set_ewhm_prop!($conn, $window, $name, &[value_atom]);
        }
    };
    ($conn:expr, $window:expr, $name:expr, $data:expr) => {
        {
            let type_atom = xcb::intern_atom($conn, true, $name)
                .get_reply().unwrap().atom();
            xcb::change_property(
                $conn,
                xcb::PROP_MODE_REPLACE as u8,
                $window,
                type_atom,
                xcb::ATOM_ATOM,
                32,
                $data);
        }
    };
}

/// Creates a Xorg window using XCB.
fn create_window<'s>(
    conn: &Connection,
    screen: &Screen<'s>,
    geometry: &Rectangle,
    background: u32,
) -> Result<Window> {
    let window = conn.generate_id();

    xcb::create_window(
        &conn,
        xcb::WINDOW_CLASS_COPY_FROM_PARENT as u8,
        window,
        screen.root(),
        geometry.x(),
        geometry.y(),
        geometry.width(),
        geometry.height(),
        0,
        xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
        screen.root_visual(),
        &[
            (xcb::CW_BACK_PIXEL, background), // Default background color
            (
                xcb::CW_EVENT_MASK, // What kinds of events are we
                xcb::EVENT_MASK_EXPOSURE |       //   interested in
             xcb::EVENT_MASK_KEY_PRESS | xcb::EVENT_MASK_ENTER_WINDOW,
            ),
            (xcb::CW_OVERRIDE_REDIRECT, 0),
        ],
    );

    // TODO: Struts tell the WM to reserve space for our bar. Derive these from the Geometry struct.
    let mut strut = vec![0; 12];
    strut[2] = 30;
    strut[8] = 5;
    strut[9] = 1915;

    set_ewhm_prop!(&conn, window, "_NET_WM_WINDOW_TYPE", @atom "_NET_WM_WINDOW_TYPE_DOCK");
    set_ewhm_prop!(&conn, window, "_NET_WM_STATE", @atom "_NET_WM_STATE_STICKY");
    set_ewhm_prop!(&conn, window, "_NET_WM_DESKTOP", &[-1]);
    set_ewhm_prop!(&conn, window, "_NET_WM_STRUT_PARTIAL", strut.as_slice());
    set_ewhm_prop!(&conn, window, "_NET_WM_STRUT", &strut[0..4]);
    set_ewhm_prop!(
        &conn,
        window,
        "_NET_WM_NAME",
        "xcbars".chars().collect::<Vec<_>>().as_slice()
    ); // TODO: Allow users to define custom window title for the bar.

    // Request the WM to manage our window.
    xcb::map_window(&conn, window);

    // Some WMs (such as OpenBox) require this.
    xcb::configure_window(
        &conn,
        window,
        &[
            (xcb::CONFIG_WINDOW_X as u16, geometry.x() as u32),
            (xcb::CONFIG_WINDOW_Y as u16, geometry.y() as u32),
        ],
    );

    conn.flush();

    Ok(window)
}
<commit_msg>Now renders correctly on the specified screen<commit_after>use bar::Bar;
use std::rc::Rc;
use error::{Result, ErrorKind};
use item_state::ItemState;
use bar_properties::BarProperties;
use futures::Stream;
use pango::FontDescription;
use xcb_event_stream::XcbEventStream;
use tokio_core::reactor::{Core, Handle};
use component::{Slot, ComponentUpdate, ComponentCreator};
use xcb::{self, Visualtype, Screen, Window, Rectangle, Connection, randr};

#[derive(Clone)]
/// Defines a color by it's red, green and blue components.
pub struct Color {
    pub red: f64,
    pub green: f64,
    pub blue: f64,
}

impl Color {
    pub fn new(red: f64, green: f64, blue: f64) -> Color {
        Color { red, green, blue }
    }

    /// Transforms this struct into a u32, which is in reality C-packed struct
    /// with the red, green, blue and alpha fields.
    /// Colors represented in this form are required by XCB.
    pub fn as_u32(&self) -> u32 {
        (((255. * self.red).round() as u32) << 16) + (((255. * self.green).round() as u32) << 8) +
            (((255. * self.blue).round() as u32) << 0)
    }
}

/// Bar position relative to the screen.
#[derive(Clone)]
pub enum Position {
    Top,
    Bottom,
}

/// Bar geometry.
#[derive(Clone)]
pub enum Geometry {
    /// Define bar's geometry with absolute coordinates.
    Absolute(Rectangle),
    /// Define bar's geometry relative to the screen.
    Relative {
        /// The bar's position relative to the screen.
        position: Position,
        /// The bar's height in pixels.
        height: u16,
        /// Space between the bar and the top or bottom side of the screen in pixels.
        padding_x: u16,
        /// Space between the bar and the left and right side of the screen in pixels.
        padding_y: u16,
    },
}

impl Default for Geometry {
    fn default() -> Geometry {
        Geometry::Relative {
            position: Position::Top,
            height: 20,
            padding_y: 0,
            padding_x: 0,
        }
    }
}

pub type UpdateStream = Box<Stream<Item = ComponentUpdate, Error = ::error::Error>>;

/// Struct implementing the builder pattern for `Bar`.
pub struct BarBuilder {
    output: String,
    geometry: Geometry,
    bg_color: Color,
    fg_color: Color,
    font_name: String,
    items: Vec<(Slot, Box<ComponentCreator>)>,
}

impl BarBuilder {
    /// Create a new `BarBuilder` with default properties.
    pub fn new<T: Into<String>>(output: T) -> BarBuilder {
        BarBuilder {
            output: output.into(),
            geometry: Default::default(),
            bg_color: Color::new(1., 1., 1.),
            fg_color: Color::new(0., 0., 0.),
            items: vec![],
            font_name: String::new(),
        }
    }

    /// Create a `tokio` event loop and run launch the bar on it.
    pub fn run(self) -> Result<()> {
        let mut core = Core::new()?;
        let bar = self.build(core.handle())?;
        let future = bar.run();
        core.run(future).map_err(|()| "event loop error".into())
    }

    /// Adds a component to the bar into the specified slot.
    pub fn add_component<C>(mut self, slot: Slot, component: C) -> Self
    where
        C: ComponentCreator + 'static,
    {
        self.items.push((slot, Box::new(component)));
        self
    }

    /// Set the bar's position and size.
    pub fn geometry(mut self, geometry: Geometry) -> Self {
        self.geometry = geometry;
        self
    }

    /// Set the default font.
    pub fn font<S: AsRef<str>>(mut self, font: S) -> Self {
        self.font_name = font.as_ref().to_string();
        self
    }

    /// Set the default foreground color. (The text color)
    pub fn foreground(mut self, color: Color) -> Self {
        self.fg_color = color;
        self
    }

    /// Set the default background color.
    pub fn background(mut self, color: Color) -> Self {
        self.bg_color = color;
        self
    }

    /// Consumes and splits self into `self.items` and `BarProperties` struct,
    /// containing everything else relevant.
    fn into_items_and_props(
        self,
        area: &Rectangle,
    ) -> (Vec<(Slot, Box<ComponentCreator>)>, BarProperties) {
        let props = BarProperties {
            geometry: self.geometry,
            area: area.clone(),
            accent_color: None,
            fg_color: self.fg_color,
            bg_color: self.bg_color,
            font: FontDescription::from_string(&*self.font_name),
        };
        (self.items, props)
    }

    /// Builds and returns the bar.
    pub fn build(self, handle: Handle) -> Result<Bar> {
        let (window_conn, _) = Connection::connect(None)
            .map_err(|e| ErrorKind::XcbConnection(e))?;
        let (conn, _) = Connection::connect(None)
            .map_err(|e| ErrorKind::XcbConnection(e))?;

        let geometry;
        let window;
        let visualtype;
        let foreground = conn.generate_id();

        // Scope for `screen`
        {
            let setup = conn.get_setup();
            let screen = setup.roots().next().unwrap();

            geometry = calculate_geometry(&screen, &self.geometry, &self.output, &conn)?;
            window = create_window(&window_conn, &screen, &geometry, self.bg_color.as_u32())?;
            visualtype = find_visualtype(&screen).unwrap();

            // Create xcb graphics context for drawin te background
            try_xcb!(
                xcb::create_gc_checked,
                "failed to create gcontext",
                &conn,
                foreground,
                screen.root(),
                &[
                    (xcb::GC_FOREGROUND, self.bg_color.as_u32()),
                    (xcb::GC_GRAPHICS_EXPOSURES, 0)
                ]
            );
        }

        let conn = Rc::new(conn);

        let item_count = self.items.len();
        let mut left_items = vec![];
        let mut center_items = vec![];
        let mut right_items = vec![];
        let mut updates: Option<UpdateStream> = None;

        // Consumes self
        let (items, properties) = self.into_items_and_props(&geometry);
        let properties = Rc::new(properties);

        // Initiate components and convert them into a stream of
        // updates.  The sream also carries information about the
        // source component such as the id, slot and the index of
        // the component in the said slot.
        for (id, (slot, creator)) in items.into_iter().enumerate() {
            let vec = match slot {
                Slot::Left => &mut left_items,
                Slot::Center => &mut center_items,
                Slot::Right => &mut right_items,
            };
            let index = vec.len();

            vec.push(ItemState::new(
                id,
                properties.clone(),
                0,
                visualtype,
                conn.clone(),
                window,
            ));

            let stream = creator.create(handle.clone())?.map(move |value| {
                ComponentUpdate {
                    slot: slot,
                    index,
                    id,
                    value,
                }
            });
            updates = match updates {
                None => Some(Box::new(stream)),
                Some(other) => Some(Box::new(other.select(stream))),
            }
        }

        // Join the component update stream with
        // a stream carrying events from XCB.
        let stream = updates
            .unwrap_or_else(|| Box::new(::futures::stream::empty()))
            .merge(XcbEventStream::new(window_conn));

        Ok(Bar {
            center_items,
            conn,
            foreground,
            geometry,
            item_positions: vec![(0, 0); item_count],
            left_items,
            right_items,
            stream: Some(stream),
            window,
        })
    }
}

/// Finds a visual type matching the one of the screen provided.
fn find_visualtype<'s>(screen: &Screen<'s>) -> Option<Visualtype> {
    'DEPTH: for depth in screen.allowed_depths() {
        for visual in depth.visuals() {
            if visual.visual_id() == screen.root_visual() {
                return Some(visual);
            }
        }
    }
    None
}

/// Calculates the position and size of the bar on
/// screen given the Geometry struct and screen dimensions.
fn calculate_geometry<'s>(
    screen: &Screen<'s>,
    geometry: &Geometry,
    output: &str,
    conn: &Connection,
) -> Result<Rectangle> {
    let screen_info = get_screen_info(screen, conn, output)?;
    let screen_w = screen_info.width();
    let screen_h = screen_info.height();
    let x_offset = screen_info.x();
    let y_offset = screen_info.y();

    match geometry {
        &Geometry::Absolute(ref rect) => Ok(rect.clone()),
        &Geometry::Relative {
            ref position,
            height: bar_height,
            padding_x,
            padding_y,
        } => {
            let x;
            let y;
            let width;
            let height;

            match *position {
                Position::Top => {
                    x = x_offset + padding_x as i16;
                    y = y_offset + padding_y as i16;
                    width = screen_w - 2 * padding_x;
                    height = bar_height;
                }
                Position::Bottom => {
                    x = x_offset + padding_x as i16;
                    y = y_offset + (screen_h - bar_height - padding_y) as i16;
                    width = screen_w - 2 * padding_x;
                    height = bar_height;
                }
            };

            Ok(Rectangle::new(x, y, width, height))
        }
    }
}

// Get informatio about specified output
fn get_screen_info<'s>(
    screen: &Screen<'s>,
    conn: &Connection,
    query_output_name: &str,
) -> Result<xcb::Reply<xcb::ffi::randr::xcb_randr_get_crtc_info_reply_t>> {
    // Load screen resources of the root window
    // Return result on error
    let res_cookie = randr::get_screen_resources(conn, screen.root());
    let res_reply = res_cookie
        .get_reply()
        .map_err(|_| "Unable to get screen resources")?;

    // Get all crtcs from the reply
    let crtcs = res_reply.crtcs();

    for crtc in crtcs {
        // Get info about crtc
        let crtc_info_cookie = randr::get_crtc_info(conn, *crtc, 0);
        let crtc_info_reply = crtc_info_cookie.get_reply();

        if let Ok(reply) = crtc_info_reply {
            // Skip this crtc if it has no width or output
            if reply.width() == 0 || reply.num_outputs() == 0 {
                continue;
            }

            // Get info of crtc's first output for output name
            let output = reply.outputs()[0];
            let output_info_cookie = randr::get_output_info(conn, output, 0);
            let output_info_reply = output_info_cookie.get_reply();

            // Get the name of the first output
            let mut output_name = String::new();
            if let Ok(output_info_reply) = output_info_reply {
                output_name = String::from_utf8_lossy(output_info_reply.name()).into();
            }

            // If the output name is the requested name, return the dimensions
            if output_name == query_output_name {
                return Ok(reply);
            }
        }
    }
    let error_msg = ["Unable to find output ", query_output_name].concat();
    Err(error_msg.into())
}

/// Convinience macro for setting EWHM properites.
macro_rules! set_ewhm_prop {
    ($conn:expr, $window:expr, $name:expr, @atom $value:expr) => {
        {
            let value_atom = xcb::intern_atom($conn, true, $value)
                .get_reply().unwrap().atom();
            set_ewhm_prop!($conn, $window, $name, &[value_atom]);
        }
    };
    ($conn:expr, $window:expr, $name:expr, $data:expr) => {
        {
            let type_atom = xcb::intern_atom($conn, true, $name)
                .get_reply().unwrap().atom();
            xcb::change_property(
                $conn,
                xcb::PROP_MODE_REPLACE as u8,
                $window,
                type_atom,
                xcb::ATOM_ATOM,
                32,
                $data);
        }
    };
}

/// Creates a Xorg window using XCB.
fn create_window<'s>(
    conn: &Connection,
    screen: &Screen<'s>,
    geometry: &Rectangle,
    background: u32,
) -> Result<Window> {
    let window = conn.generate_id();

    xcb::create_window(
        &conn,
        xcb::WINDOW_CLASS_COPY_FROM_PARENT as u8,
        window,
        screen.root(),
        geometry.x(),
        geometry.y(),
        geometry.width(),
        geometry.height(),
        0,
        xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
        screen.root_visual(),
        &[
            (xcb::CW_BACK_PIXEL, background), // Default background color
            (
                xcb::CW_EVENT_MASK, // What kinds of events are we
                xcb::EVENT_MASK_EXPOSURE |       //   interested in
             xcb::EVENT_MASK_KEY_PRESS | xcb::EVENT_MASK_ENTER_WINDOW,
            ),
            (xcb::CW_OVERRIDE_REDIRECT, 0),
        ],
    );

    // TODO: Struts tell the WM to reserve space for our bar. Derive these from the Geometry struct.
    let mut strut = vec![0; 12];
    strut[2] = 30;
    strut[8] = 5;
    strut[9] = 1915;

    set_ewhm_prop!(&conn, window, "_NET_WM_WINDOW_TYPE", @atom "_NET_WM_WINDOW_TYPE_DOCK");
    set_ewhm_prop!(&conn, window, "_NET_WM_STATE", @atom "_NET_WM_STATE_STICKY");
    set_ewhm_prop!(&conn, window, "_NET_WM_DESKTOP", &[-1]);
    set_ewhm_prop!(&conn, window, "_NET_WM_STRUT_PARTIAL", strut.as_slice());
    set_ewhm_prop!(&conn, window, "_NET_WM_STRUT", &strut[0..4]);
    set_ewhm_prop!(
        &conn,
        window,
        "_NET_WM_NAME",
        "xcbars".chars().collect::<Vec<_>>().as_slice()
    ); // TODO: Allow users to define custom window title for the bar.

    // Request the WM to manage our window.
    xcb::map_window(&conn, window);

    // Some WMs (such as OpenBox) require this.
    xcb::configure_window(
        &conn,
        window,
        &[
            (xcb::CONFIG_WINDOW_X as u16, geometry.x() as u32),
            (xcb::CONFIG_WINDOW_Y as u16, geometry.y() as u32),
        ],
    );

    conn.flush();

    Ok(window)
}
<|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

use spaces::immix_space::block_info::BlockInfo;
use spaces::immix_space::block_allocator::BlockAllocator;
use spaces::immix_space::allocator::BlockTuple;
use spaces::immix_space::allocator::Allocator;

use std::collections::RingBuf;
use std::rc::Rc;
use std::cell::RefCell;

use constants::{BLOCK_SIZE, LINE_SIZE};

pub struct OverflowAllocator {
    block_allocator: Rc<RefCell<BlockAllocator>>,
    unavailable_blocks: RingBuf<*mut BlockInfo>,
    current_block: Option<BlockTuple>,
}

impl OverflowAllocator {
    pub fn new(block_allocator: Rc<RefCell<BlockAllocator>>) -> OverflowAllocator {
        return OverflowAllocator {
            block_allocator: block_allocator,
            unavailable_blocks: RingBuf::new(),
            current_block: None,
        };
    }
}

impl Allocator for OverflowAllocator {
    fn get_all_blocks(&mut self) -> RingBuf<*mut BlockInfo> {
        return self.unavailable_blocks.drain()
                   .chain(self.current_block.take().map(|b| b.0).into_iter())
                   .collect();
    }

    fn take_current_block(&mut self) -> Option<BlockTuple> {
        return self.current_block.take();
    }

    fn put_current_block(&mut self, block_tuple: BlockTuple) {
        self.current_block = Some(block_tuple);
    }

    fn get_new_block(&mut self) -> Option<BlockTuple> {
        debug!("Request new block");
        return self.block_allocator.borrow_mut()
                   .get_block()
                   .map(|b| unsafe{ (*b).set_allocated(); b })
                   .map(|block| (block, LINE_SIZE as u16, (BLOCK_SIZE - 1) as u16));
    }

    #[allow(unused_variables)]
    fn handle_no_hole(&mut self, size: usize) -> Option<BlockTuple> {
        return None;
    }

    fn handle_full_block(&mut self, block: *mut BlockInfo) {
        debug!("Push block {:p} into unavailable_blocks", block);
        self.unavailable_blocks.push_back(block);
    }
}
<commit_msg>Add rustdoc for allocator/overflow_allocator.rs<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

use spaces::immix_space::block_info::BlockInfo;
use spaces::immix_space::block_allocator::BlockAllocator;
use spaces::immix_space::allocator::BlockTuple;
use spaces::immix_space::allocator::Allocator;

use std::collections::RingBuf;
use std::rc::Rc;
use std::cell::RefCell;

use constants::{BLOCK_SIZE, LINE_SIZE};

/// The `OverflowAllocator` is used to allocate *medium* sized objects
/// (objects of at least `MEDIUM_OBJECT` bytes size) within the immix space to
/// limit fragmentation in the `NormalAllocator`.
pub struct OverflowAllocator {
    /// The global `BlockAllocator` to get new blocks from.
    block_allocator: Rc<RefCell<BlockAllocator>>,

    /// The exhausted blocks.
    unavailable_blocks: RingBuf<*mut BlockInfo>,

    /// The current block to allocate from.
    current_block: Option<BlockTuple>,
}

impl OverflowAllocator {
    /// Create a new `OverflowAllocator` backed by the given `BlockAllocator`.
    pub fn new(block_allocator: Rc<RefCell<BlockAllocator>>) -> OverflowAllocator {
        return OverflowAllocator {
            block_allocator: block_allocator,
            unavailable_blocks: RingBuf::new(),
            current_block: None,
        };
    }
}

impl Allocator for OverflowAllocator {
    fn get_all_blocks(&mut self) -> RingBuf<*mut BlockInfo> {
        return self.unavailable_blocks.drain()
                   .chain(self.current_block.take().map(|b| b.0).into_iter())
                   .collect();
    }

    fn take_current_block(&mut self) -> Option<BlockTuple> {
        return self.current_block.take();
    }

    fn put_current_block(&mut self, block_tuple: BlockTuple) {
        self.current_block = Some(block_tuple);
    }

    fn get_new_block(&mut self) -> Option<BlockTuple> {
        debug!("Request new block");
        return self.block_allocator.borrow_mut()
                   .get_block()
                   .map(|b| unsafe{ (*b).set_allocated(); b })
                   .map(|block| (block, LINE_SIZE as u16, (BLOCK_SIZE - 1) as u16));
    }

    #[allow(unused_variables)]
    fn handle_no_hole(&mut self, size: usize) -> Option<BlockTuple> {
        return None;
    }

    fn handle_full_block(&mut self, block: *mut BlockInfo) {
        debug!("Push block {:p} into unavailable_blocks", block);
        self.unavailable_blocks.push_back(block);
    }
}
<|endoftext|>


<commit_before>//! This is a binary running in the server environment
//!
//! You have to provide all needed configuration attributes via command line parameters,
//! or you could specify a configuration file. The format of configuration file is defined
//! in mod `config`.
//!
//! *It should be notice that the extented configuration file is not suitable for the server
//! side.*

use std::net::{IpAddr, SocketAddr};

use clap::{App, Arg};
use futures::{
    future::{self, Either},
    FutureExt,
};
use log::{error, info};
use tokio::runtime::Builder;

use shadowsocks::{plugin::PluginConfig, run_manager, Config, ConfigType, Mode, ServerAddr, ServerConfig};

mod logging;
mod monitor;

fn main() {
    let matches = App::new("shadowsocks")
        .version(shadowsocks::VERSION)
        .about("A fast tunnel proxy that helps you bypass firewalls.")
        .arg(
            Arg::with_name("VERBOSE")
                .short("v")
                .multiple(true)
                .help("Set the level of debug"),
        )
        .arg(Arg::with_name("UDP_ONLY").short("u").help("Server mode UDP_ONLY"))
        .arg(Arg::with_name("TCP_AND_UDP").short("U").help("Server mode TCP_AND_UDP"))
        .arg(
            Arg::with_name("CONFIG")
                .short("c")
                .long("config")
                .takes_value(true)
                .help("Specify config file"),
        )
        .arg(
            Arg::with_name("SERVER_ADDR")
                .short("s")
                .long("server-addr")
                .takes_value(true)
                .help("Server address"),
        )
        .arg(
            Arg::with_name("BIND_ADDR")
                .short("b")
                .long("bind-addr")
                .takes_value(true)
                .help("Bind address, outbound socket will bind this address"),
        )
        .arg(
            Arg::with_name("PASSWORD")
                .short("k")
                .long("password")
                .takes_value(true)
                .help("Password"),
        )
        .arg(
            Arg::with_name("ENCRYPT_METHOD")
                .short("m")
                .long("encrypt-method")
                .takes_value(true)
                .help("Encryption method"),
        )
        .arg(
            Arg::with_name("PLUGIN")
                .long("plugin")
                .takes_value(true)
                .help("Enable SIP003 plugin"),
        )
        .arg(
            Arg::with_name("PLUGIN_OPT")
                .long("plugin-opts")
                .takes_value(true)
                .help("Set SIP003 plugin options"),
        )
        .arg(
            Arg::with_name("NO_DELAY")
                .long("no-delay")
                .takes_value(false)
                .help("Set no-delay option for socket"),
        )
        .arg(
            Arg::with_name("MANAGER_ADDRESS")
                .long("manager-address")
                .takes_value(true)
                .help("ShadowSocks Manager (ssmgr) address"),
        )
        .arg(
            Arg::with_name("NOFILE")
                .short("n")
                .long("nofile")
                .takes_value(true)
                .help("Set RLIMIT_NOFILE with both soft and hard limit (only for *nix systems)"),
        )
        .get_matches();

    let debug_level = matches.occurrences_of("VERBOSE");
    logging::init(debug_level, "ssmanager");

    let mut has_provided_config = false;
    let mut config = match matches.value_of("CONFIG") {
        Some(cpath) => match Config::load_from_file(cpath, ConfigType::Manager) {
            Ok(cfg) => {
                has_provided_config = true;
                cfg
            }
            Err(err) => {
                error!("{:?}", err);
                return;
            }
        },
        None => Config::new(ConfigType::Manager),
    };

    let has_provided_server_config = match (
        matches.value_of("SERVER_ADDR"),
        matches.value_of("PASSWORD"),
        matches.value_of("ENCRYPT_METHOD"),
    ) {
        (Some(svr_addr), Some(password), Some(method)) => {
            let method = match method.parse() {
                Ok(m) => m,
                Err(err) => {
                    panic!("Does not support {:?} method: {:?}", method, err);
                }
            };

            let sc = ServerConfig::new(
                svr_addr
                    .parse::<ServerAddr>()
                    .expect("`server-addr` invalid, \"IP:Port\" or \"Domain:Port\""),
                password.to_owned(),
                method,
                None,
                None,
            );

            config.server.push(sc);
            true
        }
        (None, None, None) => {
            // Does not provide server config
            false
        }
        _ => {
            panic!("`server-addr`, `method` and `password` should be provided together");
        }
    };

    if !has_provided_config && !has_provided_server_config {
        println!("You have to specify a configuration file or pass arguments from argument list");
        println!("{}", matches.usage());
        return;
    }

    if let Some(bind_addr) = matches.value_of("BIND_ADDR") {
        let bind_addr = match bind_addr.parse::<IpAddr>() {
            Ok(ip) => ServerAddr::from(SocketAddr::new(ip, 0)),
            Err(..) => ServerAddr::from((bind_addr, 0)),
        };

        config.local = Some(bind_addr);
    }

    if matches.is_present("UDP_ONLY") {
        if config.mode.enable_tcp() {
            config.mode = Mode::TcpAndUdp;
        } else {
            config.mode = Mode::UdpOnly;
        }
    }

    if matches.is_present("TCP_AND_UDP") {
        config.mode = Mode::TcpAndUdp;
    }

    if matches.is_present("NO_DELAY") {
        config.no_delay = true;
    }

    if let Some(p) = matches.value_of("PLUGIN") {
        let plugin = PluginConfig {
            plugin: p.to_owned(),
            plugin_opt: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned),
        };

        // Overrides config in file
        for svr in config.server.iter_mut() {
            svr.set_plugin(plugin.clone());
        }
    };

    if let Some(m) = matches.value_of("MANAGER_ADDRESS") {
        config.manager_address = Some(
            m.parse::<ServerAddr>()
                .expect("Expecting \"IP:Port\" or \"Domain:Port\" for `manager_address`"),
        );
    }

    if let Some(nofile) = matches.value_of("NOFILE") {
        config.nofile = Some(
            nofile
                .parse::<u64>()
                .expect("Expecting an unsigned integer for `nofile`"),
        );
    }

    info!("ShadowSocks {}", shadowsocks::VERSION);

    if config.manager_address.is_none() {
        panic!(
            "Missing `manager_address`, could be specified by --manager-address in command line option or \"manager_address\" key in configuration"
        );
    }

    let mut builder = Builder::new();
    if cfg!(feature = "single-threaded") {
        builder.basic_scheduler();
    } else {
        builder.threaded_scheduler();
    }
    let mut runtime = builder.enable_all().build().expect("Unable to create Tokio Runtime");
    let rt_handle = runtime.handle().clone();

    runtime.block_on(async move {
        let abort_signal = monitor::create_signal_monitor();
        match future::select(run_manager(config, rt_handle).boxed(), abort_signal.boxed()).await {
            // Server future resolved without an error. This should never happen.
            Either::Left(_) => panic!("Server exited unexpectly"),
            // The abort signal future resolved. Means we should just exit.
            Either::Right(_) => (),
        }
    })
}
<commit_msg>[#85] ssmanager configuration file is not required<commit_after>//! This is a binary running in the server environment
//!
//! You have to provide all needed configuration attributes via command line parameters,
//! or you could specify a configuration file. The format of configuration file is defined
//! in mod `config`.
//!
//! *It should be notice that the extented configuration file is not suitable for the server
//! side.*

use std::net::{IpAddr, SocketAddr};

use clap::{App, Arg};
use futures::{
    future::{self, Either},
    FutureExt,
};
use log::{error, info};
use tokio::runtime::Builder;

use shadowsocks::{plugin::PluginConfig, run_manager, Config, ConfigType, Mode, ServerAddr, ServerConfig};

mod logging;
mod monitor;

fn main() {
    let matches = App::new("shadowsocks")
        .version(shadowsocks::VERSION)
        .about("A fast tunnel proxy that helps you bypass firewalls.")
        .arg(
            Arg::with_name("VERBOSE")
                .short("v")
                .multiple(true)
                .help("Set the level of debug"),
        )
        .arg(Arg::with_name("UDP_ONLY").short("u").help("Server mode UDP_ONLY"))
        .arg(Arg::with_name("TCP_AND_UDP").short("U").help("Server mode TCP_AND_UDP"))
        .arg(
            Arg::with_name("CONFIG")
                .short("c")
                .long("config")
                .takes_value(true)
                .help("Specify config file"),
        )
        .arg(
            Arg::with_name("SERVER_ADDR")
                .short("s")
                .long("server-addr")
                .takes_value(true)
                .help("Server address"),
        )
        .arg(
            Arg::with_name("BIND_ADDR")
                .short("b")
                .long("bind-addr")
                .takes_value(true)
                .help("Bind address, outbound socket will bind this address"),
        )
        .arg(
            Arg::with_name("PASSWORD")
                .short("k")
                .long("password")
                .takes_value(true)
                .help("Password"),
        )
        .arg(
            Arg::with_name("ENCRYPT_METHOD")
                .short("m")
                .long("encrypt-method")
                .takes_value(true)
                .help("Encryption method"),
        )
        .arg(
            Arg::with_name("PLUGIN")
                .long("plugin")
                .takes_value(true)
                .help("Enable SIP003 plugin"),
        )
        .arg(
            Arg::with_name("PLUGIN_OPT")
                .long("plugin-opts")
                .takes_value(true)
                .help("Set SIP003 plugin options"),
        )
        .arg(
            Arg::with_name("NO_DELAY")
                .long("no-delay")
                .takes_value(false)
                .help("Set no-delay option for socket"),
        )
        .arg(
            Arg::with_name("MANAGER_ADDRESS")
                .long("manager-address")
                .takes_value(true)
                .help("ShadowSocks Manager (ssmgr) address"),
        )
        .arg(
            Arg::with_name("NOFILE")
                .short("n")
                .long("nofile")
                .takes_value(true)
                .help("Set RLIMIT_NOFILE with both soft and hard limit (only for *nix systems)"),
        )
        .get_matches();

    let debug_level = matches.occurrences_of("VERBOSE");
    logging::init(debug_level, "ssmanager");

    let mut config = match matches.value_of("CONFIG") {
        Some(cpath) => match Config::load_from_file(cpath, ConfigType::Manager) {
            Ok(cfg) => cfg,
            Err(err) => {
                error!("{:?}", err);
                return;
            }
        },
        None => Config::new(ConfigType::Manager),
    };

    match (
        matches.value_of("SERVER_ADDR"),
        matches.value_of("PASSWORD"),
        matches.value_of("ENCRYPT_METHOD"),
    ) {
        (Some(svr_addr), Some(password), Some(method)) => {
            let method = match method.parse() {
                Ok(m) => m,
                Err(err) => {
                    panic!("Does not support {:?} method: {:?}", method, err);
                }
            };

            let sc = ServerConfig::new(
                svr_addr
                    .parse::<ServerAddr>()
                    .expect("`server-addr` invalid, \"IP:Port\" or \"Domain:Port\""),
                password.to_owned(),
                method,
                None,
                None,
            );

            config.server.push(sc);
        }
        (None, None, None) => {
            // Does not provide server config
        }
        _ => {
            panic!("`server-addr`, `method` and `password` should be provided together");
        }
    };

    if let Some(bind_addr) = matches.value_of("BIND_ADDR") {
        let bind_addr = match bind_addr.parse::<IpAddr>() {
            Ok(ip) => ServerAddr::from(SocketAddr::new(ip, 0)),
            Err(..) => ServerAddr::from((bind_addr, 0)),
        };

        config.local = Some(bind_addr);
    }

    if matches.is_present("UDP_ONLY") {
        if config.mode.enable_tcp() {
            config.mode = Mode::TcpAndUdp;
        } else {
            config.mode = Mode::UdpOnly;
        }
    }

    if matches.is_present("TCP_AND_UDP") {
        config.mode = Mode::TcpAndUdp;
    }

    if matches.is_present("NO_DELAY") {
        config.no_delay = true;
    }

    if let Some(p) = matches.value_of("PLUGIN") {
        let plugin = PluginConfig {
            plugin: p.to_owned(),
            plugin_opt: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned),
        };

        // Overrides config in file
        for svr in config.server.iter_mut() {
            svr.set_plugin(plugin.clone());
        }
    };

    if let Some(m) = matches.value_of("MANAGER_ADDRESS") {
        config.manager_address = Some(
            m.parse::<ServerAddr>()
                .expect("Expecting \"IP:Port\" or \"Domain:Port\" for `manager_address`"),
        );
    }

    if let Some(nofile) = matches.value_of("NOFILE") {
        config.nofile = Some(
            nofile
                .parse::<u64>()
                .expect("Expecting an unsigned integer for `nofile`"),
        );
    }

    info!("ShadowSocks {}", shadowsocks::VERSION);

    if config.manager_address.is_none() {
        error!(
            "Missing `manager_address`, could be specified by --manager-address in command line option or \"manager_address\" key in configuration"
        );

        println!("{}", matches.usage());
        return;
    }

    let mut builder = Builder::new();
    if cfg!(feature = "single-threaded") {
        builder.basic_scheduler();
    } else {
        builder.threaded_scheduler();
    }
    let mut runtime = builder.enable_all().build().expect("Unable to create Tokio Runtime");
    let rt_handle = runtime.handle().clone();

    runtime.block_on(async move {
        let abort_signal = monitor::create_signal_monitor();
        match future::select(run_manager(config, rt_handle).boxed(), abort_signal.boxed()).await {
            // Server future resolved without an error. This should never happen.
            Either::Left(_) => panic!("Server exited unexpectly"),
            // The abort signal future resolved. Means we should just exit.
            Either::Right(_) => (),
        }
    })
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use error::EntryUtilError as EUE;
use error::Result;

use toml::Value;
use toml_query::read::TomlValueReadExt;

/// Trait to check whether an entry is a certain kind of entry
///
/// If an entry is marked with a `bool` flag in the header to contain a certain amount of data (for
/// example a "wiki" entry may provide some meta information in the `[wiki]` section of its header),
/// this trait provides a check whether the entry has set the flag to `true` or `false`.
///
/// # Note
///
/// This trait is solely for library implementations, as convenience functionality for implementing
/// some function like this:
///
/// # Example
///
/// ```
/// # extern crate libimagstore;
/// # #[macro_use]
/// # extern crate libimagentryutil;
///
/// # use libimagentryutil::error::Result as Result;
/// use libimagentryutil::isa::IsKindHeaderPathProvider;
/// use libimagentryutil::isa::Is;
///
/// trait WikiArticle {
///     fn is_wiki_article(&self) -> Result<bool>;
///     // ...
/// }
///
/// provide_kindflag_path!(IsWikiEntry, "wiki.is_entry");
///
/// impl WikiArticle for ::libimagstore::store::Entry {
///     fn is_wiki_article(&self) -> Result<bool> {
///         self.is::<IsWikiEntry>()
///     }
/// }
///
/// # fn main() { }
/// ```
///
/// # See also
///
/// * Documentation for `IsKindHeaderPathProvider`
/// * Helper macro `provide_kindflag_path!()`
///
pub trait Is {
    fn is<T: IsKindHeaderPathProvider>(&self) -> Result<bool>;
}

impl Is for ::libimagstore::store::Entry {
    fn is<T: IsKindHeaderPathProvider>(&self) -> Result<bool> {
        let field = T::kindflag_header_location();

        match self.get_header().read(field) {
            Ok(Some(&Value::Boolean(b))) => Ok(b),
            Ok(Some(_)) => Err(format!("Field {} has not a boolean type", field)).map_err(EUE::from),
            Ok(None)    => Err(format!("Field {} not available", field)).map_err(EUE::from),
            Err(e)      => Err(EUE::from(e))
        }
    }
}

/// The IsKindHeaderPathProvider trait provides a function `typeflag_header_location()` which
/// returns a `toml-query` path.
///
/// This path points to a `bool` entry in the header of an entry which marks the entry to be an
/// entry of a certain kind.
///
/// For example, an "Wiki" entry might contain a `true` at `"wiki.is_entry"` in the header.
/// This trait provides `"wiki.is_entry"`.
pub trait IsKindHeaderPathProvider {
    fn kindflag_header_location() -> &'static str;
}

/// Create (pub/non-pub) type for providing a `kindflag_header_location()` implementation.
#[macro_export]
macro_rules! provide_kindflag_path {
    (pub $entry_header_path_provider_type:ident, $path:expr) => {
        pub struct $entry_header_path_provider_type;
        provide_kindflag_path!(impl for $entry_header_path_provider_type, $path);
    };

    ($entry_header_path_provider_type:ident, $path:expr) => {
        struct $entry_header_path_provider_type;
        provide_kindflag_path!(impl for $entry_header_path_provider_type, $path);
    };

    (impl for $entry_header_path_provider_type:ident, $path:expr) => {
        impl IsKindHeaderPathProvider for $entry_header_path_provider_type {
            fn kindflag_header_location() -> &'static str {
                $path
            }
        }
    };
}

<commit_msg>Add Is::set_isflag() helper function<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use error::EntryUtilError as EUE;
use error::Result;

use toml::Value;
use toml_query::read::TomlValueReadExt;
use toml_query::insert::TomlValueInsertExt;

/// Trait to check whether an entry is a certain kind of entry
///
/// If an entry is marked with a `bool` flag in the header to contain a certain amount of data (for
/// example a "wiki" entry may provide some meta information in the `[wiki]` section of its header),
/// this trait provides a check whether the entry has set the flag to `true` or `false`.
///
/// # Note
///
/// This trait is solely for library implementations, as convenience functionality for implementing
/// some function like this:
///
/// # Example
///
/// ```
/// # extern crate libimagstore;
/// # #[macro_use]
/// # extern crate libimagentryutil;
///
/// # use libimagentryutil::error::Result as Result;
/// use libimagentryutil::isa::IsKindHeaderPathProvider;
/// use libimagentryutil::isa::Is;
///
/// trait WikiArticle {
///     fn is_wiki_article(&self) -> Result<bool>;
///     // ...
/// }
///
/// provide_kindflag_path!(IsWikiEntry, "wiki.is_entry");
///
/// impl WikiArticle for ::libimagstore::store::Entry {
///     fn is_wiki_article(&self) -> Result<bool> {
///         self.is::<IsWikiEntry>()
///     }
/// }
///
/// # fn main() { }
/// ```
///
/// # See also
///
/// * Documentation for `IsKindHeaderPathProvider`
/// * Helper macro `provide_kindflag_path!()`
///
pub trait Is {
    fn is<T: IsKindHeaderPathProvider>(&self) -> Result<bool>;
    fn set_isflag<T: IsKindHeaderPathProvider>(&mut self) -> Result<()>;
}

impl Is for ::libimagstore::store::Entry {
    fn is<T: IsKindHeaderPathProvider>(&self) -> Result<bool> {
        let field = T::kindflag_header_location();

        match self.get_header().read(field) {
            Ok(Some(&Value::Boolean(b))) => Ok(b),
            Ok(Some(_)) => Err(format!("Field {} has not a boolean type", field)).map_err(EUE::from),
            Ok(None)    => Err(format!("Field {} not available", field)).map_err(EUE::from),
            Err(e)      => Err(EUE::from(e))
        }
    }

    fn set_isflag<T: IsKindHeaderPathProvider>(&mut self) -> Result<()> {
        self.get_header_mut()
            .insert(T::kindflag_header_location(), Value::Boolean(true))
            .map_err(EUE::from)
            .map(|_| ())
    }
}

/// The IsKindHeaderPathProvider trait provides a function `typeflag_header_location()` which
/// returns a `toml-query` path.
///
/// This path points to a `bool` entry in the header of an entry which marks the entry to be an
/// entry of a certain kind.
///
/// For example, an "Wiki" entry might contain a `true` at `"wiki.is_entry"` in the header.
/// This trait provides `"wiki.is_entry"`.
pub trait IsKindHeaderPathProvider {
    fn kindflag_header_location() -> &'static str;
}

/// Create (pub/non-pub) type for providing a `kindflag_header_location()` implementation.
#[macro_export]
macro_rules! provide_kindflag_path {
    (pub $entry_header_path_provider_type:ident, $path:expr) => {
        pub struct $entry_header_path_provider_type;
        provide_kindflag_path!(impl for $entry_header_path_provider_type, $path);
    };

    ($entry_header_path_provider_type:ident, $path:expr) => {
        struct $entry_header_path_provider_type;
        provide_kindflag_path!(impl for $entry_header_path_provider_type, $path);
    };

    (impl for $entry_header_path_provider_type:ident, $path:expr) => {
        impl IsKindHeaderPathProvider for $entry_header_path_provider_type {
            fn kindflag_header_location() -> &'static str {
                $path
            }
        }
    };
}

<|endoftext|>


<commit_before>//! Combines sequences of arithmetic or logical instructions into single instructions.

use middle::ir::MOpcode;
use middle::ssa::ssa_traits::*;
use middle::ssa::ssastorage::SSAStorage;

use either::*;

use std::collections::HashMap;
use std::fmt;
use std::num::Wrapping;

mod combine_rules;

type SSAValue = <SSAStorage as SSA>::ValueRef;

/// For every instruction, try to combine one of its operands into itself. This
/// transforms linear data-dependency chains into trees.
pub fn run(ssa: &mut SSAStorage) -> () {
    Combiner::new().run(ssa);
}

/// Represents binary operations that are effectively unary because one of the
/// operands is constant. In other words, represents curried binary operations.
/// e.g. `(|x| 7 & x)`, `(|x| x + 3)`, etc.
#[derive(Clone)]
struct CombinableOpInfo(MOpcode, CombinableOpConstInfo);
#[derive(Clone, Debug)]
enum CombinableOpConstInfo {
    /// no const, like in `(|x| !x)`
    Unary,
    /// const is on the left, like in `(|x| 3 - x)`
    Left(u64),
    /// const is on the right, like in `(|x| x - 3)`
    Right(u64),
}

use self::CombinableOpConstInfo as COCI;

#[derive(Debug)]
struct Combiner {
    /// Nodes that could potentially be combined into another
    combine_candidates: HashMap<SSAValue, (SSAValue, CombinableOpInfo)>,
}

impl Combiner {
    fn new() -> Self {
        Combiner {
            combine_candidates: HashMap::new(),
        }
    }

    /// Calls `visit_node` on every node and replaces the node in the SSA with
    /// its return value.
    fn run(&mut self, ssa: &mut SSAStorage) -> () {
        for node in ssa.inorder_walk() {
            if let Some(repl_node) = self.visit_node(node, ssa) {
                let blk = ssa.block_for(node).unwrap();
                let addr = ssa.address(node).unwrap();
                ssa.replace_value(node, repl_node);
                if !ssa.is_constant(repl_node) {
                    ssa.insert_into_block(repl_node, blk, addr);
                }
            }
        }
    }

    /// Returns `Some(new_node)` if one of `cur_node`'s operands can be combined
    /// into `cur_node`, resulting in `new_node`.
    /// Returns `None` if no simplification can occur.
    fn visit_node(&mut self, cur_node: SSAValue, ssa: &mut SSAStorage) -> Option<SSAValue> {
        // bail if non-combinable
        let extracted = extract_opinfo(cur_node, ssa)?;
        match extracted {
            Left((sub_node, cur_opinfo, cur_vt)) => {
                let opt_new_node = self.make_combined_node(&cur_opinfo, cur_vt, sub_node, ssa);
                if let Some((new_node, new_sub_node, new_opinfo)) = opt_new_node {
                    radeco_trace!(
                        "combined ({:?} = {:?} {:?} {:?}) into ({:?} = {:?} {:?})",
                        cur_node,
                        new_sub_node,
                        self.combine_candidates[&sub_node].1,
                        cur_opinfo,
                        new_node,
                        new_sub_node,
                        new_opinfo
                    );
                    self.combine_candidates
                        .insert(new_node, (new_sub_node, new_opinfo));
                    Some(new_node)
                } else {
                    self.combine_candidates
                        .insert(cur_node, (sub_node, cur_opinfo));
                    None
                }
            }
            Right(c_val) => {
                let c_node = ssa.insert_const(c_val)?;
                Some(c_node)
            }
        }
    }

    /// Returns (the node that was just created, its operand, its opinfo)
    fn make_combined_node(
        &self,
        cur_opinfo: &CombinableOpInfo,
        cur_vt: ValueInfo,
        sub_node: SSAValue,
        ssa: &mut SSAStorage,
    ) -> Option<(SSAValue, SSAValue, CombinableOpInfo)> {
        // bail if the operand isn't combinable
        let (sub_sub_node, sub_opinfo) = self.combine_candidates.get(&sub_node)?;
        // bail if no combination exists
        let new_opinfo = combine_rules::combine_opinfo(cur_opinfo, sub_opinfo)?;

        // make the new node
        let CombinableOpInfo(new_opcode, new_coci) = new_opinfo.clone();
        let new_node = ssa.insert_op(new_opcode, cur_vt, None)?;
        match new_coci {
            COCI::Unary => {
                ssa.op_use(new_node, 0, sub_node);
            }
            COCI::Left(new_c) => {
                let new_cnode = ssa.insert_const(new_c)?;
                ssa.op_use(new_node, 0, new_cnode);
                ssa.op_use(new_node, 1, *sub_sub_node);
            }
            COCI::Right(new_c) => {
                let new_cnode = ssa.insert_const(new_c)?;
                ssa.op_use(new_node, 0, *sub_sub_node);
                ssa.op_use(new_node, 1, new_cnode);
            }
        };
        Some((new_node, *sub_sub_node, new_opinfo))
    }
}

/// Returns `Some(Left(_))` if `cur_node` has exactly one non-const operand.
/// Returns `Some(Right(_))` if `cur_node` has all const operands.
/// Returns `None` if `cur_node` is non-combinable.
fn extract_opinfo(
    cur_node: SSAValue,
    ssa: &SSAStorage,
) -> Option<Either<(SSAValue, CombinableOpInfo, ValueInfo), u64>> {
    // bail if non-`NodeType::Op`
    let (cur_opcode, cur_vt) = extract_opcode(cur_node, ssa)?;
    let cur_operands = ssa.operands_of(cur_node);
    match cur_operands.as_slice() {
        &[sub_node] => {
            let cur_opinfo = CombinableOpInfo(cur_opcode, COCI::Unary);
            Some(Left((sub_node, cur_opinfo, cur_vt)))
        }
        &[sub_node1, sub_node2] => {
            match (ssa.constant(sub_node1), ssa.constant(sub_node2)) {
                (Some(c1), Some(c2)) => {
                    // this is const_prop's job, but we can do this here too
                    // bail if `cur_opcode` is non-evalable, since that also
                    // implies it's non-combinable
                    let res_val = cur_opcode.eval_binop(c1, c2)?;
                    Some(Right(res_val))
                }
                (None, Some(c)) => {
                    let cur_opinfo = CombinableOpInfo(cur_opcode, COCI::Right(c));
                    Some(Left((sub_node1, cur_opinfo, cur_vt)))
                }
                (Some(c), None) => {
                    let cur_opinfo = CombinableOpInfo(cur_opcode, COCI::Left(c));
                    Some(Left((sub_node2, cur_opinfo, cur_vt)))
                }
                (None, None) => None,
            }
        }
        _ => None,
    }
}

fn extract_opcode(node: SSAValue, ssa: &SSAStorage) -> Option<(MOpcode, ValueInfo)> {
    if let NodeData {
        vt,
        nt: NodeType::Op(opcode),
    } = ssa.node_data(node).ok()?
    {
        Some((opcode, vt))
    } else {
        None
    }
}

impl fmt::Debug for CombinableOpInfo {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.1 {
            COCI::Unary => fmt.write_fmt(format_args!("-> ({:?} .)", self.0)),
            COCI::Left(c) => fmt.write_fmt(format_args!("-> ({:#x} {:?} .)", c, self.0)),
            COCI::Right(c) => fmt.write_fmt(format_args!("-> (. {:?} {:#x})", self.0, c)),
        }
    }
}
<commit_msg>Add some simplifications and no-op removal to `inst_combine`<commit_after>//! Combines sequences of arithmetic or logical instructions into single instructions.

use middle::ir::MOpcode;
use middle::ssa::ssa_traits::*;
use middle::ssa::ssastorage::SSAStorage;

use either::*;

use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;
use std::num::Wrapping;

mod combine_rules;

type SSAValue = <SSAStorage as SSA>::ValueRef;

/// For every instruction, try to combine one of its operands into itself. This
/// transforms linear data-dependency chains into trees.
pub fn run(ssa: &mut SSAStorage) -> () {
    Combiner::new().run(ssa);
}

/// Represents binary operations that are effectively unary because one of the
/// operands is constant. In other words, represents curried binary operations.
/// e.g. `(|x| 7 & x)`, `(|x| x + 3)`, etc.
#[derive(Clone)]
struct CombinableOpInfo(MOpcode, CombinableOpConstInfo);
#[derive(Clone, Debug)]
enum CombinableOpConstInfo {
    /// no const, like in `(|x| !x)`
    Unary,
    /// const is on the left, like in `(|x| 3 - x)`
    Left(u64),
    /// const is on the right, like in `(|x| x - 3)`
    Right(u64),
}

use self::CombinableOpConstInfo as COCI;

#[derive(Debug)]
struct Combiner {
    /// Nodes that could potentially be combined into another
    combine_candidates: HashMap<SSAValue, (SSAValue, CombinableOpInfo)>,
}

impl Combiner {
    fn new() -> Self {
        Combiner {
            combine_candidates: HashMap::new(),
        }
    }

    /// Calls `visit_node` on every node and replaces the node in the SSA with
    /// its return value.
    fn run(&mut self, ssa: &mut SSAStorage) -> () {
        for node in ssa.inorder_walk() {
            if let Some(repl_node) = self.visit_node(node, ssa) {
                let blk = ssa.block_for(node).unwrap();
                let addr = ssa.address(node).unwrap();
                ssa.replace_value(node, repl_node);
                if !ssa.is_constant(repl_node) && ssa.address(repl_node).is_none() {
                    ssa.insert_into_block(repl_node, blk, addr);
                }
            }
        }
    }

    /// Returns `Some(new_node)` if one of `cur_node`'s operands can be combined
    /// into `cur_node`, resulting in `new_node`; or, if `cur_node` could be
    /// simplified, resulting in `new_node`.
    /// Returns `None` if no simplification can occur.
    fn visit_node(&mut self, cur_node: SSAValue, ssa: &mut SSAStorage) -> Option<SSAValue> {
        // bail if non-combinable
        let extracted = extract_opinfo(cur_node, ssa)?;
        match extracted {
            Left((sub_node, cur_opinfo, cur_vt)) => {
                radeco_trace!(
                    "trying to combine ({:?} = {:?} {:?})",
                    cur_node,
                    sub_node,
                    cur_opinfo
                );
                let opt_new_node = self.make_combined_node(&cur_opinfo, cur_vt, sub_node, ssa);
                match opt_new_node {
                    Some(Left((new_node, new_sub_node, new_opinfo))) => {
                        radeco_trace!(
                            "  {:?} ==> ({:?} = {:?} {:?})",
                            cur_node,
                            new_node,
                            new_sub_node,
                            new_opinfo
                        );
                        self.combine_candidates
                            .insert(new_node, (new_sub_node, new_opinfo));
                        Some(new_node)
                    }
                    Some(Right(new_node)) => {
                        radeco_trace!("  {:?} ==> no-op", cur_node);
                        Some(new_node)
                    }
                    None => {
                        // no change; still add to `combine_candidates`
                        self.combine_candidates
                            .insert(cur_node, (sub_node, cur_opinfo));
                        None
                    }
                }
            }
            Right(c_val) => {
                // combined to constant
                radeco_trace!("{:?} = {:#x}", cur_node, c_val);
                let c_node = ssa.insert_const(c_val)?;
                Some(c_node)
            }
        }
    }

    /// Returns `Left(new_node, new_sub_node, new_opinfo)` if `cur_opinfo`
    /// combined with an operand or if `cur_opinfo` was simplified.
    /// Returns `Right(new_node)` if `cur_opinfo` canceled with an
    /// operand to make a no-op or was originally a no-op.
    /// Returns `None` if no combination or simplification exists.
    fn make_combined_node(
        &self,
        cur_opinfo: &CombinableOpInfo,
        cur_vt: ValueInfo,
        sub_node: SSAValue,
        ssa: &mut SSAStorage,
    ) -> Option<Either<(SSAValue, SSAValue, CombinableOpInfo), SSAValue>> {
        let (new_sub_node, new_opinfo) = self.combine_candidates
            .get(&sub_node)
            .and_then(|(sub_sub_node, sub_opinfo)| {
                combine_rules::combine_opinfo(cur_opinfo, sub_opinfo).map(|new_opinfo| {
                    radeco_trace!(
                        "    combined ({:?} {:?}) into ({:?})",
                        sub_opinfo,
                        cur_opinfo,
                        new_opinfo
                    );
                    (*sub_sub_node, Cow::Owned(new_opinfo))
                })
            })
            .unwrap_or((sub_node, Cow::Borrowed(cur_opinfo)));

        // simplify
        match simplify_opinfo(&new_opinfo) {
            Some(Some(simpl_new_opinfo)) => {
                radeco_trace!(
                    "    simplified ({:?}) into ({:?})",
                    new_opinfo,
                    simpl_new_opinfo
                );
                // make the new node
                let CombinableOpInfo(new_opcode, new_coci) = simpl_new_opinfo.clone();
                let new_node = ssa.insert_op(new_opcode, cur_vt, None)?;
                match new_coci {
                    COCI::Unary => {
                        ssa.op_use(new_node, 0, sub_node);
                    }
                    COCI::Left(new_c) => {
                        let new_cnode = ssa.insert_const(new_c)?;
                        ssa.op_use(new_node, 0, new_cnode);
                        ssa.op_use(new_node, 1, new_sub_node);
                    }
                    COCI::Right(new_c) => {
                        let new_cnode = ssa.insert_const(new_c)?;
                        ssa.op_use(new_node, 0, new_sub_node);
                        ssa.op_use(new_node, 1, new_cnode);
                    }
                };
                Some(Left((new_node, new_sub_node, simpl_new_opinfo)))
            }
            Some(None) => {
                radeco_trace!("    simplified ({:?}) into no-op", new_opinfo);
                Some(Right(new_sub_node))
            }
            None => {
                // no simplification
                None
            }
        }
    }
}

/// Returns an equivalent `CombinableOpInfo`, but "simpler" in some sence.
/// Currently, this converts `OpAdd`s or `OpSub`s with "negative" constants into
/// equivalent operations with positive constants.
/// Returns `Some(None)` if `info` is a no-op.
/// Returns `None` if no simplification exists.
fn simplify_opinfo(info: &CombinableOpInfo) -> Option<Option<CombinableOpInfo>> {
    use self::CombinableOpConstInfo as COCI;
    use self::CombinableOpInfo as COI;
    use middle::ir::MOpcode::*;

    match info {
        COI(OpAdd, COCI::Left(0))
        | COI(OpAdd, COCI::Right(0))
        | COI(OpSub, COCI::Right(0))
        | COI(OpAnd, COCI::Left(0xFFFFFFFFFFFFFFFF))
        | COI(OpAnd, COCI::Right(0xFFFFFFFFFFFFFFFF))
        | COI(OpOr, COCI::Left(0))
        | COI(OpOr, COCI::Right(0))
        | COI(OpXor, COCI::Left(0))
        | COI(OpXor, COCI::Right(0)) => Some(None),
        COI(OpAdd, COCI::Left(c)) | COI(OpAdd, COCI::Right(c)) if *c > u64::max_value() / 2 => {
            let c = OpSub.eval_binop(0, *c).unwrap();
            Some(Some(COI(OpSub, COCI::Right(c))))
        }
        COI(OpSub, COCI::Right(c)) if *c > u64::max_value() / 2 => {
            let c = OpSub.eval_binop(0, *c).unwrap();
            Some(Some(COI(OpAdd, COCI::Left(c))))
        }
        _ => None,
    }
}

/// Returns `Some(Left(_))` if `cur_node` has exactly one non-const operand.
/// Returns `Some(Right(_))` if `cur_node` has all const operands.
/// Returns `None` if `cur_node` is non-combinable.
fn extract_opinfo(
    cur_node: SSAValue,
    ssa: &SSAStorage,
) -> Option<Either<(SSAValue, CombinableOpInfo, ValueInfo), u64>> {
    // bail if non-`NodeType::Op`
    let (cur_opcode, cur_vt) = extract_opcode(cur_node, ssa)?;
    let cur_operands = ssa.operands_of(cur_node);
    match cur_operands.as_slice() {
        &[sub_node] => {
            let cur_opinfo = CombinableOpInfo(cur_opcode, COCI::Unary);
            Some(Left((sub_node, cur_opinfo, cur_vt)))
        }
        &[sub_node1, sub_node2] => {
            match (ssa.constant(sub_node1), ssa.constant(sub_node2)) {
                (Some(c1), Some(c2)) => {
                    // this is const_prop's job, but we can do this here too
                    // bail if `cur_opcode` is non-evalable, since that also
                    // implies it's non-combinable
                    let res_val = cur_opcode.eval_binop(c1, c2)?;
                    Some(Right(res_val))
                }
                (None, Some(c)) => {
                    let cur_opinfo = CombinableOpInfo(cur_opcode, COCI::Right(c));
                    Some(Left((sub_node1, cur_opinfo, cur_vt)))
                }
                (Some(c), None) => {
                    let cur_opinfo = CombinableOpInfo(cur_opcode, COCI::Left(c));
                    Some(Left((sub_node2, cur_opinfo, cur_vt)))
                }
                (None, None) => None,
            }
        }
        _ => None,
    }
}

fn extract_opcode(node: SSAValue, ssa: &SSAStorage) -> Option<(MOpcode, ValueInfo)> {
    if let NodeData {
        vt,
        nt: NodeType::Op(opcode),
    } = ssa.node_data(node).ok()?
    {
        Some((opcode, vt))
    } else {
        None
    }
}

impl fmt::Debug for CombinableOpInfo {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.1 {
            COCI::Unary => fmt.write_fmt(format_args!("-> ({:?} .)", self.0)),
            COCI::Left(c) => fmt.write_fmt(format_args!("-> ({:#x} {:?} .)", c, self.0)),
            COCI::Right(c) => fmt.write_fmt(format_args!("-> (. {:?} {:#x})", self.0, c)),
        }
    }
}
<|endoftext|>


<commit_before>use crate::{config::WorkMode, env::Env, file_saver::*};
use std::path::Path;

mod alias;
mod bound;
mod child_properties;
mod constants;
mod doc;
mod enums;
mod flags;
pub mod function;
mod function_body_chunk;
mod functions;
mod general;
mod object;
mod objects;
mod parameter;
mod properties;
mod property_body;
mod record;
mod records;
mod ref_mode;
mod return_value;
mod signal;
mod signal_body;
mod special_functions;
mod sys;
mod trait_impls;
mod trampoline;
mod trampoline_from_glib;
mod trampoline_to_glib;
pub mod translate_from_glib;
pub mod translate_to_glib;

pub fn generate(env: &Env) {
    match env.config.work_mode {
        WorkMode::Normal => normal_generate(env),
        WorkMode::Sys => sys::generate(env),
        WorkMode::Doc => doc::generate(env),
        WorkMode::DisplayNotBound => {}
    }
}

fn normal_generate(env: &Env) {
    let mut mod_rs: Vec<String> = Vec::new();
    let mut traits: Vec<String> = Vec::new();
    let mut builders: Vec<String> = Vec::new();
    let root_path = env.config.auto_path.as_path();

    generate_single_version_file(env);
    objects::generate(env, root_path, &mut mod_rs, &mut traits, &mut builders);
    records::generate(env, root_path, &mut mod_rs);
    enums::generate(env, root_path, &mut mod_rs);
    flags::generate(env, root_path, &mut mod_rs);
    alias::generate(env, root_path, &mut mod_rs);
    functions::generate(env, root_path, &mut mod_rs);
    constants::generate(env, root_path, &mut mod_rs);

    generate_mod_rs(env, root_path, &mod_rs, &traits, &builders);
}

pub fn generate_mod_rs(
    env: &Env,
    root_path: &Path,
    mod_rs: &[String],
    traits: &[String],
    builders: &[String],
) {
    let path = root_path.join("mod.rs");
    save_to_file(path, env.config.make_backup, |w| {
        general::start_comments(w, &env.config)?;
        general::write_vec(w, mod_rs)?;
        writeln!(w)?;
        writeln!(w, "#[doc(hidden)]")?;
        writeln!(w, "pub mod traits {{")?;
        general::write_vec(w, traits)?;
        writeln!(w, "}}")?;

        writeln!(w, "#[doc(hidden)]")?;
        writeln!(w, "pub mod builders {{")?;
        general::write_vec(w, builders)?;
        writeln!(w, "}}")
    });
}

pub fn generate_single_version_file(env: &Env) {
    if let Some(ref path) = env.config.single_version_file {
        save_to_file(path, env.config.make_backup, |w| {
            general::single_version_file(w, &env.config, "")
        });
    }
}
<commit_msg>codgen: don't generate traits/builders mod if they are empty<commit_after>use crate::{config::WorkMode, env::Env, file_saver::*};
use std::path::Path;

mod alias;
mod bound;
mod child_properties;
mod constants;
mod doc;
mod enums;
mod flags;
pub mod function;
mod function_body_chunk;
mod functions;
mod general;
mod object;
mod objects;
mod parameter;
mod properties;
mod property_body;
mod record;
mod records;
mod ref_mode;
mod return_value;
mod signal;
mod signal_body;
mod special_functions;
mod sys;
mod trait_impls;
mod trampoline;
mod trampoline_from_glib;
mod trampoline_to_glib;
pub mod translate_from_glib;
pub mod translate_to_glib;

pub fn generate(env: &Env) {
    match env.config.work_mode {
        WorkMode::Normal => normal_generate(env),
        WorkMode::Sys => sys::generate(env),
        WorkMode::Doc => doc::generate(env),
        WorkMode::DisplayNotBound => {}
    }
}

fn normal_generate(env: &Env) {
    let mut mod_rs: Vec<String> = Vec::new();
    let mut traits: Vec<String> = Vec::new();
    let mut builders: Vec<String> = Vec::new();
    let root_path = env.config.auto_path.as_path();

    generate_single_version_file(env);
    objects::generate(env, root_path, &mut mod_rs, &mut traits, &mut builders);
    records::generate(env, root_path, &mut mod_rs);
    enums::generate(env, root_path, &mut mod_rs);
    flags::generate(env, root_path, &mut mod_rs);
    alias::generate(env, root_path, &mut mod_rs);
    functions::generate(env, root_path, &mut mod_rs);
    constants::generate(env, root_path, &mut mod_rs);

    generate_mod_rs(env, root_path, &mod_rs, &traits, &builders);
}

pub fn generate_mod_rs(
    env: &Env,
    root_path: &Path,
    mod_rs: &[String],
    traits: &[String],
    builders: &[String],
) {
    let path = root_path.join("mod.rs");
    save_to_file(path, env.config.make_backup, |w| {
        general::start_comments(w, &env.config)?;
        general::write_vec(w, mod_rs)?;
        writeln!(w)?;
        if !traits.is_empty() {
            writeln!(w, "#[doc(hidden)]")?;
            writeln!(w, "pub mod traits {{")?;
            general::write_vec(w, traits)?;
            writeln!(w, "}}")?;
        }

        if !builders.is_empty() {
            writeln!(w, "#[doc(hidden)]")?;
            writeln!(w, "pub mod builders {{")?;
            general::write_vec(w, builders)?;
            writeln!(w, "}}")?;
        }
        Ok(())
    });
}

pub fn generate_single_version_file(env: &Env) {
    if let Some(ref path) = env.config.single_version_file {
        save_to_file(path, env.config.make_backup, |w| {
            general::single_version_file(w, &env.config, "")
        });
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core_foundation::base::{CFRelease, CFRetain, CFTypeID};
use foreign_types::ForeignType;

foreign_type! {
    #[doc(hidden)]
    type CType = ::sys::CGColorSpace;
    fn drop = |p| CFRelease(p as *mut _);
    fn clone = |p| CFRetain(p as *const _) as *mut _;
    pub struct CGColorSpace;
    pub struct CGColorSpaceRef;
}

impl CGColorSpace {
    pub fn type_id() -> CFTypeID {
        unsafe {
            CGColorSpaceGetTypeID()
        }
    }

    pub fn create_device_rgb() -> CGColorSpace {
        unsafe {
            let result = CGColorSpaceCreateDeviceRGB();
            CGColorSpace::from_ptr(result)
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    fn CGColorSpaceCreateDeviceRGB() -> ::sys::CGColorSpaceRef;
    fn CGColorSpaceGetTypeID() -> CFTypeID;
}

<commit_msg>Auto merge of #94 - pornel:cs, r=jdm<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core_foundation::base::{CFRelease, CFRetain, CFTypeID};
use core_foundation::string::CFStringRef;
use foreign_types::ForeignType;

foreign_type! {
    #[doc(hidden)]
    type CType = ::sys::CGColorSpace;
    fn drop = |p| CFRelease(p as *mut _);
    fn clone = |p| CFRetain(p as *const _) as *mut _;
    pub struct CGColorSpace;
    pub struct CGColorSpaceRef;
}

impl CGColorSpace {
    pub fn type_id() -> CFTypeID {
        unsafe {
            CGColorSpaceGetTypeID()
        }
    }

    pub fn create_with_name(name: CFStringRef) -> Option<CGColorSpace> {
        unsafe {
            let p = CGColorSpaceCreateWithName(name);
            if !p.is_null() {Some(CGColorSpace::from_ptr(p))} else {None}
        }
    }

    pub fn create_device_rgb() -> CGColorSpace {
        unsafe {
            let result = CGColorSpaceCreateDeviceRGB();
            CGColorSpace::from_ptr(result)
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    pub static kCGColorSpaceSRGB: CFStringRef;
    pub static kCGColorSpaceAdobeRGB1998: CFStringRef;
    pub static kCGColorSpaceGenericGray: CFStringRef;
    pub static kCGColorSpaceGenericRGB: CFStringRef;
    pub static kCGColorSpaceGenericCMYK: CFStringRef;
    pub static kCGColorSpaceGenericRGBLinear: CFStringRef;
    pub static kCGColorSpaceGenericGrayGamma2_2: CFStringRef;

    fn CGColorSpaceCreateDeviceRGB() -> ::sys::CGColorSpaceRef;
    fn CGColorSpaceCreateWithName(name: CFStringRef) -> ::sys::CGColorSpaceRef;
    fn CGColorSpaceGetTypeID() -> CFTypeID;
}

<|endoftext|>


<commit_before>extern crate libc;

extern crate emu;
extern crate spc;
extern crate snes_apu;

use std::sync::{Arc, Mutex};

use std::ffi::CStr;
use libc::{c_void, c_char};

use emu::audio_driver::AudioDriver;
use emu::core_audio_driver::CoreAudioDriver;

use spc::spc::{Spc, RAM_LEN};
use snes_apu::apu::{Apu, BUFFER_LEN};

struct ContextState {
    apu: Box<Apu>,
    spc: Option<Spc>
}

struct Context {
    state: Arc<Mutex<ContextState>>,
    _driver: CoreAudioDriver
}

impl Context {
    fn new() -> Context {
        let state = Arc::new(Mutex::new(ContextState {
            apu: Apu::new(),
            spc: None
        }));

        let mut driver = CoreAudioDriver::new();
        driver.set_sample_rate(32000);
        let render_callback_state = state.clone();
        let mut left = [0; BUFFER_LEN];
        let mut right = [0; BUFFER_LEN];
        driver.set_render_callback(Some(Box::new(move |buffer, num_frames| {
            render_callback_state.lock().unwrap().apu.render(&mut left, &mut right, num_frames as i32);
            for i in 0..num_frames {
                let j = i * 2;
                buffer[j + 0] = left[i] as f32 / 32768.0;
                buffer[j + 1] = right[i] as f32 / 32768.0;
            }
        })));

        Context {
            state: state,
            _driver: driver
        }
    }

    fn set_song(&mut self, spc: Option<Spc>) {
        let state = &mut self.state.lock().unwrap();
        state.apu.reset();
        if let Some(ref spc) = spc {
            state.apu.set_state(&spc);
        }
        state.spc = spc;
    }

    fn get_ram_snapshot(&mut self) -> Box<[u8; RAM_LEN]> {
        self.state.lock().unwrap().apu.get_ram_snapshot()
    }
}

#[no_mangle]
pub extern fn create_context() -> *mut c_void {
    Box::into_raw(Box::new(Context::new())) as *mut c_void
}

#[no_mangle]
pub extern fn free_context(context: *mut c_void) {
    unsafe { Box::from_raw(context as *mut Context) };
}

#[no_mangle]
pub extern fn set_song(context: *mut c_void, filename: *const c_char) {
    let context = unsafe { &mut *(context as *mut Context) };
    let spc = if filename.is_null() {
        None
    } else {
        let filename = unsafe { CStr::from_ptr(filename) }.to_str().unwrap();
        Some(Spc::load(filename).unwrap())
    };
    context.set_song(spc);
}

#[no_mangle]
pub extern fn get_ram_snapshot(context: *mut c_void) -> *mut u8 {
    let context = unsafe { &mut *(context as *mut Context) };
    let snapshot = context.get_ram_snapshot();
    Box::into_raw(snapshot) as *mut u8
}

#[no_mangle]
pub extern fn free_ram_snapshot(snapshot: *mut c_void) {
    unsafe { Box::from_raw(snapshot as *mut [u8; RAM_LEN]) };
}
<commit_msg>Echo buffer is now cleared when SPC's are loaded<commit_after>extern crate libc;

extern crate emu;
extern crate spc;
extern crate snes_apu;

use std::sync::{Arc, Mutex};

use std::ffi::CStr;
use libc::{c_void, c_char};

use emu::audio_driver::AudioDriver;
use emu::core_audio_driver::CoreAudioDriver;

use spc::spc::{Spc, RAM_LEN};
use snes_apu::apu::{Apu, BUFFER_LEN};

struct ContextState {
    apu: Box<Apu>,
    spc: Option<Spc>
}

struct Context {
    state: Arc<Mutex<ContextState>>,
    _driver: CoreAudioDriver
}

impl Context {
    fn new() -> Context {
        let state = Arc::new(Mutex::new(ContextState {
            apu: Apu::new(),
            spc: None
        }));

        let mut driver = CoreAudioDriver::new();
        driver.set_sample_rate(32000);
        let render_callback_state = state.clone();
        let mut left = [0; BUFFER_LEN];
        let mut right = [0; BUFFER_LEN];
        driver.set_render_callback(Some(Box::new(move |buffer, num_frames| {
            render_callback_state.lock().unwrap().apu.render(&mut left, &mut right, num_frames as i32);
            for i in 0..num_frames {
                let j = i * 2;
                buffer[j + 0] = left[i] as f32 / 32768.0;
                buffer[j + 1] = right[i] as f32 / 32768.0;
            }
        })));

        Context {
            state: state,
            _driver: driver
        }
    }

    fn set_song(&mut self, spc: Option<Spc>) {
        let state = &mut self.state.lock().unwrap();
        state.apu.reset();
        if let Some(ref spc) = spc {
            state.apu.set_state(&spc);
            state.apu.clear_echo_buffer();
        }
        state.spc = spc;
    }

    fn get_ram_snapshot(&mut self) -> Box<[u8; RAM_LEN]> {
        self.state.lock().unwrap().apu.get_ram_snapshot()
    }
}

#[no_mangle]
pub extern fn create_context() -> *mut c_void {
    Box::into_raw(Box::new(Context::new())) as *mut c_void
}

#[no_mangle]
pub extern fn free_context(context: *mut c_void) {
    unsafe { Box::from_raw(context as *mut Context) };
}

#[no_mangle]
pub extern fn set_song(context: *mut c_void, filename: *const c_char) {
    let context = unsafe { &mut *(context as *mut Context) };
    let spc = if filename.is_null() {
        None
    } else {
        let filename = unsafe { CStr::from_ptr(filename) }.to_str().unwrap();
        Some(Spc::load(filename).unwrap())
    };
    context.set_song(spc);
}

#[no_mangle]
pub extern fn get_ram_snapshot(context: *mut c_void) -> *mut u8 {
    let context = unsafe { &mut *(context as *mut Context) };
    let snapshot = context.get_ram_snapshot();
    Box::into_raw(snapshot) as *mut u8
}

#[no_mangle]
pub extern fn free_ram_snapshot(snapshot: *mut c_void) {
    unsafe { Box::from_raw(snapshot as *mut [u8; RAM_LEN]) };
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::*;
use std::collections::*;
use std::ops::*;
use procon::*;

pub fn main() {
    return;
}

pub mod procon {
    use std;
    use std::collections::*;
    use std::io;
    use std::mem;
    use std::str::FromStr;

    pub fn read_line() -> String {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim_right().to_owned()
    }

    pub fn read_words<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.split_whitespace()
            .map(|word| T::from_str(word).unwrap())
            .collect()
    }

    pub fn read_vec(len: usize) -> Vec<String> {
        let mut vec = Vec::new();
        while vec.len() < len {
            let line = read_line();
            for word in line.split_whitespace() {
                vec.push(word.to_owned());
            }
        }
        assert!(vec.len() == len);
        vec
    }
}
<commit_msg>Sort use directives<commit_after>#![allow(unused_imports)]
#![allow(non_snake_case)]

use procon::*;
use std::collections::*;
use std::ops::*;
use std::*;

pub fn main() {
    return;
}

pub mod procon {
    use std;
    use std::collections::*;
    use std::io;
    use std::mem;
    use std::str::FromStr;

    pub fn read_line() -> String {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim_right().to_owned()
    }

    pub fn read_words<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.split_whitespace()
            .map(|word| T::from_str(word).unwrap())
            .collect()
    }

    pub fn read_vec(len: usize) -> Vec<String> {
        let mut vec = Vec::new();
        while vec.len() < len {
            let line = read_line();
            for word in line.split_whitespace() {
                vec.push(word.to_owned());
            }
        }
        assert!(vec.len() == len);
        vec
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use futures_util::{
    future::FutureExt,
    stream::{StreamExt, StreamFuture},
};
use pin_project::pin_project;
use tokio::time::{self, Interval};

use std::{
    future::Future,
    sync::{atomic::Ordering, Arc},
};

use super::Inner;
use crate::{prelude::Queryable, PoolOptions};
use futures_core::task::{Context, Poll};
use std::pin::Pin;

/// Idling connections TTL check interval.
///
/// The purpose of this interval is to remove idling connections that both:
/// * overflows min bound of the pool;
/// * idles longer then `inactive_connection_ttl`.
#[pin_project]
pub struct TtlCheckInterval {
    inner: Arc<Inner>,
    #[pin]
    interval: StreamFuture<Interval>,
    pool_options: PoolOptions,
}

impl TtlCheckInterval {
    /// Creates new `TtlCheckInterval`.
    pub fn new(pool_options: PoolOptions, inner: Arc<Inner>) -> Self {
        let interval = time::interval(pool_options.ttl_check_interval()).into_future();
        Self {
            inner,
            interval,
            pool_options,
        }
    }

    /// Perform the check.
    pub fn check_ttl(&self) {
        let mut exchange = self.inner.exchange.lock().unwrap();

        let num_idling = exchange.available.len();
        let num_to_drop = num_idling.saturating_sub(self.pool_options.constraints().min());

        for _ in 0..num_to_drop {
            let idling_conn = exchange.available.pop_front().unwrap();
            if idling_conn.elapsed() > self.pool_options.inactive_connection_ttl() {
                assert!(idling_conn.conn.inner.pool.is_none());
                tokio::spawn(idling_conn.conn.disconnect().map(drop));
                exchange.exist -= 1;
            } else {
                exchange.available.push_back(idling_conn);
            }
        }
    }
}

impl Future for TtlCheckInterval {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            let (_, interval) = futures_core::ready!(self.as_mut().project().interval.poll(cx));
            let close = self.inner.close.load(Ordering::Acquire);

            if !close {
                self.check_ttl();
                self.interval = interval.into_future();
            } else {
                return Poll::Ready(());
            }
        }
    }
}
<commit_msg>Decrement exchange.exist when expired connection is actually disconnected<commit_after>// Copyright (c) 2019 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use futures_util::{
    future::{ok, FutureExt},
    stream::{StreamExt, StreamFuture},
};
use pin_project::pin_project;
use tokio::time::{self, Interval};

use std::{
    future::Future,
    sync::{atomic::Ordering, Arc},
};

use super::Inner;
use crate::{prelude::Queryable, PoolOptions};
use futures_core::task::{Context, Poll};
use std::pin::Pin;

/// Idling connections TTL check interval.
///
/// The purpose of this interval is to remove idling connections that both:
/// * overflows min bound of the pool;
/// * idles longer then `inactive_connection_ttl`.
#[pin_project]
pub struct TtlCheckInterval {
    inner: Arc<Inner>,
    #[pin]
    interval: StreamFuture<Interval>,
    pool_options: PoolOptions,
}

impl TtlCheckInterval {
    /// Creates new `TtlCheckInterval`.
    pub fn new(pool_options: PoolOptions, inner: Arc<Inner>) -> Self {
        let interval = time::interval(pool_options.ttl_check_interval()).into_future();
        Self {
            inner,
            interval,
            pool_options,
        }
    }

    /// Perform the check.
    pub fn check_ttl(&self) {
        let mut exchange = self.inner.exchange.lock().unwrap();

        let num_idling = exchange.available.len();
        let num_to_drop = num_idling.saturating_sub(self.pool_options.constraints().min());

        for _ in 0..num_to_drop {
            let idling_conn = exchange.available.pop_front().unwrap();
            if idling_conn.elapsed() > self.pool_options.inactive_connection_ttl() {
                assert!(idling_conn.conn.inner.pool.is_none());
                let inner = self.inner.clone();
                tokio::spawn(idling_conn.conn.disconnect().then(move |_| {
                    let mut exchange = inner.exchange.lock().unwrap();
                    exchange.exist -= 1;
                    ok::<_, ()>(())
                }));
            } else {
                exchange.available.push_back(idling_conn);
            }
        }
    }
}

impl Future for TtlCheckInterval {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            let (_, interval) = futures_core::ready!(self.as_mut().project().interval.poll(cx));
            let close = self.inner.close.load(Ordering::Acquire);

            if !close {
                self.check_ttl();
                self.interval = interval.into_future();
            } else {
                return Poll::Ready(());
            }
        }
    }
}
<|endoftext|>