<commit_before>//! Abstractions for the replies passed back from i3.

use std::collections::HashMap;

/// The outcome of a single command.
#[derive(Debug)]
pub struct CommandOutcome {
    /// Whether the command was successful.
    pub success: bool,
    /// A human-readable error message.
    pub error: Option<String>,
}

/// The reply to the `command` request.
#[derive(Debug)]
pub struct Command {
    /// A list of `CommandOutcome` structs; one for each command that was parsed.
    pub outcomes: Vec<CommandOutcome>,
}

/// A single workspace.
#[derive(Debug)]
pub struct Workspace {
    /// The logical number of the workspace. Corresponds to the command to switch to this
    /// workspace. For named workspaces, this will be -1.
    pub num: i32,
    /// The name of this workspace (by default num+1), as changed by the user.
    pub name: String,
    /// Whether this workspace is currently visible on an output (multiple workspaces can be
    /// visible at the same time).
    pub visible: bool,
    /// Whether this workspace currently has the focus (only one workspace can have the focus
    /// at the same time).
    pub focused: bool,
    /// Whether a window on this workspace has the "urgent" flag set.
    pub urgent: bool,
    /// The rectangle of this workspace (equals the rect of the output it is on), consists of
    /// x, y, width, height.
    pub rect: (i32, i32, i32, i32),
    /// The video output this workspace is on (LVDS1, VGA1, …).
    pub output: String,
}

/// The reply to the `get_workspaces` request.
#[derive(Debug)]
pub struct Workspaces {
    /// A list of workspaces.
    pub workspaces: Vec<Workspace>,
}

/// The reply to the `subscribe` request.
#[derive(Debug)]
pub struct Subscribe {
    /// Indicates whether the subscription was successful (the default) or whether a JSON
    /// parse error occurred.
    pub success: bool,
}

/// A single output (display)
#[derive(Debug)]
pub struct Output {
    /// The name of this output (as seen in xrandr).
    pub name: String,
    /// Whether the output is currently active (has a valid mode).
    pub active: bool,
    /// Whether the output is currently the primary output.
    pub primary: bool,
    /// The name of the current workspace that is visible on this output. None if the output is
    /// not active.
    pub current_workspace: Option<String>,
    /// The rectangle of this output (equals the rect of the output it is on), consists of
    /// x, y, width, height.
    pub rect: (i32, i32, i32, i32),
}

/// The reply to the `get_outputs` request.
#[derive(Debug)]
pub struct Outputs {
    /// A list of outputs (displays)
    pub outputs: Vec<Output>,
}

#[derive(Eq, PartialEq, Debug)]
pub enum NodeType {
    Root,
    Output,
    Con,
    FloatingCon,
    Workspace,
    DockArea,
    /// A NodeType we don't support yet.
    Unknown,
}

#[derive(Eq, PartialEq, Debug)]
pub enum NodeBorder {
    Normal,
    None,
    Pixel,
    /// A NodeBorder we don't support yet.
    Unknown,
}

#[derive(Eq, PartialEq, Debug)]
pub enum NodeLayout {
    SplitH,
    SplitV,
    Stacked,
    Tabbed,
    DockArea,
    Output,
    /// A NodeLayout we don't support yet.
    Unknown,
}

/// The reply to the `get_tree` request.
#[derive(Debug)]
pub struct Node {
    /// List of child node IDs (see `nodes`, `floating_nodes` and `id`) in focus order. Traversing
    /// the tree by following the first entry in this array will result in eventually reaching the
    /// one node with `focused` set to true.
    pub focus: Vec<i64>,

    /// The child nodes of this container.
    pub nodes: Vec<Node>,

    /// The child floating nodes of this container.
    pub floating_nodes: Vec<Node>,

    /// The internal ID (actually a C pointer value) of this container. Do not make any
    /// assumptions about it. You can use it to (re-)identify and address containers when
    /// talking to i3.
    pub id: i64,

    /// The internal name of this container. For all containers which are part of the tree
    /// structure down to the workspace contents, this is set to a nice human-readable name of
    /// the container. For containers that have an X11 window, the content is the title
    /// (_NET_WM_NAME property) of that window. For all other containers, the content is not
    /// defined (yet).
    pub name: Option<String>,

    /// Type of this container. Can be one of "root", "output", "con", "floating_con",
    /// "workspace" or "dockarea".
    pub nodetype: NodeType,

    /// Can be either "normal", "none" or "1pixel", dependending on the container’s border
    /// style.
    pub border: NodeBorder,

    /// Number of pixels of the border width.
    pub current_border_width: i32,

    /// Can be either "splith", "splitv", "stacked", "tabbed", "dockarea" or "output". Other values
    /// might be possible in the future, should we add new layouts.
    pub layout: NodeLayout,

    /// The percentage which this container takes in its parent. A value of null means that the
    /// percent property does not make sense for this container, for example for the root
    /// container.
    pub percent: Option<f64>,

    /// The (x, y, width, height) absolute display coordinates for this container. Display
    /// coordinates means that when you have two 1600x1200 monitors on a single X11 Display
    /// (the standard way), the coordinates of the first window on the second monitor are
    /// (1600, 0, 1600, 1200).
    pub rect: (i32, i32, i32, i32),

    /// The (x, y, width, height) coordinates of the actual client window inside its container.
    /// These coordinates are  relative to the container and do not include the window
    /// decoration (which is actually rendered on the parent container). So for example, when
    /// using the default layout, you will have a 2 pixel border on each side, making the
    /// window_rect (2, 0, 632, 366).
    pub window_rect: (i32, i32, i32, i32),

    /// The (x, y, width, height) coordinates of the window decoration inside its container.
    /// These coordinates are relative to the container and do not include the actual client
    /// window.
    pub deco_rect: (i32, i32, i32, i32),

    /// The original geometry the window specified when i3 mapped it. Used when switching a
    /// window to floating mode, for example.
    pub geometry: (i32, i32, i32, i32),

    /// The X11 window ID of the actual client window inside this container. This field is set
    /// to null for split containers or otherwise empty containers. This ID corresponds to what
    /// xwininfo(1) and other X11-related tools display (usually in hex).
    pub window: Option<i32>,

    /// Whether this container (window, split container, floating container or workspace) has the
    /// urgency hint set, directly or indirectly. All parent containers up until the workspace
    /// container will be marked urgent if they have at least one urgent child.
    pub urgent: bool,

    /// Whether this container is currently focused.
    pub focused: bool,
}

/// The reply to the `get_marks` request.
///
/// Consists of a single vector of strings for each container that has a mark. A mark can only
/// be set on one container, so the vector is unique. The order of that vector is undefined. If
/// no window has a mark the response will be an empty vector.
#[derive(Debug)]
pub struct Marks {
    pub marks: Vec<String>,
}

/// The reply to the `get_bar_ids` request.
///
/// This can be used by third-party workspace bars (especially i3bar, but others are free to
/// implement compatible alternatives) to get the bar block configuration from i3.
#[derive(Debug)]
pub struct BarIds {
    /// A vector of configured bar IDs.
    pub ids: Vec<String>,
}

#[derive(Hash, Eq, PartialEq, Debug)]
pub enum ColorableBarPart {
    /// Background color of the bar.
    Background,

    /// Text color to be used for the statusline.
    Statusline,

    /// Text color to be used for the separator.
    Separator,

    /// Background color of the bar on the currently focused monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedBackground,

    /// Text color to be used for the statusline on the currently focused
    /// monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedStatusline,

    /// Text color to be used for the separator on the currently focused
    /// monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedSeparator,

    /// Text color for a workspace button when the workspace has focus.
    FocusedWorkspaceText,

    /// Background color for a workspace button when the workspace has focus.
    FocusedWorkspaceBg,

    /// Border color for a workspace button when the workspace has focus.
    FocusedWorkspaceBorder,

    /// Text color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceText,

    /// Background color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceBg,

    /// Border color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceBorder,

    /// Text color for a workspace button when the workspace does not have focus and is not
    /// active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceText,

    /// Background color for a workspace button when the workspace does not have focus and is
    /// not active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceBg,

    /// Border color for a workspace button when the workspace does not have focus and is
    /// not active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceBorder,

    /// Text color for workspaces which contain at least one window with the urgency hint set.
    UrgentWorkspaceText,

    /// Background color for workspaces which contain at least one window with the urgency hint
    /// set.
    UrgentWorkspaceBg,

    /// Border color for workspaces which contain at least one window with the urgency hint set.
    UrgentWorkspaceBorder,

    /// Text color for the binding mode indicator.
    BindingModeText,

    /// Background color for the binding mode indicator.
    BindingModeBg,

    /// Border color for the binding mode indicator.
    BindingModeBorder,

    /// A ColorableBarPart we don't support yet.
    Unknown,
}

/// The reply to the `get_bar_config` request.
///
/// This can be used by third-party workspace bars (especially i3bar, but others are free to
/// implement compatible alternatives) to get the bar block configuration from i3.
#[derive(Debug)]
pub struct BarConfig {
    /// The ID for this bar. Included in case you request multiple configurations and want to
    /// differentiate the different replies.
    pub id: String,

    /// Either dock (the bar sets the dock window type) or hide (the bar does not show unless a
    /// specific key is pressed).
    pub mode: String,

    /// Either bottom or top at the moment.
    pub position: String,

    /// Command which will be run to generate a statusline. Each line on stdout of this command
    /// will be displayed in the bar. At the moment, no formatting is supported.
    pub status_command: String,

    /// The font to use for text on the bar.
    pub font: String,

    /// Display workspace buttons or not? Defaults to true.
    pub workspace_buttons: bool,

    /// Display the mode indicator or not? Defaults to true.
    pub binding_mode_indicator: bool,

    /// Should the bar enable verbose output for debugging? Defaults to false.
    pub verbose: bool,

    /// Contains key/value pairs of colors. Each value is a color code in hex, formatted
    /// \#rrggbb (like in HTML).
    pub colors: HashMap<ColorableBarPart, String>,
}

/// The reply to the `get_version` request.
#[derive(Debug)]
pub struct Version {
    /// The major version of i3, such as 4.
    pub major: i32,

    /// The minor version of i3, such as 2. Changes in the IPC interface (new features) will
    /// only occur with new minor (or major) releases. However, bugfixes might be introduced in
    /// patch releases, too.
    pub minor: i32,

    /// The patch version of i3, such as 1 (when the complete version is 4.2.1). For versions
    /// such as 4.2, patch will be set to 0.
    pub patch: i32,

    /// A human-readable version of i3 containing the precise git version, build date and
    /// branch name. When you need to display the i3 version to your users, use the
    /// human-readable version whenever possible (since this is what i3 --version displays,
    /// too).
    pub human_readable: String,

    /// The current config path.
    pub loaded_config_file_name: String,
}

/// The reply to the `get_binding_modes` request.
#[cfg(feature = "i3-4-13")]
#[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-13")))]
#[derive(Debug)]
pub struct BindingModes {
    /// A vector of all currently configured binding modes.
    pub modes: Vec<String>,
}

/// The reply to the `get_config` request.
#[cfg(feature = "i3-4-14")]
#[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-14")))]
#[derive(Debug)]
pub struct Config {
    /// A string containing the config file as loaded by i3 most recently.
    pub config: String,
}
<commit_msg>make Node Clone-able<commit_after>//! Abstractions for the replies passed back from i3.

use std::collections::HashMap;

/// The outcome of a single command.
#[derive(Debug)]
pub struct CommandOutcome {
    /// Whether the command was successful.
    pub success: bool,
    /// A human-readable error message.
    pub error: Option<String>,
}

/// The reply to the `command` request.
#[derive(Debug)]
pub struct Command {
    /// A list of `CommandOutcome` structs; one for each command that was parsed.
    pub outcomes: Vec<CommandOutcome>,
}

/// A single workspace.
#[derive(Debug)]
pub struct Workspace {
    /// The logical number of the workspace. Corresponds to the command to switch to this
    /// workspace. For named workspaces, this will be -1.
    pub num: i32,
    /// The name of this workspace (by default num+1), as changed by the user.
    pub name: String,
    /// Whether this workspace is currently visible on an output (multiple workspaces can be
    /// visible at the same time).
    pub visible: bool,
    /// Whether this workspace currently has the focus (only one workspace can have the focus
    /// at the same time).
    pub focused: bool,
    /// Whether a window on this workspace has the "urgent" flag set.
    pub urgent: bool,
    /// The rectangle of this workspace (equals the rect of the output it is on), consists of
    /// x, y, width, height.
    pub rect: (i32, i32, i32, i32),
    /// The video output this workspace is on (LVDS1, VGA1, …).
    pub output: String,
}

/// The reply to the `get_workspaces` request.
#[derive(Debug)]
pub struct Workspaces {
    /// A list of workspaces.
    pub workspaces: Vec<Workspace>,
}

/// The reply to the `subscribe` request.
#[derive(Debug)]
pub struct Subscribe {
    /// Indicates whether the subscription was successful (the default) or whether a JSON
    /// parse error occurred.
    pub success: bool,
}

/// A single output (display)
#[derive(Debug)]
pub struct Output {
    /// The name of this output (as seen in xrandr).
    pub name: String,
    /// Whether the output is currently active (has a valid mode).
    pub active: bool,
    /// Whether the output is currently the primary output.
    pub primary: bool,
    /// The name of the current workspace that is visible on this output. None if the output is
    /// not active.
    pub current_workspace: Option<String>,
    /// The rectangle of this output (equals the rect of the output it is on), consists of
    /// x, y, width, height.
    pub rect: (i32, i32, i32, i32),
}

/// The reply to the `get_outputs` request.
#[derive(Debug)]
pub struct Outputs {
    /// A list of outputs (displays)
    pub outputs: Vec<Output>,
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub enum NodeType {
    Root,
    Output,
    Con,
    FloatingCon,
    Workspace,
    DockArea,
    /// A NodeType we don't support yet.
    Unknown,
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub enum NodeBorder {
    Normal,
    None,
    Pixel,
    /// A NodeBorder we don't support yet.
    Unknown,
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub enum NodeLayout {
    SplitH,
    SplitV,
    Stacked,
    Tabbed,
    DockArea,
    Output,
    /// A NodeLayout we don't support yet.
    Unknown,
}

/// The reply to the `get_tree` request.
#[derive(Debug, Clone)]
pub struct Node {
    /// List of child node IDs (see `nodes`, `floating_nodes` and `id`) in focus order. Traversing
    /// the tree by following the first entry in this array will result in eventually reaching the
    /// one node with `focused` set to true.
    pub focus: Vec<i64>,

    /// The child nodes of this container.
    pub nodes: Vec<Node>,

    /// The child floating nodes of this container.
    pub floating_nodes: Vec<Node>,

    /// The internal ID (actually a C pointer value) of this container. Do not make any
    /// assumptions about it. You can use it to (re-)identify and address containers when
    /// talking to i3.
    pub id: i64,

    /// The internal name of this container. For all containers which are part of the tree
    /// structure down to the workspace contents, this is set to a nice human-readable name of
    /// the container. For containers that have an X11 window, the content is the title
    /// (_NET_WM_NAME property) of that window. For all other containers, the content is not
    /// defined (yet).
    pub name: Option<String>,

    /// Type of this container. Can be one of "root", "output", "con", "floating_con",
    /// "workspace" or "dockarea".
    pub nodetype: NodeType,

    /// Can be either "normal", "none" or "1pixel", dependending on the container’s border
    /// style.
    pub border: NodeBorder,

    /// Number of pixels of the border width.
    pub current_border_width: i32,

    /// Can be either "splith", "splitv", "stacked", "tabbed", "dockarea" or "output". Other values
    /// might be possible in the future, should we add new layouts.
    pub layout: NodeLayout,

    /// The percentage which this container takes in its parent. A value of null means that the
    /// percent property does not make sense for this container, for example for the root
    /// container.
    pub percent: Option<f64>,

    /// The (x, y, width, height) absolute display coordinates for this container. Display
    /// coordinates means that when you have two 1600x1200 monitors on a single X11 Display
    /// (the standard way), the coordinates of the first window on the second monitor are
    /// (1600, 0, 1600, 1200).
    pub rect: (i32, i32, i32, i32),

    /// The (x, y, width, height) coordinates of the actual client window inside its container.
    /// These coordinates are  relative to the container and do not include the window
    /// decoration (which is actually rendered on the parent container). So for example, when
    /// using the default layout, you will have a 2 pixel border on each side, making the
    /// window_rect (2, 0, 632, 366).
    pub window_rect: (i32, i32, i32, i32),

    /// The (x, y, width, height) coordinates of the window decoration inside its container.
    /// These coordinates are relative to the container and do not include the actual client
    /// window.
    pub deco_rect: (i32, i32, i32, i32),

    /// The original geometry the window specified when i3 mapped it. Used when switching a
    /// window to floating mode, for example.
    pub geometry: (i32, i32, i32, i32),

    /// The X11 window ID of the actual client window inside this container. This field is set
    /// to null for split containers or otherwise empty containers. This ID corresponds to what
    /// xwininfo(1) and other X11-related tools display (usually in hex).
    pub window: Option<i32>,

    /// Whether this container (window, split container, floating container or workspace) has the
    /// urgency hint set, directly or indirectly. All parent containers up until the workspace
    /// container will be marked urgent if they have at least one urgent child.
    pub urgent: bool,

    /// Whether this container is currently focused.
    pub focused: bool,
}

/// The reply to the `get_marks` request.
///
/// Consists of a single vector of strings for each container that has a mark. A mark can only
/// be set on one container, so the vector is unique. The order of that vector is undefined. If
/// no window has a mark the response will be an empty vector.
#[derive(Debug)]
pub struct Marks {
    pub marks: Vec<String>,
}

/// The reply to the `get_bar_ids` request.
///
/// This can be used by third-party workspace bars (especially i3bar, but others are free to
/// implement compatible alternatives) to get the bar block configuration from i3.
#[derive(Debug)]
pub struct BarIds {
    /// A vector of configured bar IDs.
    pub ids: Vec<String>,
}

#[derive(Hash, Eq, PartialEq, Debug)]
pub enum ColorableBarPart {
    /// Background color of the bar.
    Background,

    /// Text color to be used for the statusline.
    Statusline,

    /// Text color to be used for the separator.
    Separator,

    /// Background color of the bar on the currently focused monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedBackground,

    /// Text color to be used for the statusline on the currently focused
    /// monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedStatusline,

    /// Text color to be used for the separator on the currently focused
    /// monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedSeparator,

    /// Text color for a workspace button when the workspace has focus.
    FocusedWorkspaceText,

    /// Background color for a workspace button when the workspace has focus.
    FocusedWorkspaceBg,

    /// Border color for a workspace button when the workspace has focus.
    FocusedWorkspaceBorder,

    /// Text color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceText,

    /// Background color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceBg,

    /// Border color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceBorder,

    /// Text color for a workspace button when the workspace does not have focus and is not
    /// active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceText,

    /// Background color for a workspace button when the workspace does not have focus and is
    /// not active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceBg,

    /// Border color for a workspace button when the workspace does not have focus and is
    /// not active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceBorder,

    /// Text color for workspaces which contain at least one window with the urgency hint set.
    UrgentWorkspaceText,

    /// Background color for workspaces which contain at least one window with the urgency hint
    /// set.
    UrgentWorkspaceBg,

    /// Border color for workspaces which contain at least one window with the urgency hint set.
    UrgentWorkspaceBorder,

    /// Text color for the binding mode indicator.
    BindingModeText,

    /// Background color for the binding mode indicator.
    BindingModeBg,

    /// Border color for the binding mode indicator.
    BindingModeBorder,

    /// A ColorableBarPart we don't support yet.
    Unknown,
}

/// The reply to the `get_bar_config` request.
///
/// This can be used by third-party workspace bars (especially i3bar, but others are free to
/// implement compatible alternatives) to get the bar block configuration from i3.
#[derive(Debug)]
pub struct BarConfig {
    /// The ID for this bar. Included in case you request multiple configurations and want to
    /// differentiate the different replies.
    pub id: String,

    /// Either dock (the bar sets the dock window type) or hide (the bar does not show unless a
    /// specific key is pressed).
    pub mode: String,

    /// Either bottom or top at the moment.
    pub position: String,

    /// Command which will be run to generate a statusline. Each line on stdout of this command
    /// will be displayed in the bar. At the moment, no formatting is supported.
    pub status_command: String,

    /// The font to use for text on the bar.
    pub font: String,

    /// Display workspace buttons or not? Defaults to true.
    pub workspace_buttons: bool,

    /// Display the mode indicator or not? Defaults to true.
    pub binding_mode_indicator: bool,

    /// Should the bar enable verbose output for debugging? Defaults to false.
    pub verbose: bool,

    /// Contains key/value pairs of colors. Each value is a color code in hex, formatted
    /// \#rrggbb (like in HTML).
    pub colors: HashMap<ColorableBarPart, String>,
}

/// The reply to the `get_version` request.
#[derive(Debug)]
pub struct Version {
    /// The major version of i3, such as 4.
    pub major: i32,

    /// The minor version of i3, such as 2. Changes in the IPC interface (new features) will
    /// only occur with new minor (or major) releases. However, bugfixes might be introduced in
    /// patch releases, too.
    pub minor: i32,

    /// The patch version of i3, such as 1 (when the complete version is 4.2.1). For versions
    /// such as 4.2, patch will be set to 0.
    pub patch: i32,

    /// A human-readable version of i3 containing the precise git version, build date and
    /// branch name. When you need to display the i3 version to your users, use the
    /// human-readable version whenever possible (since this is what i3 --version displays,
    /// too).
    pub human_readable: String,

    /// The current config path.
    pub loaded_config_file_name: String,
}

/// The reply to the `get_binding_modes` request.
#[cfg(feature = "i3-4-13")]
#[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-13")))]
#[derive(Debug)]
pub struct BindingModes {
    /// A vector of all currently configured binding modes.
    pub modes: Vec<String>,
}

/// The reply to the `get_config` request.
#[cfg(feature = "i3-4-14")]
#[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-14")))]
#[derive(Debug)]
pub struct Config {
    /// A string containing the config file as loaded by i3 most recently.
    pub config: String,
}
<|endoftext|>


<commit_before>//! Abstractions for the replies passed back from i3.

use std::collections::HashMap;

/// The outcome of a single command.
#[derive(Debug)]
pub struct CommandOutcome {
    /// Whether the command was successful.
    pub success: bool,
    /// A human-readable error message.
    pub error: Option<String>
}

/// The reply to the `command` request.
#[derive(Debug)]
pub struct Command {
    /// A list of `CommandOutcome` structs; one for each command that was parsed.
    pub outcomes: Vec<CommandOutcome>
}

/// A single workspace.
#[derive(Debug)]
pub struct Workspace {
    /// The logical number of the workspace. Corresponds to the command to switch to this
    /// workspace. For named workspaces, this will be -1.
    pub num: i32,
    /// The name of this workspace (by default num+1), as changed by the user.
    pub name: String,
    /// Whether this workspace is currently visible on an output (multiple workspaces can be
    /// visible at the same time).
    pub visible: bool,
    /// Whether this workspace currently has the focus (only one workspace can have the focus
    /// at the same time).
    pub focused: bool,
    /// Whether a window on this workspace has the "urgent" flag set.
    pub urgent: bool,
    /// The rectangle of this workspace (equals the rect of the output it is on), consists of
    /// x, y, width, height.
    pub rect: (i32, i32, i32, i32),
    /// The video output this workspace is on (LVDS1, VGA1, …).
    pub output: String
}

/// The reply to the `get_workspaces` request.
#[derive(Debug)]
pub struct Workspaces {
    /// A list of workspaces.
    pub workspaces: Vec<Workspace>,
}

/// The reply to the `subscribe` request.
#[derive(Debug)]
pub struct Subscribe {
    /// Indicates whether the subscription was successful (the default) or whether a JSON
    /// parse error occurred.
    pub success: bool,
}

/// A single output (display)
#[derive(Debug)]
pub struct Output {
    /// The name of this output (as seen in xrandr).
    pub name: String,
    /// Whether the output is currently active (has a valid mode).
    pub active: bool,
    /// Whether the output is currently the primary output.
    pub primary: bool,
    /// The name of the current workspace that is visible on this output. None if the output is
    /// not active.
    pub current_workspace: Option<String>,
    /// The rectangle of this output (equals the rect of the output it is on), consists of
    /// x, y, width, height.
    pub rect: (i32, i32, i32, i32)
}

/// The reply to the `get_outputs` request.
#[derive(Debug)]
pub struct Outputs {
    /// A list of outputs (displays)
    pub outputs: Vec<Output>
}

#[derive(Debug)]
pub enum NodeType {
    Root,
    Output,
    Con,
    FloatingCon,
    Workspace,
    DockArea,
    /// A NodeType we don't support yet.
    Unknown,
}

#[derive(Debug)]
pub enum NodeBorder {
    Normal,
    None,
    Pixel,
    /// A NodeBorder we don't support yet.
    Unknown,
}

#[derive(Debug)]
pub enum NodeLayout {
    SplitH,
    SplitV,
    Stacked,
    Tabbed,
    DockArea,
    Output,
    /// A NodeLayout we don't support yet.
    Unknown,
}

/// The reply to the `get_tree` request.
#[derive(Debug)]
pub struct Node {
    /// List of child node IDs (see `nodes`, `floating_nodes` and `id`) in focus order. Traversing
    /// the tree by following the first entry in this array will result in eventually reaching the
    /// one node with `focused` set to true.
    pub focus: Vec<i64>,

    /// The child nodes of this container.
    pub nodes: Vec<Node>,

    /// The child floating nodes of this container.
    pub floating_nodes: Vec<Node>,

    /// The internal ID (actually a C pointer value) of this container. Do not make any
    /// assumptions about it. You can use it to (re-)identify and address containers when
    /// talking to i3.
    pub id: i64,

    /// The internal name of this container. For all containers which are part of the tree
    /// structure down to the workspace contents, this is set to a nice human-readable name of
    /// the container. For containers that have an X11 window, the content is the title
    /// (_NET_WM_NAME property) of that window. For all other containers, the content is not
    /// defined (yet).
    pub name: Option<String>,

    /// Type of this container. Can be one of "root", "output", "con", "floating_con",
    /// "workspace" or "dockarea".
    pub nodetype: NodeType,

    /// Can be either "normal", "none" or "1pixel", dependending on the container’s border
    /// style.
    pub border: NodeBorder,

    /// Number of pixels of the border width.
    pub current_border_width: i32,

    /// Can be either "splith", "splitv", "stacked", "tabbed", "dockarea" or "output". Other values
    /// might be possible in the future, should we add new layouts.
    pub layout: NodeLayout,

    /// The percentage which this container takes in its parent. A value of null means that the
    /// percent property does not make sense for this container, for example for the root
    /// container.
    pub percent: Option<f64>,

    /// The (x, y, width, height) absolute display coordinates for this container. Display
    /// coordinates means that when you have two 1600x1200 monitors on a single X11 Display
    /// (the standard way), the coordinates of the first window on the second monitor are
    /// (1600, 0, 1600, 1200).
    pub rect: (i32, i32, i32, i32),

    /// The (x, y, width, height) coordinates of the actual client window inside its container.
    /// These coordinates are  relative to the container and do not include the window
    /// decoration (which is actually rendered on the parent container). So for example, when
    /// using the default layout, you will have a 2 pixel border on each side, making the
    /// window_rect (2, 0, 632, 366).
    pub window_rect: (i32, i32, i32, i32),

    /// The (x, y, width, height) coordinates of the window decoration inside its container.
    /// These coordinates are relative to the container and do not include the actual client
    /// window.
    pub deco_rect: (i32, i32, i32, i32),

    /// The original geometry the window specified when i3 mapped it. Used when switching a
    /// window to floating mode, for example.
    pub geometry: (i32, i32, i32, i32),

    /// The X11 window ID of the actual client window inside this container. This field is set
    /// to null for split containers or otherwise empty containers. This ID corresponds to what
    /// xwininfo(1) and other X11-related tools display (usually in hex).
    pub window: Option<i32>,

    /// Whether this container (window, split container, floating container or workspace) has the
    /// urgency hint set, directly or indirectly. All parent containers up until the workspace
    /// container will be marked urgent if they have at least one urgent child.
    pub urgent: bool,

    /// Whether this container is currently focused.
    pub focused: bool,
}

/// The reply to the `get_marks` request.
///
/// Consists of a single vector of strings for each container that has a mark. A mark can only
/// be set on one container, so the vector is unique. The order of that vector is undefined. If
/// no window has a mark the response will be an empty vector.
#[derive(Debug)]
pub struct Marks {
    pub marks: Vec<String>
}

/// The reply to the `get_bar_ids` request.
///
/// This can be used by third-party workspace bars (especially i3bar, but others are free to
/// implement compatible alternatives) to get the bar block configuration from i3.
#[derive(Debug)]
pub struct BarIds {
    /// A vector of configured bar IDs.
    pub ids: Vec<String>
}

#[derive(Hash, Eq, PartialEq, Debug)]
pub enum ColorableBarPart {
    /// Background color of the bar.
    Background,

    /// Text color to be used for the statusline.
    Statusline,

    /// Text color to be used for the separator.
    Separator,

    /// Background color of the bar on the currently focused monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedBackground,

    /// Text color to be used for the statusline on the currently focused
    /// monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedStatusline,

    /// Text color to be used for the separator on the currently focused
    /// monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedSeparator,

    /// Text color for a workspace button when the workspace has focus.
    FocusedWorkspaceText,

    /// Background color for a workspace button when the workspace has focus.
    FocusedWorkspaceBg,

    /// Border color for a workspace button when the workspace has focus.
    FocusedWorkspaceBorder,

    /// Text color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceText,

    /// Background color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceBg,

    /// Border color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceBorder,

    /// Text color for a workspace button when the workspace does not have focus and is not
    /// active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceText,

    /// Background color for a workspace button when the workspace does not have focus and is
    /// not active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceBg,

    /// Border color for a workspace button when the workspace does not have focus and is
    /// not active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceBorder,

    /// Text color for workspaces which contain at least one window with the urgency hint set.
    UrgentWorkspaceText,

    /// Background color for workspaces which contain at least one window with the urgency hint
    /// set.
    UrgentWorkspaceBg,

    /// Border color for workspaces which contain at least one window with the urgency hint set.
    UrgentWorkspaceBorder,

    /// Text color for the binding mode indicator.
    BindingModeText,

    /// Background color for the binding mode indicator.
    BindingModeBg,

    /// Border color for the binding mode indicator.
    BindingModeBorder,

    /// A ColorableBarPart we don't support yet.
    Unknown,
}

/// The reply to the `get_bar_config` request.
///
/// This can be used by third-party workspace bars (especially i3bar, but others are free to
/// implement compatible alternatives) to get the bar block configuration from i3.
#[derive(Debug)]
pub struct BarConfig {
    /// The ID for this bar. Included in case you request multiple configurations and want to
    /// differentiate the different replies.
    pub id: String,

    /// Either dock (the bar sets the dock window type) or hide (the bar does not show unless a
    /// specific key is pressed).
    pub mode: String,

    /// Either bottom or top at the moment.
    pub position: String,

    /// Command which will be run to generate a statusline. Each line on stdout of this command
    /// will be displayed in the bar. At the moment, no formatting is supported.
    pub status_command: String,

    /// The font to use for text on the bar.
    pub font: String,

    /// Display workspace buttons or not? Defaults to true.
    pub workspace_buttons: bool,

    /// Display the mode indicator or not? Defaults to true.
    pub binding_mode_indicator: bool,

    /// Should the bar enable verbose output for debugging? Defaults to false.
    pub verbose: bool,

    /// Contains key/value pairs of colors. Each value is a color code in hex, formatted
    /// \#rrggbb (like in HTML).
    pub colors: HashMap<ColorableBarPart, String>,
}

/// The reply to the `get_version` request.
#[derive(Debug)]
pub struct Version {
    /// The major version of i3, such as 4.
    pub major: i32,

    /// The minor version of i3, such as 2. Changes in the IPC interface (new features) will
    /// only occur with new minor (or major) releases. However, bugfixes might be introduced in
    /// patch releases, too.
    pub minor: i32,

    /// The patch version of i3, such as 1 (when the complete version is 4.2.1). For versions
    /// such as 4.2, patch will be set to 0.
    pub patch: i32,

    /// A human-readable version of i3 containing the precise git version, build date and
    /// branch name. When you need to display the i3 version to your users, use the
    /// human-readable version whenever possible (since this is what i3 --version displays,
    /// too).
    pub human_readable: String,

    /// The current config path.
    pub loaded_config_file_name: String
}

/// The reply to the `get_binding_modes` request.
#[cfg(feature = "i3-4-13")]
#[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-13")))]
#[derive(Debug)]
pub struct BindingModes {
    /// A vector of all currently configured binding modes.
    pub modes: Vec<String>,
}

/// The reply to the `get_config` request.
#[cfg(feature = "i3-4-14")]
#[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-14")))]
#[derive(Debug)]
pub struct Config {
    /// A string containing the config file as loaded by i3 most recently.
    pub config: String,
}
<commit_msg>Derive Eq and PartialEq for all enums<commit_after>//! Abstractions for the replies passed back from i3.

use std::collections::HashMap;

/// The outcome of a single command.
#[derive(Debug)]
pub struct CommandOutcome {
    /// Whether the command was successful.
    pub success: bool,
    /// A human-readable error message.
    pub error: Option<String>
}

/// The reply to the `command` request.
#[derive(Debug)]
pub struct Command {
    /// A list of `CommandOutcome` structs; one for each command that was parsed.
    pub outcomes: Vec<CommandOutcome>
}

/// A single workspace.
#[derive(Debug)]
pub struct Workspace {
    /// The logical number of the workspace. Corresponds to the command to switch to this
    /// workspace. For named workspaces, this will be -1.
    pub num: i32,
    /// The name of this workspace (by default num+1), as changed by the user.
    pub name: String,
    /// Whether this workspace is currently visible on an output (multiple workspaces can be
    /// visible at the same time).
    pub visible: bool,
    /// Whether this workspace currently has the focus (only one workspace can have the focus
    /// at the same time).
    pub focused: bool,
    /// Whether a window on this workspace has the "urgent" flag set.
    pub urgent: bool,
    /// The rectangle of this workspace (equals the rect of the output it is on), consists of
    /// x, y, width, height.
    pub rect: (i32, i32, i32, i32),
    /// The video output this workspace is on (LVDS1, VGA1, …).
    pub output: String
}

/// The reply to the `get_workspaces` request.
#[derive(Debug)]
pub struct Workspaces {
    /// A list of workspaces.
    pub workspaces: Vec<Workspace>,
}

/// The reply to the `subscribe` request.
#[derive(Debug)]
pub struct Subscribe {
    /// Indicates whether the subscription was successful (the default) or whether a JSON
    /// parse error occurred.
    pub success: bool,
}

/// A single output (display)
#[derive(Debug)]
pub struct Output {
    /// The name of this output (as seen in xrandr).
    pub name: String,
    /// Whether the output is currently active (has a valid mode).
    pub active: bool,
    /// Whether the output is currently the primary output.
    pub primary: bool,
    /// The name of the current workspace that is visible on this output. None if the output is
    /// not active.
    pub current_workspace: Option<String>,
    /// The rectangle of this output (equals the rect of the output it is on), consists of
    /// x, y, width, height.
    pub rect: (i32, i32, i32, i32)
}

/// The reply to the `get_outputs` request.
#[derive(Debug)]
pub struct Outputs {
    /// A list of outputs (displays)
    pub outputs: Vec<Output>
}

#[derive(Eq, PartialEq, Debug)]
pub enum NodeType {
    Root,
    Output,
    Con,
    FloatingCon,
    Workspace,
    DockArea,
    /// A NodeType we don't support yet.
    Unknown,
}

#[derive(Eq, PartialEq, Debug)]
pub enum NodeBorder {
    Normal,
    None,
    Pixel,
    /// A NodeBorder we don't support yet.
    Unknown,
}

#[derive(Eq, PartialEq, Debug)]
pub enum NodeLayout {
    SplitH,
    SplitV,
    Stacked,
    Tabbed,
    DockArea,
    Output,
    /// A NodeLayout we don't support yet.
    Unknown,
}

/// The reply to the `get_tree` request.
#[derive(Debug)]
pub struct Node {
    /// List of child node IDs (see `nodes`, `floating_nodes` and `id`) in focus order. Traversing
    /// the tree by following the first entry in this array will result in eventually reaching the
    /// one node with `focused` set to true.
    pub focus: Vec<i64>,

    /// The child nodes of this container.
    pub nodes: Vec<Node>,

    /// The child floating nodes of this container.
    pub floating_nodes: Vec<Node>,

    /// The internal ID (actually a C pointer value) of this container. Do not make any
    /// assumptions about it. You can use it to (re-)identify and address containers when
    /// talking to i3.
    pub id: i64,

    /// The internal name of this container. For all containers which are part of the tree
    /// structure down to the workspace contents, this is set to a nice human-readable name of
    /// the container. For containers that have an X11 window, the content is the title
    /// (_NET_WM_NAME property) of that window. For all other containers, the content is not
    /// defined (yet).
    pub name: Option<String>,

    /// Type of this container. Can be one of "root", "output", "con", "floating_con",
    /// "workspace" or "dockarea".
    pub nodetype: NodeType,

    /// Can be either "normal", "none" or "1pixel", dependending on the container’s border
    /// style.
    pub border: NodeBorder,

    /// Number of pixels of the border width.
    pub current_border_width: i32,

    /// Can be either "splith", "splitv", "stacked", "tabbed", "dockarea" or "output". Other values
    /// might be possible in the future, should we add new layouts.
    pub layout: NodeLayout,

    /// The percentage which this container takes in its parent. A value of null means that the
    /// percent property does not make sense for this container, for example for the root
    /// container.
    pub percent: Option<f64>,

    /// The (x, y, width, height) absolute display coordinates for this container. Display
    /// coordinates means that when you have two 1600x1200 monitors on a single X11 Display
    /// (the standard way), the coordinates of the first window on the second monitor are
    /// (1600, 0, 1600, 1200).
    pub rect: (i32, i32, i32, i32),

    /// The (x, y, width, height) coordinates of the actual client window inside its container.
    /// These coordinates are  relative to the container and do not include the window
    /// decoration (which is actually rendered on the parent container). So for example, when
    /// using the default layout, you will have a 2 pixel border on each side, making the
    /// window_rect (2, 0, 632, 366).
    pub window_rect: (i32, i32, i32, i32),

    /// The (x, y, width, height) coordinates of the window decoration inside its container.
    /// These coordinates are relative to the container and do not include the actual client
    /// window.
    pub deco_rect: (i32, i32, i32, i32),

    /// The original geometry the window specified when i3 mapped it. Used when switching a
    /// window to floating mode, for example.
    pub geometry: (i32, i32, i32, i32),

    /// The X11 window ID of the actual client window inside this container. This field is set
    /// to null for split containers or otherwise empty containers. This ID corresponds to what
    /// xwininfo(1) and other X11-related tools display (usually in hex).
    pub window: Option<i32>,

    /// Whether this container (window, split container, floating container or workspace) has the
    /// urgency hint set, directly or indirectly. All parent containers up until the workspace
    /// container will be marked urgent if they have at least one urgent child.
    pub urgent: bool,

    /// Whether this container is currently focused.
    pub focused: bool,
}

/// The reply to the `get_marks` request.
///
/// Consists of a single vector of strings for each container that has a mark. A mark can only
/// be set on one container, so the vector is unique. The order of that vector is undefined. If
/// no window has a mark the response will be an empty vector.
#[derive(Debug)]
pub struct Marks {
    pub marks: Vec<String>
}

/// The reply to the `get_bar_ids` request.
///
/// This can be used by third-party workspace bars (especially i3bar, but others are free to
/// implement compatible alternatives) to get the bar block configuration from i3.
#[derive(Debug)]
pub struct BarIds {
    /// A vector of configured bar IDs.
    pub ids: Vec<String>
}

#[derive(Hash, Eq, PartialEq, Debug)]
pub enum ColorableBarPart {
    /// Background color of the bar.
    Background,

    /// Text color to be used for the statusline.
    Statusline,

    /// Text color to be used for the separator.
    Separator,

    /// Background color of the bar on the currently focused monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedBackground,

    /// Text color to be used for the statusline on the currently focused
    /// monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedStatusline,

    /// Text color to be used for the separator on the currently focused
    /// monitor output.
    #[cfg(feature = "i3-4-12")]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-12")))]
    FocusedSeparator,

    /// Text color for a workspace button when the workspace has focus.
    FocusedWorkspaceText,

    /// Background color for a workspace button when the workspace has focus.
    FocusedWorkspaceBg,

    /// Border color for a workspace button when the workspace has focus.
    FocusedWorkspaceBorder,

    /// Text color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceText,

    /// Background color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceBg,

    /// Border color for a workspace button when the workspace is active (visible) on some
    /// output, but the focus is on another one. You can only tell this apart from the
    /// focused workspace when you are using multiple monitors.
    ActiveWorkspaceBorder,

    /// Text color for a workspace button when the workspace does not have focus and is not
    /// active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceText,

    /// Background color for a workspace button when the workspace does not have focus and is
    /// not active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceBg,

    /// Border color for a workspace button when the workspace does not have focus and is
    /// not active (visible) on any output. This will be the case for most workspaces.
    InactiveWorkspaceBorder,

    /// Text color for workspaces which contain at least one window with the urgency hint set.
    UrgentWorkspaceText,

    /// Background color for workspaces which contain at least one window with the urgency hint
    /// set.
    UrgentWorkspaceBg,

    /// Border color for workspaces which contain at least one window with the urgency hint set.
    UrgentWorkspaceBorder,

    /// Text color for the binding mode indicator.
    BindingModeText,

    /// Background color for the binding mode indicator.
    BindingModeBg,

    /// Border color for the binding mode indicator.
    BindingModeBorder,

    /// A ColorableBarPart we don't support yet.
    Unknown,
}

/// The reply to the `get_bar_config` request.
///
/// This can be used by third-party workspace bars (especially i3bar, but others are free to
/// implement compatible alternatives) to get the bar block configuration from i3.
#[derive(Debug)]
pub struct BarConfig {
    /// The ID for this bar. Included in case you request multiple configurations and want to
    /// differentiate the different replies.
    pub id: String,

    /// Either dock (the bar sets the dock window type) or hide (the bar does not show unless a
    /// specific key is pressed).
    pub mode: String,

    /// Either bottom or top at the moment.
    pub position: String,

    /// Command which will be run to generate a statusline. Each line on stdout of this command
    /// will be displayed in the bar. At the moment, no formatting is supported.
    pub status_command: String,

    /// The font to use for text on the bar.
    pub font: String,

    /// Display workspace buttons or not? Defaults to true.
    pub workspace_buttons: bool,

    /// Display the mode indicator or not? Defaults to true.
    pub binding_mode_indicator: bool,

    /// Should the bar enable verbose output for debugging? Defaults to false.
    pub verbose: bool,

    /// Contains key/value pairs of colors. Each value is a color code in hex, formatted
    /// \#rrggbb (like in HTML).
    pub colors: HashMap<ColorableBarPart, String>,
}

/// The reply to the `get_version` request.
#[derive(Debug)]
pub struct Version {
    /// The major version of i3, such as 4.
    pub major: i32,

    /// The minor version of i3, such as 2. Changes in the IPC interface (new features) will
    /// only occur with new minor (or major) releases. However, bugfixes might be introduced in
    /// patch releases, too.
    pub minor: i32,

    /// The patch version of i3, such as 1 (when the complete version is 4.2.1). For versions
    /// such as 4.2, patch will be set to 0.
    pub patch: i32,

    /// A human-readable version of i3 containing the precise git version, build date and
    /// branch name. When you need to display the i3 version to your users, use the
    /// human-readable version whenever possible (since this is what i3 --version displays,
    /// too).
    pub human_readable: String,

    /// The current config path.
    pub loaded_config_file_name: String
}

/// The reply to the `get_binding_modes` request.
#[cfg(feature = "i3-4-13")]
#[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-13")))]
#[derive(Debug)]
pub struct BindingModes {
    /// A vector of all currently configured binding modes.
    pub modes: Vec<String>,
}

/// The reply to the `get_config` request.
#[cfg(feature = "i3-4-14")]
#[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-14")))]
#[derive(Debug)]
pub struct Config {
    /// A string containing the config file as loaded by i3 most recently.
    pub config: String,
}
<|endoftext|>


<commit_before>use color::{Colorf32, Color888};

/// Document is a sequence of nodes concatenated together.
#[derive(Debug)]
pub struct Document(pub Vec<Node>);

#[derive(Debug)]
pub enum Node {
    /// Pure text.
    Text(String),
    /// Set foreground color for the child document.
    Foreground(Colorf32, Document),
    /// Set background color for the child document.
    Background(Colorf32, Document),
    /// Bold the child document.
    Bold(Document),
    /// `Widget(name, args)` calls the widget named `name` with `args`.
    Widget(String, Vec<String>),
}

impl From<Vec<Node>> for Document {
    fn from(nodes: Vec<Node>) -> Self {
        Document(nodes)
    }
}

mod grammar {
    include!(concat!(env!("OUT_DIR"), "/grammar.rs"));
}

/// Parse `input` string into a `Document`.
pub fn parse(input: &str) -> Result<Document, String> {
    grammar::document(input).map_err(|e| e.to_string())
}

/// Parse `input` string into a `Document`. A `Document` is a
/// sequence of `Node`s. Take the first `Node` and discard all
/// the rest.
pub fn parse_for_first_node(input: &str) -> Result<Node, String> {
    parse(input).and_then(|doc| {
        doc.0
            .into_iter()
            .next()
            .ok_or("not a single node".into())
    })
}

/// Parse `input` string into a `Color888`.
/// `input` should be in `rrggbb` format, all in lowercase.
pub fn parse_color(input: &str) -> Result<Color888, String> {
    grammar::color(input).map_err(|e| e.to_string())
}

/// Escape `input` so that it will only generate `Text` node,
/// removing magic in the `input` string.
pub fn escape_for_text(input: &str) -> String {
    input.chars().map(escape_char_for_text).collect()
}

fn escape_char_for_text(ch: char) -> String {
    match ch {
        '<' | '>' | '(' | ')' | '[' | ']' | '{' | '}' | '\\' | '|' => {
            let mut s = '\\'.to_string();
            s.push(ch);
            s
        }
        _ => ch.to_string(),
    }
}

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

    #[test]
    fn test() {
        println!("{:?}", parse("f{f1\\[  }234(123456: a<sd|h|>el\\)lo) \\("));
        println!("{:?}", parse("f{f1\\[\\}234(123456: a<sd|h|>el\\)lo) \\("));
    }

    #[test]
    fn escape() {
        let escaped = escape_for_text("hello <([{\\|}])> world");
        let should_be = "hello \\<\\(\\[\\{\\\\\\|\\}\\]\\)\\> world";
        assert_eq!(escaped, should_be);
    }
}

<commit_msg>fastup: @ escape_for_text now escapes spaces<commit_after>use color::{Colorf32, Color888};

/// Document is a sequence of nodes concatenated together.
#[derive(Debug)]
pub struct Document(pub Vec<Node>);

#[derive(Debug)]
pub enum Node {
    /// Pure text.
    Text(String),
    /// Set foreground color for the child document.
    Foreground(Colorf32, Document),
    /// Set background color for the child document.
    Background(Colorf32, Document),
    /// Bold the child document.
    Bold(Document),
    /// `Widget(name, args)` calls the widget named `name` with `args`.
    Widget(String, Vec<String>),
}

impl From<Vec<Node>> for Document {
    fn from(nodes: Vec<Node>) -> Self {
        Document(nodes)
    }
}

mod grammar {
    include!(concat!(env!("OUT_DIR"), "/grammar.rs"));
}

/// Parse `input` string into a `Document`.
pub fn parse(input: &str) -> Result<Document, String> {
    grammar::document(input).map_err(|e| e.to_string())
}

/// Parse `input` string into a `Document`. A `Document` is a
/// sequence of `Node`s. Take the first `Node` and discard all
/// the rest.
pub fn parse_for_first_node(input: &str) -> Result<Node, String> {
    parse(input).and_then(|doc| {
        doc.0
            .into_iter()
            .next()
            .ok_or("not a single node".into())
    })
}

/// Parse `input` string into a `Color888`.
/// `input` should be in `rrggbb` format, all in lowercase.
pub fn parse_color(input: &str) -> Result<Color888, String> {
    grammar::color(input).map_err(|e| e.to_string())
}

/// Escape `input` so that it will only generate `Text` node,
/// removing magic in the `input` string.
pub fn escape_for_text(input: &str) -> String {
    input.chars().map(escape_char_for_text).collect()
}

fn escape_char_for_text(ch: char) -> String {
    match ch {
        '<' | '>' | '(' | ')' | '[' | ']' | '{' | '}' | '\\' | '|' | ' ' | '\t' | '\n' => {
            let mut s = '\\'.to_string();
            s.push(ch);
            s
        }
        _ => ch.to_string(),
    }
}

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

    #[test]
    fn test() {
        println!("{:?}", parse("f{f1\\[  }234(123456: a<sd|h|>el\\)lo) \\("));
        println!("{:?}", parse("f{f1\\[\\}234(123456: a<sd|h|>el\\)lo) \\("));
    }

    #[test]
    fn escape() {
        let escaped = escape_for_text("hello <([{\\|}])> world\nyes\tno");
        let should_be = "hello\\ \\<\\(\\[\\{\\\\\\|\\}\\]\\)\\>\\ world\\\nyes\\\tno";
        assert_eq!(escaped, should_be);
    }
}

<|endoftext|>


<commit_before>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Grin server implementation, glues the different parts of the system (mostly
//! the peer-to-peer server, the blockchain and the transaction pool) and acts
//! as a facade.

use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
use std::thread;
use std::time;

use futures::{Future, Stream};
use tokio_core::reactor;
use tokio_timer::Timer;

use adapters::*;
use api;
use chain;
use miner;
use p2p;
use pool;
use seed;
use sync;
use types::*;
use pow;
use util::LOGGER;

use core::global;

/// Grin server holding internal structures.
pub struct Server {
	/// server config
	pub config: ServerConfig,
	/// event handle
	evt_handle: reactor::Handle,
	/// handle to our network server
	p2p: Arc<p2p::Server>,
	/// data store access
	chain: Arc<chain::Chain>,
	/// in-memory transaction pool
	tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
	net_adapter: Arc<NetToChainAdapter>,
}

impl Server {
	/// Instantiates and starts a new server.
	pub fn start(config: ServerConfig) -> Result<Server, Error> {
		let mut evtlp = reactor::Core::new().unwrap();

		let mut mining_config = config.mining_config.clone();
		let serv = Server::future(config, &evtlp.handle())?;
		if mining_config.as_mut().unwrap().enable_mining {
			serv.start_miner(mining_config.unwrap());
		}

		let forever = Timer::default()
			.interval(time::Duration::from_secs(60))
			.for_each(move |_| {
				debug!(LOGGER, "event loop running");
				Ok(())
			})
			.map_err(|_| ());

		evtlp.run(forever).unwrap();
		Ok(serv)
	}

	/// Instantiates a new server associated with the provided future reactor.
	pub fn future(mut config: ServerConfig, evt_handle: &reactor::Handle) -> Result<Server, Error> {

		let pool_adapter = Arc::new(PoolToChainAdapter::new());
		let tx_pool = Arc::new(RwLock::new(pool::TransactionPool::new(
			config.pool_config.clone(),
			pool_adapter.clone(),
		)));

		let chain_adapter = Arc::new(ChainToPoolAndNetAdapter::new(tx_pool.clone()));

		let mut genesis_block = None;
		if !chain::Chain::chain_exists(config.db_root.clone()) {
			genesis_block = pow::mine_genesis_block(config.mining_config.clone());
		}

		let shared_chain = Arc::new(chain::Chain::init(
			config.db_root.clone(),
			chain_adapter.clone(),
			genesis_block,
			pow::verify_size,
		)?);

		pool_adapter.set_chain(shared_chain.clone());

		let peer_store = Arc::new(p2p::PeerStore::new(config.db_root.clone())?);
		let net_adapter = Arc::new(NetToChainAdapter::new(
			shared_chain.clone(),
			tx_pool.clone(),
			peer_store.clone(),
		));
		let p2p_server = Arc::new(p2p::Server::new(
			config.capabilities,
			config.p2p_config.unwrap(),
			net_adapter.clone(),
		));
		chain_adapter.init(p2p_server.clone());

		let seed = seed::Seeder::new(config.capabilities, peer_store.clone(), p2p_server.clone());
		match config.seeding_type.clone() {
			Seeding::None => {}
			Seeding::List => {
				seed.connect_and_monitor(
					evt_handle.clone(),
					seed::predefined_seeds(config.seeds.as_mut().unwrap().clone()),
				);
			}
			Seeding::WebStatic => {
				seed.connect_and_monitor(evt_handle.clone(), seed::web_seeds(evt_handle.clone()));
			}
		}

		if config.seeding_type != Seeding::None {
			let sync = sync::Syncer::new(shared_chain.clone(), p2p_server.clone());
			net_adapter.start_sync(sync);
		}

		evt_handle.spawn(p2p_server.start(evt_handle.clone()).map_err(|_| ()));

		info!(LOGGER, "Starting rest apis at: {}", &config.api_http_addr);

		api::start_rest_apis(
			config.api_http_addr.clone(),
			shared_chain.clone(),
			tx_pool.clone(),
		);

		warn!(LOGGER, "Grin server started.");
		Ok(Server {
			config: config,
			evt_handle: evt_handle.clone(),
			p2p: p2p_server,
			chain: shared_chain,
			tx_pool: tx_pool,
			net_adapter: net_adapter,
		})
	}

	/// Asks the server to connect to a peer at the provided network address.
	pub fn connect_peer(&self, addr: SocketAddr) -> Result<(), Error> {
		let handle = self.evt_handle.clone();
		handle.spawn(
			self.p2p
				.connect_peer(addr, handle.clone())
				.map(|_| ())
				.map_err(|_| ()),
		);
		Ok(())
	}

	/// Number of peers
	pub fn peer_count(&self) -> u32 {
		self.p2p.peer_count()
	}

	/// Start mining for blocks on a separate thread. Uses toy miner by default,
	/// mostly for testing, but can also load a plugin from cuckoo-miner
	pub fn start_miner(&self, config: pow::types::MinerConfig) {
		let cuckoo_size = global::sizeshift();
		let proof_size = global::proofsize();
		let net_adapter = self.net_adapter.clone();

		let mut miner = miner::Miner::new(config.clone(), self.chain.clone(), self.tx_pool.clone());
		miner.set_debug_output_id(format!("Port {}", self.config.p2p_config.unwrap().port));
		thread::spawn(move || {
			let secs_5 = time::Duration::from_secs(5);
			while net_adapter.syncing() {
				thread::sleep(secs_5);
			}
			miner.run_loop(config.clone(), cuckoo_size as u32, proof_size);
		});
	}

	/// The chain head
	pub fn head(&self) -> chain::Tip {
		self.chain.head().unwrap()
	}

	/// Returns a set of stats about this server. This and the ServerStats
	/// structure
	/// can be updated over time to include any information needed by tests or
	/// other
	/// consumers

	pub fn get_server_stats(&self) -> Result<ServerStats, Error> {
		Ok(ServerStats {
			peer_count: self.peer_count(),
			head: self.head(),
		})
	}
}
<commit_msg>Warn when no seed configured<commit_after>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Grin server implementation, glues the different parts of the system (mostly
//! the peer-to-peer server, the blockchain and the transaction pool) and acts
//! as a facade.

use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
use std::thread;
use std::time;

use futures::{Future, Stream};
use tokio_core::reactor;
use tokio_timer::Timer;

use adapters::*;
use api;
use chain;
use miner;
use p2p;
use pool;
use seed;
use sync;
use types::*;
use pow;
use util::LOGGER;

use core::global;

/// Grin server holding internal structures.
pub struct Server {
	/// server config
	pub config: ServerConfig,
	/// event handle
	evt_handle: reactor::Handle,
	/// handle to our network server
	p2p: Arc<p2p::Server>,
	/// data store access
	chain: Arc<chain::Chain>,
	/// in-memory transaction pool
	tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
	net_adapter: Arc<NetToChainAdapter>,
}

impl Server {
	/// Instantiates and starts a new server.
	pub fn start(config: ServerConfig) -> Result<Server, Error> {
		let mut evtlp = reactor::Core::new().unwrap();

		let mut mining_config = config.mining_config.clone();
		let serv = Server::future(config, &evtlp.handle())?;
		if mining_config.as_mut().unwrap().enable_mining {
			serv.start_miner(mining_config.unwrap());
		}

		let forever = Timer::default()
			.interval(time::Duration::from_secs(60))
			.for_each(move |_| {
				debug!(LOGGER, "event loop running");
				Ok(())
			})
			.map_err(|_| ());

		evtlp.run(forever).unwrap();
		Ok(serv)
	}

	/// Instantiates a new server associated with the provided future reactor.
	pub fn future(mut config: ServerConfig, evt_handle: &reactor::Handle) -> Result<Server, Error> {

		let pool_adapter = Arc::new(PoolToChainAdapter::new());
		let tx_pool = Arc::new(RwLock::new(pool::TransactionPool::new(
			config.pool_config.clone(),
			pool_adapter.clone(),
		)));

		let chain_adapter = Arc::new(ChainToPoolAndNetAdapter::new(tx_pool.clone()));

		let mut genesis_block = None;
		if !chain::Chain::chain_exists(config.db_root.clone()) {
			genesis_block = pow::mine_genesis_block(config.mining_config.clone());
		}

		let shared_chain = Arc::new(chain::Chain::init(
			config.db_root.clone(),
			chain_adapter.clone(),
			genesis_block,
			pow::verify_size,
		)?);

		pool_adapter.set_chain(shared_chain.clone());

		let peer_store = Arc::new(p2p::PeerStore::new(config.db_root.clone())?);
		let net_adapter = Arc::new(NetToChainAdapter::new(
			shared_chain.clone(),
			tx_pool.clone(),
			peer_store.clone(),
		));
		let p2p_server = Arc::new(p2p::Server::new(
			config.capabilities,
			config.p2p_config.unwrap(),
			net_adapter.clone(),
		));
		chain_adapter.init(p2p_server.clone());

		let seed = seed::Seeder::new(config.capabilities, peer_store.clone(), p2p_server.clone());
		match config.seeding_type.clone() {
			Seeding::None => {
				warn!(
					LOGGER,
					"No seed configured, will stay solo unless connected to"
				);
			}
			Seeding::List => {
				seed.connect_and_monitor(
					evt_handle.clone(),
					seed::predefined_seeds(config.seeds.as_mut().unwrap().clone()),
				);
			}
			Seeding::WebStatic => {
				seed.connect_and_monitor(evt_handle.clone(), seed::web_seeds(evt_handle.clone()));
			}
		}

		if config.seeding_type != Seeding::None {
			let sync = sync::Syncer::new(shared_chain.clone(), p2p_server.clone());
			net_adapter.start_sync(sync);
		}

		evt_handle.spawn(p2p_server.start(evt_handle.clone()).map_err(|_| ()));

		info!(LOGGER, "Starting rest apis at: {}", &config.api_http_addr);

		api::start_rest_apis(
			config.api_http_addr.clone(),
			shared_chain.clone(),
			tx_pool.clone(),
		);

		warn!(LOGGER, "Grin server started.");
		Ok(Server {
			config: config,
			evt_handle: evt_handle.clone(),
			p2p: p2p_server,
			chain: shared_chain,
			tx_pool: tx_pool,
			net_adapter: net_adapter,
		})
	}

	/// Asks the server to connect to a peer at the provided network address.
	pub fn connect_peer(&self, addr: SocketAddr) -> Result<(), Error> {
		let handle = self.evt_handle.clone();
		handle.spawn(
			self.p2p
				.connect_peer(addr, handle.clone())
				.map(|_| ())
				.map_err(|_| ()),
		);
		Ok(())
	}

	/// Number of peers
	pub fn peer_count(&self) -> u32 {
		self.p2p.peer_count()
	}

	/// Start mining for blocks on a separate thread. Uses toy miner by default,
	/// mostly for testing, but can also load a plugin from cuckoo-miner
	pub fn start_miner(&self, config: pow::types::MinerConfig) {
		let cuckoo_size = global::sizeshift();
		let proof_size = global::proofsize();
		let net_adapter = self.net_adapter.clone();

		let mut miner = miner::Miner::new(config.clone(), self.chain.clone(), self.tx_pool.clone());
		miner.set_debug_output_id(format!("Port {}", self.config.p2p_config.unwrap().port));
		thread::spawn(move || {
			let secs_5 = time::Duration::from_secs(5);
			while net_adapter.syncing() {
				thread::sleep(secs_5);
			}
			miner.run_loop(config.clone(), cuckoo_size as u32, proof_size);
		});
	}

	/// The chain head
	pub fn head(&self) -> chain::Tip {
		self.chain.head().unwrap()
	}

	/// Returns a set of stats about this server. This and the ServerStats
	/// structure
	/// can be updated over time to include any information needed by tests or
	/// other
	/// consumers

	pub fn get_server_stats(&self) -> Result<ServerStats, Error> {
		Ok(ServerStats {
			peer_count: self.peer_count(),
			head: self.head(),
		})
	}
}
<|endoftext|>


<commit_before>pub struct Space {
    state: SpaceState,
    position: [u8; 2],
}

impl Space {
    pub fn new(pos: [u8; 2]) -> Space {
        Space {
            state: SpaceState::Unchecked,
            position: pos
        }
    }

    /// Sets this space as having been checked, and whether it was hit.
    pub fn set_checked(&mut self, hit: bool) {
        self.state = SpaceState::Checked(hit);
    }

    pub fn is_unchecked(&self) -> bool {
        self.state == SpaceState::Unchecked
    }

    pub fn is_empty(&self) -> bool {
        self.state == SpaceState::Checked(false)
    }

    pub fn is_hit(&self) -> bool {
        self.state == SpaceState::Checked(true)
    }

    pub fn pos(&self) -> &[u8; 2] {
        &self.position
    }
}

#[derive(Clone, Copy, PartialEq)]
pub enum SpaceState {
    Unchecked,
    Checked(bool)
}

<commit_msg>Space set_checked() now returns an error if already checked<commit_after>pub struct Space {
    state: SpaceState,
    position: [u8; 2],
}

impl Space {
    pub fn new(pos: [u8; 2]) -> Space {
        Space {
            state: SpaceState::Unchecked,
            position: pos
        }
    }

    /// Sets this space as having been checked, and whether it was hit.
    ///
    /// # Errors
    ///
    /// Returns an error if the space's state is not `SpaceState::Unchecked`.
    pub fn set_checked(&mut self, hit: bool) -> Result<(), &'static str> {
        if self.state != SpaceState::Unchecked {
            Err("tried to check an already checked space")
        } else {
            self.state = SpaceState::Checked(hit);
            Ok(())
        }
    }

    pub fn is_unchecked(&self) -> bool {
        self.state == SpaceState::Unchecked
    }

    pub fn is_empty(&self) -> bool {
        self.state == SpaceState::Checked(false)
    }

    pub fn is_hit(&self) -> bool {
        self.state == SpaceState::Checked(true)
    }

    pub fn pos(&self) -> &[u8; 2] {
        &self.position
    }
}

#[derive(Clone, Copy, PartialEq)]
pub enum SpaceState {
    Unchecked,
    Checked(bool)
}

<|endoftext|>


<commit_before>use std::fs::File;
use std::path::{Path, PathBuf};

use crate::prelude::*;

use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION};
use rustc_codegen_ssa::back::archive::{ArchiveBuilder, find_library};

struct ArchiveConfig<'a> {
    sess: &'a Session,
    dst: PathBuf,
    src: Option<PathBuf>,
    lib_search_paths: Vec<PathBuf>,
    use_gnu_style_archive: bool,
}

#[derive(Debug)]
enum ArchiveEntry {
    FromArchive { archive_index: usize, entry_index: usize },
    File(File),
}

pub struct ArArchiveBuilder<'a> {
    config: ArchiveConfig<'a>,
    src_archives: Vec<ar::Archive<File>>,
    // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
    // the end of an archive for linkers to not get confused.
    entries: Vec<(String, ArchiveEntry)>,
    update_symbols: bool,
}

impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
    fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
        use rustc_codegen_ssa::back::link::archive_search_paths;
        let config = ArchiveConfig {
            sess,
            dst: output.to_path_buf(),
            src: input.map(|p| p.to_path_buf()),
            lib_search_paths: archive_search_paths(sess),
            // FIXME test for linux and System V derivatives instead
            use_gnu_style_archive: !sess.target.target.options.is_like_osx,
        };

        let (src_archives, entries) = if let Some(src) = &config.src {
            let mut archive = ar::Archive::new(File::open(src).unwrap());
            let mut entries = Vec::new();

            let mut i = 0;
            while let Some(entry) = archive.next_entry() {
                let entry = entry.unwrap();
                entries.push((
                    String::from_utf8(entry.header().identifier().to_vec()).unwrap(),
                    ArchiveEntry::FromArchive { archive_index: 0, entry_index: i },
                ));
                i += 1;
            }

            (vec![archive], entries)
        } else {
            (vec![], Vec::new())
        };

        ArArchiveBuilder {
            config,
            src_archives,
            entries,
            update_symbols: false,
        }
    }

    fn src_files(&mut self) -> Vec<String> {
        self.entries.iter().map(|(name, _)| name.clone()).collect()
    }

    fn remove_file(&mut self, name: &str) {
        let index = self.entries
            .iter()
            .position(|(entry_name, _)| entry_name == name)
            .expect("Tried to remove file not existing in src archive");
        self.entries.remove(index);
    }

    fn add_file(&mut self, file: &Path) {
        self.entries.push((
            file.file_name().unwrap().to_str().unwrap().to_string(),
            ArchiveEntry::File(File::open(file).unwrap()),
        ));
    }

    fn add_native_library(&mut self, name: &str) {
        let location = find_library(name, &self.config.lib_search_paths, self.config.sess);
        self.add_archive(&location, |_| false).unwrap_or_else(|e| {
            panic!("failed to add native library {}: {}", location.to_string_lossy(), e);
        });
    }

    fn add_rlib(&mut self, rlib: &Path, name: &str, lto: bool, skip_objects: bool) -> std::io::Result<()> {
        let obj_start = name.to_owned();

        self.add_archive(rlib, move |fname: &str| {
            // Ignore bytecode/metadata files, no matter the name.
            if fname.ends_with(RLIB_BYTECODE_EXTENSION) || fname == METADATA_FILENAME {
                return true;
            }

            // Don't include Rust objects if LTO is enabled
            if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") {
                return true;
            }

            // Otherwise if this is *not* a rust object and we're skipping
            // objects then skip this file
            if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
                return true;
            }

            // ok, don't skip this
            return false;
        })
    }

    fn update_symbols(&mut self) {
        self.update_symbols = true;
    }

    fn build(mut self) {
        enum BuilderKind {
            Bsd(ar::Builder<File>),
            Gnu(ar::GnuBuilder<File>),
        }

        let archive_file = File::create(&self.config.dst).unwrap();
        let mut builder = if self.config.use_gnu_style_archive {
            BuilderKind::Gnu(ar::GnuBuilder::new(
                archive_file,
                self.entries.iter().map(|(name, _)| name.as_bytes().to_vec()).collect(),
            ))
        } else {
            BuilderKind::Bsd(ar::Builder::new(archive_file))
        };

        // Add all files
        for (entry_name, entry) in self.entries.into_iter() {
            match entry {
                ArchiveEntry::FromArchive { archive_index, entry_index } => {
                    let entry = self.src_archives[archive_index].jump_to_entry(entry_index).unwrap();
                    let orig_header = entry.header();

                    let mut header =
                        ar::Header::new(orig_header.identifier().to_vec(), orig_header.size());
                    header.set_mtime(orig_header.mtime());
                    header.set_uid(orig_header.uid());
                    header.set_gid(orig_header.gid());
                    header.set_mode(orig_header.mode());
                    match builder {
                        BuilderKind::Bsd(ref mut builder) => builder.append(&header, entry).unwrap(),
                        BuilderKind::Gnu(ref mut builder) => builder.append(&header, entry).unwrap(),
                    }
                }
                ArchiveEntry::File(mut file) => {
                    match builder {
                        BuilderKind::Bsd(ref mut builder) => builder.append_file(entry_name.as_bytes(), &mut file).unwrap(),
                        BuilderKind::Gnu(ref mut builder) => builder.append_file(entry_name.as_bytes(), &mut file).unwrap(),
                    }
                }
            }
        }

        // Finalize archive
        std::mem::drop(builder);

        // Run ranlib to be able to link the archive
        let status = std::process::Command::new("ranlib")
            .arg(self.config.dst)
            .status()
            .expect("Couldn't run ranlib");
        assert!(
            status.success(),
            "Ranlib exited with code {:?}",
            status.code()
        );
    }
}

impl<'a> ArArchiveBuilder<'a> {
    fn add_archive<F>(&mut self, archive: &Path, mut skip: F) -> std::io::Result<()>
        where F: FnMut(&str) -> bool + 'static
    {
        let mut archive = ar::Archive::new(std::fs::File::open(archive)?);
        let archive_index = self.src_archives.len();

        let mut i = 0;
        while let Some(entry) = archive.next_entry() {
            let entry = entry.unwrap();
            let file_name = String::from_utf8(entry.header().identifier().to_vec()).unwrap();
            if !skip(&file_name) {
                self.entries.push((
                    file_name,
                    ArchiveEntry::FromArchive { archive_index, entry_index: i },
                ));
            }
            i += 1;
        }

        self.src_archives.push(archive);
        Ok(())
    }
}
<commit_msg>Use native `ar` to create archive files<commit_after>use std::fs::File;
use std::path::{Path, PathBuf};

use crate::prelude::*;

use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION};
use rustc_codegen_ssa::back::archive::{ArchiveBuilder, find_library};

struct ArchiveConfig<'a> {
    sess: &'a Session,
    dst: PathBuf,
    lib_search_paths: Vec<PathBuf>,
    use_native_ar: bool,
    use_gnu_style_archive: bool,
}

#[derive(Debug)]
enum ArchiveEntry {
    FromArchive { archive_index: usize, entry_index: usize },
    File(PathBuf),
}

pub struct ArArchiveBuilder<'a> {
    config: ArchiveConfig<'a>,
    src_archives: Vec<(PathBuf, ar::Archive<File>)>,
    // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
    // the end of an archive for linkers to not get confused.
    entries: Vec<(String, ArchiveEntry)>,
    update_symbols: bool,
}

impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
    fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
        use rustc_codegen_ssa::back::link::archive_search_paths;
        let config = ArchiveConfig {
            sess,
            dst: output.to_path_buf(),
            lib_search_paths: archive_search_paths(sess),
            use_native_ar: true, // FIXME fix rust-ar to not emit corrupted archive files.
            // FIXME test for linux and System V derivatives instead
            use_gnu_style_archive: !sess.target.target.options.is_like_osx,
        };

        let (src_archives, entries) = if let Some(input) = input {
            let mut archive = ar::Archive::new(File::open(input).unwrap());
            let mut entries = Vec::new();

            let mut i = 0;
            while let Some(entry) = archive.next_entry() {
                let entry = entry.unwrap();
                entries.push((
                    String::from_utf8(entry.header().identifier().to_vec()).unwrap(),
                    ArchiveEntry::FromArchive { archive_index: 0, entry_index: i },
                ));
                i += 1;
            }

            (vec![(input.to_owned(), archive)], entries)
        } else {
            (vec![], Vec::new())
        };

        ArArchiveBuilder {
            config,
            src_archives,
            entries,
            update_symbols: false,
        }
    }

    fn src_files(&mut self) -> Vec<String> {
        self.entries.iter().map(|(name, _)| name.clone()).collect()
    }

    fn remove_file(&mut self, name: &str) {
        let index = self.entries
            .iter()
            .position(|(entry_name, _)| entry_name == name)
            .expect("Tried to remove file not existing in src archive");
        self.entries.remove(index);
    }

    fn add_file(&mut self, file: &Path) {
        self.entries.push((
            file.file_name().unwrap().to_str().unwrap().to_string(),
            ArchiveEntry::File(file.to_owned()),
        ));
    }

    fn add_native_library(&mut self, name: &str) {
        let location = find_library(name, &self.config.lib_search_paths, self.config.sess);
        self.add_archive(location.clone(), |_| false).unwrap_or_else(|e| {
            panic!("failed to add native library {}: {}", location.to_string_lossy(), e);
        });
    }

    fn add_rlib(&mut self, rlib: &Path, name: &str, lto: bool, skip_objects: bool) -> std::io::Result<()> {
        let obj_start = name.to_owned();

        self.add_archive(rlib.to_owned(), move |fname: &str| {
            // Ignore bytecode/metadata files, no matter the name.
            if fname.ends_with(RLIB_BYTECODE_EXTENSION) || fname == METADATA_FILENAME {
                return true;
            }

            // Don't include Rust objects if LTO is enabled
            if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") {
                return true;
            }

            // Otherwise if this is *not* a rust object and we're skipping
            // objects then skip this file
            if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
                return true;
            }

            // ok, don't skip this
            return false;
        })
    }

    fn update_symbols(&mut self) {
        self.update_symbols = true;
    }

    fn build(mut self) {
        use std::process::Command;

        fn add_file_using_ar(archive: &Path, file: &Path) {
            Command::new("ar")
                .arg("r") // add or replace file
                .arg("-c") // silence created file message
                .arg(archive)
                .arg(&file)
                .status()
                .unwrap();
        }

        enum BuilderKind<'a> {
            Bsd(ar::Builder<File>),
            Gnu(ar::GnuBuilder<File>),
            NativeAr(&'a Path),
        }

        let mut builder = if self.config.use_native_ar {
            BuilderKind::NativeAr(&self.config.dst)
        } else if self.config.use_gnu_style_archive {
            BuilderKind::Gnu(ar::GnuBuilder::new(
                File::create(&self.config.dst).unwrap(),
                self.entries.iter().map(|(name, _)| name.as_bytes().to_vec()).collect(),
            ))
        } else {
            BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap()))
        };

        // Add all files
        for (entry_name, entry) in self.entries.into_iter() {
            match entry {
                ArchiveEntry::FromArchive { archive_index, entry_index } => {
                    let (ref src_archive_path, ref mut src_archive) = self.src_archives[archive_index];
                    let entry = src_archive.jump_to_entry(entry_index).unwrap();
                    let orig_header = entry.header();

                    // FIXME implement clone for `ar::Archive`.
                    let mut header =
                        ar::Header::new(orig_header.identifier().to_vec(), orig_header.size());
                    header.set_mtime(orig_header.mtime());
                    header.set_uid(orig_header.uid());
                    header.set_gid(orig_header.gid());
                    header.set_mode(orig_header.mode());

                    match builder {
                        BuilderKind::Bsd(ref mut builder) => builder.append(&header, entry).unwrap(),
                        BuilderKind::Gnu(ref mut builder) => builder.append(&header, entry).unwrap(),
                        BuilderKind::NativeAr(archive_file) => {
                            Command::new("ar").arg("x").arg(src_archive_path).arg(&entry_name).status().unwrap();
                            add_file_using_ar(archive_file, Path::new(&entry_name));
                            std::fs::remove_file(entry_name).unwrap();
                        }
                    }
                }
                ArchiveEntry::File(file) => {
                    match builder {
                        BuilderKind::Bsd(ref mut builder) => builder.append_file(entry_name.as_bytes(), &mut File::open(file).unwrap()).unwrap(),
                        BuilderKind::Gnu(ref mut builder) => builder.append_file(entry_name.as_bytes(), &mut File::open(file).unwrap()).unwrap(),
                        BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file),
                    }
                }
            }
        }

        // Finalize archive
        std::mem::drop(builder);

        // Run ranlib to be able to link the archive
        let status = std::process::Command::new("ranlib")
            .arg(self.config.dst)
            .status()
            .expect("Couldn't run ranlib");
        assert!(
            status.success(),
            "Ranlib exited with code {:?}",
            status.code()
        );
    }
}

impl<'a> ArArchiveBuilder<'a> {
    fn add_archive<F>(&mut self, archive_path: PathBuf, mut skip: F) -> std::io::Result<()>
        where F: FnMut(&str) -> bool + 'static
    {
        let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?);
        let archive_index = self.src_archives.len();

        let mut i = 0;
        while let Some(entry) = archive.next_entry() {
            let entry = entry.unwrap();
            let file_name = String::from_utf8(entry.header().identifier().to_vec()).unwrap();
            if !skip(&file_name) {
                self.entries.push((
                    file_name,
                    ArchiveEntry::FromArchive { archive_index, entry_index: i },
                ));
            }
            i += 1;
        }

        self.src_archives.push((archive_path, archive));
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std;
use std::io;
use std::fs;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use zip;

pub fn extract_zip<T: io::Read + io::Seek>(
    archive: &mut zip::ZipArchive<T>,
    output: &std::path::Path,
) -> Result<(), zip::result::ZipError> {
    for i in 0..archive.len() {
        let mut file = archive.by_index(i)?;
        let outpath = output.join(sanitize_filename(file.name()));

        {
            let comment = file.comment();
            if comment.len() > 0 {
                println!("  File comment: {}", comment);
            }
        }

        let perms = convert_permissions(file.unix_mode());

        // also suspicious but why not?
        if (&*file.name()).ends_with("/") {
            create_directory(&outpath, perms);
        } else {
            write_file(&mut file, &outpath, perms);
        }
    }
    Ok(())
}

#[cfg(unix)]
fn convert_permissions(mode: Option<u32>) -> Option<fs::Permissions> {
    match mode {
        Some(mode) => Some(fs::Permissions::from_mode(mode)),
        None => None,
    }
}
#[cfg(not(unix))]
fn convert_permissions(_mode: Option<u32>) -> Option<fs::Permissions> {
    None
}

fn write_file(
    file: &mut zip::read::ZipFile,
    outpath: &std::path::Path,
    perms: Option<fs::Permissions>,
) {
    let mut outfile = fs::File::create(&outpath).unwrap();
    io::copy(file, &mut outfile).unwrap();
    if let Some(perms) = perms {
        fs::set_permissions(outpath, perms).unwrap();
    }
}

fn create_directory(outpath: &std::path::Path, perms: Option<fs::Permissions>) {
    fs::create_dir_all(&outpath).unwrap();
    if let Some(perms) = perms {
        fs::set_permissions(outpath, perms).unwrap();
    }
}

fn sanitize_filename(filename: &str) -> std::path::PathBuf {
    let no_null_filename = match filename.find('\0') {
        Some(index) => &filename[0..index],
        None => filename,
    };

    std::path::Path::new(no_null_filename)
        .components()
        .filter(|component| match *component {
            std::path::Component::Normal(..) => true,
            _ => false,
        })
        .fold(std::path::PathBuf::new(), |mut path, ref cur| {
            path.push(cur.as_os_str());
            path
        })
}
<commit_msg>Cargo fmt<commit_after>use std;
use std::fs;
use std::io;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use zip;

pub fn extract_zip<T: io::Read + io::Seek>(
    archive: &mut zip::ZipArchive<T>,
    output: &std::path::Path,
) -> Result<(), zip::result::ZipError> {
    for i in 0..archive.len() {
        let mut file = archive.by_index(i)?;
        let outpath = output.join(sanitize_filename(file.name()));

        {
            let comment = file.comment();
            if comment.len() > 0 {
                println!("  File comment: {}", comment);
            }
        }

        let perms = convert_permissions(file.unix_mode());

        // also suspicious but why not?
        if (&*file.name()).ends_with("/") {
            create_directory(&outpath, perms);
        } else {
            write_file(&mut file, &outpath, perms);
        }
    }
    Ok(())
}

#[cfg(unix)]
fn convert_permissions(mode: Option<u32>) -> Option<fs::Permissions> {
    match mode {
        Some(mode) => Some(fs::Permissions::from_mode(mode)),
        None => None,
    }
}
#[cfg(not(unix))]
fn convert_permissions(_mode: Option<u32>) -> Option<fs::Permissions> {
    None
}

fn write_file(
    file: &mut zip::read::ZipFile,
    outpath: &std::path::Path,
    perms: Option<fs::Permissions>,
) {
    let mut outfile = fs::File::create(&outpath).unwrap();
    io::copy(file, &mut outfile).unwrap();
    if let Some(perms) = perms {
        fs::set_permissions(outpath, perms).unwrap();
    }
}

fn create_directory(outpath: &std::path::Path, perms: Option<fs::Permissions>) {
    fs::create_dir_all(&outpath).unwrap();
    if let Some(perms) = perms {
        fs::set_permissions(outpath, perms).unwrap();
    }
}

fn sanitize_filename(filename: &str) -> std::path::PathBuf {
    let no_null_filename = match filename.find('\0') {
        Some(index) => &filename[0..index],
        None => filename,
    };

    std::path::Path::new(no_null_filename)
        .components()
        .filter(|component| match *component {
            std::path::Component::Normal(..) => true,
            _ => false,
        })
        .fold(std::path::PathBuf::new(), |mut path, ref cur| {
            path.push(cur.as_os_str());
            path
        })
}
<|endoftext|>


<commit_before>pub fn guess_single_xor_char_decode(bytes: &Vec<u8>) -> (u16, Vec<u8>, u8) {
	use english_scoring::*;
	use key::*;

	let mut top_score = 0;
	let mut top_decode = vec![];
	let mut top_x = 2;
	for x in 0..255 {
		let mut rk = RepeatingKey::new_bytes(vec![x]);
		let decoded = rk.encrypt_bytes(&bytes);

		let score = score_on_letter_frequency(&decoded);
		if score > top_score {
			top_score = score;
			top_decode = decoded;
			top_x = x;
		}
	}

	(top_score, top_decode, top_x)
}

//-----------------------------------------------------------------------------

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

	#[test]
	fn guess_single_xor_char_decode_i_set_1_problem_3() {
		// http://cryptopals.com/sets/1/challenges/3/
		use byte_conversion::*;
		let encoded = hex_to_bytes("1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736");

		let (top_score, top_decode, top_x) = guess_single_xor_char_decode(&encoded);

		let expected = readable_text_to_bytes(&"Cooking MC's like a pound of bacon");

		assert_eq!(expected, top_decode);
		assert_eq!(88, top_x);
		assert!(top_score > 0);
	}
}
<commit_msg>Second test for single_xor_guess<commit_after>pub fn guess_single_xor_char_decode(bytes: &Vec<u8>) -> (u16, Vec<u8>, u8) {
	use english_scoring::*;
	use key::*;

	let mut top_score = 0;
	let mut top_decode = vec![];
	let mut top_x = 2;
	for x in 0..255 {
		let mut rk = RepeatingKey::new_bytes(vec![x]);
		let decoded = rk.encrypt_bytes(&bytes);

		let score = score_on_letter_frequency(&decoded);
		if score > top_score {
			top_score = score;
			top_decode = decoded;
			top_x = x;
		}
	}

	(top_score, top_decode, top_x)
}

//-----------------------------------------------------------------------------

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

	#[test]
	fn guess_single_xor_char_decode_i_set_1_problem_3() {
		// http://cryptopals.com/sets/1/challenges/3/
		use byte_conversion::*;
		let encoded = hex_to_bytes("1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736");

		let (top_score, guessed_decode, guessed_character) = guess_single_xor_char_decode(&encoded);

		let expected = readable_text_to_bytes(&"Cooking MC's like a pound of bacon");

		assert_eq!(expected, guessed_decode);
		assert_eq!(88, guessed_character);
		assert!(top_score > 0);
	}

	#[test]
	fn guess_single_xor_char_decode_i_example() {
		// http://cryptopals.com/sets/1/challenges/3/
		use byte_conversion::*;
		use key::*;

		let mut rk = RepeatingKey::new("Q");
		let example = readable_text_to_bytes(&"Some super hard to decrypt (but still English!) text.");

		let encrypted = rk.encrypt_bytes(&example);
		let (top_score, guessed_decode, guessed_character) = guess_single_xor_char_decode(&encrypted);

		assert_eq!(example, guessed_decode);
		assert_eq!('Q' as u8, guessed_character);
		assert!(top_score > 0);
	}
}
<|endoftext|>