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

use std::{fs::File, io::Read, path::PathBuf};

use libmount;
use nix::mount::{umount2, MntFlags};

use devicemapper::{DevId, DmOptions};

use crate::engine::strat_engine::{
    cmd::udev_settle,
    dm::{get_dm, get_dm_init},
};

mod cleanup_errors {
    use libmount;
    use nix;
    use std;

    error_chain! {
        foreign_links {
            Ioe(std::io::Error);
            Mnt(libmount::mountinfo::ParseError);
            Nix(nix::Error);
        }
    }
}

use self::cleanup_errors::{Error, Result};

/// Attempt to remove all device mapper devices which match the stratis naming convention.
/// FIXME: Current implementation complicated by https://bugzilla.redhat.com/show_bug.cgi?id=1506287
fn dm_stratis_devices_remove() -> Result<()> {
    /// One iteration of removing devicemapper devices
    fn one_iteration() -> Result<(bool, Vec<String>)> {
        let mut progress_made = false;
        let mut remain = Vec::new();

        for n in get_dm()
            .list_devices()
            .map_err(|e| {
                let err_msg = "failed while listing DM devices, giving up";
                Error::with_chain(e, err_msg)
            })?
            .iter()
            .map(|d| &d.0)
            .filter(|n| n.to_string().starts_with("stratis-1"))
        {
            match get_dm().device_remove(&DevId::Name(n), &DmOptions::new()) {
                Ok(_) => progress_made = true,
                Err(_) => remain.push(n.to_string()),
            }
        }
        Ok((progress_made, remain))
    }

    /// Do one iteration of removals until progress stops. Return remaining
    /// dm devices.
    fn do_while_progress() -> Result<Vec<String>> {
        let mut result = one_iteration()?;
        while result.0 {
            result = one_iteration()?;
        }
        Ok(result.1)
    }

    || -> Result<()> {
        udev_settle().unwrap();
        get_dm_init().map_err(|err| Error::with_chain(err, "Unable to initialize DM"))?;
        do_while_progress().and_then(|remain| {
            if !remain.is_empty() {
                Err(format!("Some Stratis DM devices remaining: {:?}", remain).into())
            } else {
                Ok(())
            }
        })
    }()
    .map_err(|e| e.chain_err(|| "Failed to ensure removal of all Stratis DM devices"))
}

/// Try and un-mount any filesystems that have the name stratis in the mount point, returning
/// immediately on the first one we are unable to unmount.
fn stratis_filesystems_unmount() -> Result<()> {
    || -> Result<()> {
        let mut mount_data = String::new();
        File::open("/proc/self/mountinfo")?.read_to_string(&mut mount_data)?;
        let parser = libmount::mountinfo::Parser::new(mount_data.as_bytes());

        for mount_point in parser
            .filter_map(|x| x.ok())
            .filter_map(|m| m.mount_point.into_owned().into_string().ok())
            .filter(|mp| mp.contains("stratis"))
        {
            umount2(&PathBuf::from(mount_point), MntFlags::MNT_DETACH)?;
        }

        Ok(())
    }()
    .map_err(|e| e.chain_err(|| "Failed to ensure all Stratis filesystems were unmounted"))
}

/// When a unit test panics we can leave the system in an inconsistent state.  This function
/// tries to clean up by un-mounting any mounted file systems which contain the string
/// "stratis_testing" and then it tries to remove any device mapper tables which are also stratis
/// created.
pub fn clean_up() -> Result<()> {
    stratis_filesystems_unmount()?;
    dm_stratis_devices_remove()?;
    Ok(())
}
<commit_msg>Shorten and clarify cleanup method<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{fs::File, io::Read, path::PathBuf};

use libmount;
use nix::mount::{umount2, MntFlags};

use devicemapper::{DevId, DmOptions};

use crate::engine::strat_engine::{
    cmd::udev_settle,
    dm::{get_dm, get_dm_init},
};

mod cleanup_errors {
    use libmount;
    use nix;
    use std;

    error_chain! {
        foreign_links {
            Ioe(std::io::Error);
            Mnt(libmount::mountinfo::ParseError);
            Nix(nix::Error);
        }
    }
}

use self::cleanup_errors::{Error, Result};

/// Attempt to remove all device mapper devices which match the stratis naming convention.
/// FIXME: Current implementation complicated by https://bugzilla.redhat.com/show_bug.cgi?id=1506287
fn dm_stratis_devices_remove() -> Result<()> {
    /// One iteration of removing devicemapper devices
    fn one_iteration() -> Result<(bool, Vec<String>)> {
        let mut progress_made = false;
        let mut remain = Vec::new();

        for n in get_dm()
            .list_devices()
            .map_err(|e| {
                let err_msg = "failed while listing DM devices, giving up";
                Error::with_chain(e, err_msg)
            })?
            .iter()
            .map(|d| &d.0)
            .filter(|n| n.to_string().starts_with("stratis-1"))
        {
            match get_dm().device_remove(&DevId::Name(n), &DmOptions::new()) {
                Ok(_) => progress_made = true,
                Err(_) => remain.push(n.to_string()),
            }
        }
        Ok((progress_made, remain))
    }

    /// Do one iteration of removals until progress stops. Return remaining
    /// dm devices.
    fn do_while_progress() -> Result<Vec<String>> {
        let mut result = one_iteration()?;
        while result.0 {
            result = one_iteration()?;
        }
        Ok(result.1)
    }

    || -> Result<()> {
        udev_settle().unwrap();
        get_dm_init().map_err(|err| Error::with_chain(err, "Unable to initialize DM"))?;
        do_while_progress().and_then(|remain| {
            if !remain.is_empty() {
                Err(format!("Some Stratis DM devices remaining: {:?}", remain).into())
            } else {
                Ok(())
            }
        })
    }()
    .map_err(|e| e.chain_err(|| "Failed to ensure removal of all Stratis DM devices"))
}

/// Try and un-mount any filesystems that have the name stratis in the mount point, returning
/// immediately on the first one we are unable to unmount.
fn stratis_filesystems_unmount() -> Result<()> {
    || -> Result<()> {
        let mut mount_data = String::new();
        File::open("/proc/self/mountinfo")?.read_to_string(&mut mount_data)?;
        let parser = libmount::mountinfo::Parser::new(mount_data.as_bytes());

        for mount_point in parser
            .filter_map(|x| x.ok())
            .filter_map(|m| m.mount_point.into_owned().into_string().ok())
            .filter(|mp| mp.contains("stratis"))
        {
            umount2(&PathBuf::from(mount_point), MntFlags::MNT_DETACH)?;
        }

        Ok(())
    }()
    .map_err(|e| e.chain_err(|| "Failed to ensure all Stratis filesystems were unmounted"))
}

/// When a unit test panics we can leave the system in an inconsistent state.  This function
/// tries to clean up by un-mounting any mounted file systems which contain the string
/// "stratis_testing" and then it tries to remove any device mapper tables which are also stratis
/// created.
pub fn clean_up() -> Result<()> {
    stratis_filesystems_unmount().and_then(|_| dm_stratis_devices_remove())
}
<|endoftext|>


<commit_before>// Code based on https://github.com/defuz/sublimate/blob/master/src/core/syntax/style.rs
// released under the MIT license by @defuz
use bitflags::bitflags;

/// The foreground, background and font style
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Style {
    /// Foreground color.
    pub foreground: Color,
    /// Background color.
    pub background: Color,
    /// Style of the font.
    pub font_style: FontStyle,
}

/// A change to a `Style` applied incrementally by a theme rule.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct StyleModifier {
    /// Foreground color.
    pub foreground: Option<Color>,
    /// Background color.
    pub background: Option<Color>,
    /// Style of the font.
    pub font_style: Option<FontStyle>,
}

/// RGBA color, these numbers come directly from the theme so
/// for now you might have to do your own color space conversion if you are outputting
/// a different color space from the theme. This can be a problem because some Sublime
/// themes use sRGB and some don't. This is specified in an attribute syntect doesn't parse yet.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Color {
    /// Red component
    pub r: u8,
    /// Green component
    pub g: u8,
    /// Blue component
    pub b: u8,
    /// Alpha component
    pub a: u8,
}

bitflags! {
    /// This can be a combination of `BOLD`, `UNDERLINE` and `ITALIC`
    #[derive(Serialize, Deserialize)]
    pub struct FontStyle: u8 {
        /// Bold font style
        const BOLD = 1;
        /// Underline font style
        const UNDERLINE = 2;
        /// Italic font style
        const ITALIC = 4;
    }
}

impl Color {
    /// Black color (`#000000`)
    pub const BLACK: Color = Color {
        r: 0x00,
        g: 0x00,
        b: 0x00,
        a: 0xFF,
    };

    /// White color (`#FFFFFF`)
    pub const WHITE: Color = Color {
        r: 0xFF,
        g: 0xFF,
        b: 0xFF,
        a: 0xFF,
    };

    /// Red CSS colors /////////////////////////////////////////////////////////
    pub const LIGHTSALMON: Color = Color {
        r: 0xFF,
        g: 0xA0,
        b: 0x7A,
        a: 0xFF,
    };
    pub const SALMON: Color = Color {
        r: 0xFA,
        g: 0x80,
        b: 0x72,
        a: 0xFF,
    };
    pub const DARKSALMON: Color = Color {
        r: 0xE9,
        g: 0x96,
        b: 0x7A,
        a: 0xFF,
    };
    pub const LIGHTCORAL: Color = Color {
        r: 0xF0,
        g: 0x80,
        b: 0x80,
        a: 0xFF,
    };
    pub const INDIANRED: Color = Color {
        r: 0xCD,
        g: 0x5C,
        b: 0x5C,
        a: 0xFF,
    };
    pub const CRIMSON: Color = Color {
        r: 0xDC,
        g: 0x14,
        b: 0x3C,
        a: 0xFF,
    };
    pub const FIREBRICK: Color = Color {
        r: 0xB2,
        g: 0x22,
        b: 0x22,
        a: 0xFF,
    };
    pub const RED: Color = Color {
        r: 0xFF,
        g: 0x00,
        b: 0x00,
        a: 0xFF,
    };
    pub const DARKRED: Color = Color {
        r: 0x8B,
        g: 0x00,
        b: 0x00,
        a: 0xFF,
    };

    /// Orange CSS colors //////////////////////////////////////////////////////
    pub const CORAL: Color = Color {
        r: 0xFF,
        g: 0x7F,
        b: 0x50,
        a: 0xFF,
    };
    pub const TOMATO: Color = Color {
        r: 0xFF,
        g: 0x63,
        b: 0x47,
        a: 0xFF,
    };
    pub const ORANGERED: Color = Color {
        r: 0xFF,
        g: 0x45,
        b: 0x00,
        a: 0xFF,
    };
    pub const GOLD: Color = Color {
        r: 0xFF,
        g: 0xD7,
        b: 0x00,
        a: 0xFF,
    };
    pub const ORANGE: Color = Color {
        r: 0xFF,
        g: 0xA5,
        b: 0x00,
        a: 0xFF,
    };
    pub const DARKORANGE: Color = Color {
        r: 0xFF,
        g: 0x8C,
        b: 0x00,
        a: 0xFF,
    };

    /// Yellow CSS colors //////////////////////////////////////////////////////
    pub const LIGHTYELLOW: Color = Color {
        r: 0xFF,
        g: 0xFF,
        b: 0xE0,
        a: 0xFF,
    };
    pub const LEMONCHIFFON: Color = Color {
        r: 0xFF,
        g: 0xFA,
        b: 0xCD,
        a: 0xFF,
    };
    pub const LIGHTGOLDENRODYELLOW: Color = Color {
        r: 0xFA,
        g: 0xFA,
        b: 0xD2,
        a: 0xFF,
    };
    pub const PAPAYAWHIP: Color = Color {
        r: 0xFF,
        g: 0xEF,
        b: 0xD5,
        a: 0xFF,
    };
    pub const MOCCASIN: Color = Color {
        r: 0xFF,
        g: 0xE4,
        b: 0xB5,
        a: 0xFF,
    };
    pub const PEACHPUFF: Color = Color {
        r: 0xFF,
        g: 0xDA,
        b: 0xB9,
        a: 0xFF,
    };
    pub const PALEGOLDENROD: Color = Color {
        r: 0xEE,
        g: 0xE8,
        b: 0xAA,
        a: 0xFF,
    };
    pub const KHAKI: Color = Color {
        r: 0xF0,
        g: 0xE6,
        b: 0x8C,
        a: 0xFF,
    };
    pub const DARKKHAKI: Color = Color {
        r: 0xBD,
        g: 0xB7,
        b: 0x6B,
        a: 0xFF,
    };
    pub const YELLOW: Color = Color {
        r: 0xFF,
        g: 0xFF,
        b: 0x00,
        a: 0xFF,
    };

    /// Green CSS colors ///////////////////////////////////////////////////////
    pub const LAWNGREEN: Color = Color {
        r: 0x7C,
        g: 0xFC,
        b: 0x00,
        a: 0xFF,
    };
    pub const CHARTREUSE: Color = Color {
        r: 0x7F,
        g: 0xFF,
        b: 0x00,
        a: 0xFF,
    };
    pub const LIMEGREEN: Color = Color {
        r: 0x32,
        g: 0xCD,
        b: 0x32,
        a: 0xFF,
    };
    pub const LIME: Color = Color {
        r: 0x00,
        g: 0xFF,
        b: 0x00,
        a: 0xFF,
    };
    pub const FORESTGREEN: Color = Color {
        r: 0x22,
        g: 0x8B,
        b: 0x22,
        a: 0xFF,
    };
    pub const GREEN: Color = Color {
        r: 0x00,
        g: 0x80,
        b: 0x00,
        a: 0xFF,
    };
    pub const DARKGREEN: Color = Color {
        r: 0x00,
        g: 0x64,
        b: 0x00,
        a: 0xFF,
    };
    pub const GREENYELLOW: Color = Color {
        r: 0xAD,
        g: 0xFF,
        b: 0x2F,
        a: 0xFF,
    };
    pub const YELLOWGREEN: Color = Color {
        r: 0x9A,
        g: 0xCD,
        b: 0x32,
        a: 0xFF,
    };
    pub const SPRINGGREEN: Color = Color {
        r: 0x00,
        g: 0xFF,
        b: 0x7F,
        a: 0xFF,
    };
    pub const MEDIUMSPINGGREEN: Color = Color {
        r: 0x00,
        g: 0xFA,
        b: 0x9A,
        a: 0xFF,
    };
    pub const LIGHTGREEN: Color = Color {
        r: 0x90,
        g: 0xEE,
        b: 0x90,
        a: 0xFF,
    };
    pub const PALEGREEN: Color = Color {
        r: 0x98,
        g: 0xFB,
        b: 0x98,
        a: 0xFF,
    };
    pub const DARKSEAGREEN: Color = Color {
        r: 0x8F,
        g: 0xBC,
        b: 0x8F,
        a: 0xFF,
    };
    pub const MEDIUMSEAGREEN: Color = Color {
        r: 0x3C,
        g: 0xB3,
        b: 0x71,
        a: 0xFF,
    };
    pub const SEAGREEN: Color = Color {
        r: 0x2E,
        g: 0x8B,
        b: 0x57,
        a: 0xFF,
    };
    pub const OLIVE: Color = Color {
        r: 0x80,
        g: 0x80,
        b: 0x00,
        a: 0xFF,
    };
    pub const DARKOLIVE: Color = Color {
        r: 0x55,
        g: 0x6B,
        b: 0x2F,
        a: 0xFF,
    };
    pub const OLIVEDRAB: Color = Color {
        r: 0x6B,
        g: 0x8E,
        b: 0x23,
        a: 0xFF,
    };

    /// Cyan CSS colors ////////////////////////////////////////////////////////
    pub const LIGHTCYAN: Color = Color {
        r: 0xE0,
        g: 0xFF,
        b: 0xFF,
        a: 0xFF,
    };
    pub const CYAN: Color = Color {
        r: 0x00,
        g: 0xFF,
        b: 0xFF,
        a: 0xFF,
    };
    pub const AQUA: Color = Color {
        r: 0xE0,
        g: 0xFF,
        b: 0xFF,
        a: 0xFF,
    };
    pub const AQUAMARINE: Color = Color {
        r: 0x7F,
        g: 0xFF,
        b: 0xD4,
        a: 0xFF,
    };
    pub const MEDIUMAQUAMARINE: Color = Color {
        r: 0x66,
        g: 0xCD,
        b: 0xAA,
        a: 0xFF,
    };
    pub const PALETURQUOISE: Color = Color {
        r: 0xAF,
        g: 0xEE,
        b: 0xEE,
        a: 0xFF,
    };
    pub const TURQUOISE: Color = Color {
        r: 0x40,
        g: 0xE0,
        b: 0xD0,
        a: 0xFF,
    };
    pub const MEDIUMTURQUOISE: Color = Color {
        r: 0x48,
        g: 0xD1,
        b: 0xCC,
        a: 0xFF,
    };
    pub const DARKTURQUOISE: Color = Color {
        r: 0x00,
        g: 0xCE,
        b: 0xD1,
        a: 0xFF,
    };
    pub const LIGHTSEAGREEN: Color = Color {
        r: 0x20,
        g: 0xB2,
        b: 0xAA,
        a: 0xFF,
    };
    pub const CADETBLUE: Color = Color {
        r: 0x5F,
        g: 0x9E,
        b: 0xA0,
        a: 0xFF,
    };
    pub const DARKCYAN: Color = Color {
        r: 0x00,
        g: 0x8B,
        b: 0x8B,
        a: 0xFF,
    };
    pub const TEAL: Color = Color {
        r: 0x00,
        g: 0x80,
        b: 0x80,
        a: 0xFF,
    };

    /// Blue CSS colors ////////////////////////////////////////////////////////
    pub const POWDERBLUE: Color = Color {
        r: 0xB0,
        g: 0xE0,
        b: 0xE6,
        a: 0xFF,
    };
    pub const LIGHTBLUE: Color = Color {
        r: 0xAD,
        g: 0xD8,
        b: 0xE6,
        a: 0xFF,
    };
    pub const LIGHTSKYBLUE: Color = Color {
        r: 0x87,
        g: 0xCE,
        b: 0xFA,
        a: 0xFF,
    };
    pub const SKYBLUE: Color = Color {
        r: 0x87,
        g: 0xCE,
        b: 0xEB,
        a: 0xFF,
    };
    pub const DEEPSKYBLUE: Color = Color {
        r: 0x00,
        g: 0xBF,
        b: 0xFF,
        a: 0xFF,
    };
    pub const LIGHTSTEELBLUE: Color = Color {
        r: 0xB0,
        g: 0xC4,
        b: 0xDE,
        a: 0xFF,
    };
    pub const DODGERBLUE: Color = Color {
        r: 0x1E,
        g: 0x90,
        b: 0xFF,
        a: 0xFF,
    };
    pub const CORNFLOWERBLUE: Color = Color {
        r: 0x64,
        g: 0x95,
        b: 0xED,
        a: 0xFF,
    };
    pub const STEELBLUE: Color = Color {
        r: 0x46,
        g: 0x82,
        b: 0xB4,
        a: 0xFF,
    };
    pub const ROYALBLUE: Color = Color {
        r: 0x41,
        g: 0x69,
        b: 0xE1,
        a: 0xFF,
    };
    pub const BLUE: Color = Color {
        r: 0x00,
        g: 0x00,
        b: 0xFF,
        a: 0xFF,
    };
    pub const MEDIUMBLUE: Color = Color {
        r: 0x00,
        g: 0x00,
        b: 0xCD,
        a: 0xFF,
    };
    pub const DARKBLUE: Color = Color {
        r: 0x00,
        g: 0x00,
        b: 0x8B,
        a: 0xFF,
    };
    pub const NAVY: Color = Color {
        r: 0x00,
        g: 0x00,
        b: 0x80,
        a: 0xFF,
    };
    pub const MIDNIGHTBLUE: Color = Color {
        r: 0x19,
        g: 0x19,
        b: 0x70,
        a: 0xFF,
    };
    pub const MEDIUMSLATEBLUE: Color = Color {
        r: 0x7B,
        g: 0x68,
        b: 0xEE,
        a: 0xFF,
    };
    pub const SLATEBLUE: Color = Color {
        r: 0x6A,
        g: 0x5A,
        b: 0xCD,
        a: 0xFF,
    };
    pub const DARKSLATEBLUE: Color = Color {
        r: 0x48,
        g: 0x3D,
        b: 0x8B,
        a: 0xFF,
    };

    /// Purple CSS colors //////////////////////////////////////////////////////
    pub const LAVENDER: Color = Color {
        r: 0xE6,
        g: 0xE6,
        b: 0xFA,
        a: 0xFF,
    };
    pub const THISTLE: Color = Color {
        r: 0xD8,
        g: 0xBF,
        b: 0xD8,
        a: 0xFF,
    };
    pub const PLUM: Color = Color {
        r: 0xDD,
        g: 0xA0,
        b: 0xDD,
        a: 0xFF,
    };
    pub const VIOLET: Color = Color {
        r: 0xEE,
        g: 0x82,
        b: 0xEE,
        a: 0xFF,
    };
    pub const ORCHID: Color = Color {
        r: 0xDA,
        g: 0x70,
        b: 0xD6,
        a: 0xFF,
    };
    pub const FUCHSIA: Color = Color {
        r: 0xFF,
        g: 0x00,
        b: 0xFF,
        a: 0xFF,
    };
    pub const MAGENTA: Color = Color {
        r: 0xFF,
        g: 0x00,
        b: 0xFF,
        a: 0xFF,
    };
    pub const MEDIUMORCHID: Color = Color {
        r: 0xBA,
        g: 0x55,
        b: 0xD3,
        a: 0xFF,
    };
    pub const MEDIUMPURPLE: Color = Color {
        r: 0x93,
        g: 0x70,
        b: 0xDB,
        a: 0xFF,
    };
    pub const BLUEVIOLET: Color = Color {
        r: 0x8A,
        g: 0x2B,
        b: 0xE2,
        a: 0xFF,
    };
    pub const DARKVIOLET: Color = Color {
        r: 0x94,
        g: 0x00,
        b: 0xD3,
        a: 0xFF,
    };
    pub const DARKORCHID: Color = Color {
        r: 0x99,
        g: 0x32,
        b: 0xCC,
        a: 0xFF,
    };
    pub const DARKMAGENTA: Color = Color {
        r: 0x8B,
        g: 0x00,
        b: 0x8B,
        a: 0xFF,
    };
    pub const PURPLE: Color = Color {
        r: 0x80,
        g: 0x00,
        b: 0x80,
        a: 0xFF,
    };
    pub const INDIGO: Color = Color {
        r: 0x4B,
        g: 0x00,
        b: 0x82,
        a: 0xFF,
    };

    /// Pink CSS colors ////////////////////////////////////////////////////////
    pub const PINK: Color = Color {
        r: 0xFF,
        g: 0xC0,
        b: 0xCB,
        a: 0xFF,
    };
    pub const LIGHTPINK: Color = Color {
        r: 0xFF,
        g: 0xB6,
        b: 0xC1,
        a: 0xFF,
    };
    pub const HOTPINK: Color = Color {
        r: 0xFF,
        g: 0x69,
        b: 0xB4,
        a: 0xFF,
    };
    pub const DEEPPINK: Color = Color {
        r: 0xFF,
        g: 0x14,
        b: 0x93,
        a: 0xFF,
    };
    pub const PALEVIOLETRED: Color = Color {
        r: 0xDB,
        g: 0x70,
        b: 0x93,
        a: 0xFF,
    };
    pub const MEDIUMVIOLETRED: Color = Color {
        r: 0xC7,
        g: 0x15,
        b: 0x85,
        a: 0xFF,
    };

    /// White CSS colors ///////////////////////////////////////////////////////
    pub const WHITE: Color = Color {
        r: 0xFF,
        g: 0xFF,
        b: 0xFF,
        a: 0xFF,
    };
    pub const SNOW: Color = Color {
        r: 0xFF,
        g: 0xFA,
        b: 0xFA,
        a: 0xFF,
    };
    pub const HONEYDEW: Color = Color {
        r: 0xF0,
        g: 0xFF,
        b: 0xF0,
        a: 0xFF,
    };
    pub const MINTCREAM: Color = Color {
        r: 0xF5,
        g: 0xFF,
        b: 0xFA,
        a: 0xFF,
    };
    pub const AZURE: Color = Color {
        r: 0xF0,
        g: 0xFF,
        b: 0xFF,
        a: 0xFF,
    };
    pub const ALICEBLUE: Color = Color {
        r: 0xF0,
        g: 0xF8,
        b: 0xFF,
        a: 0xFF,
    };
    pub const GHOSTWHITE: Color = Color {
        r: 0xF8,
        g: 0xF8,
        b: 0xFF,
        a: 0xFF,
    };
    pub const WHITESMOKE: Color = Color {
        r: 0xF5,
        g: 0xF5,
        b: 0xF5,
        a: 0xFF,
    };
    pub const SEASHELL: Color = Color {
        r: 0xFF,
        g: 0xF5,
        b: 0xEE,
        a: 0xFF,
    };
    pub const BEIGE: Color = Color {
        r: 0xF5,
        g: 0xF5,
        b: 0xDC,
        a: 0xFF,
    };
    pub const OLDLACE: Color = Color {
        r: 0xFD,
        g: 0xF5,
        b: 0xE6,
        a: 0xFF,
    };
    pub const FLORALWHITE: Color = Color {
        r: 0xFF,
        g: 0xFA,
        b: 0xF0,
        a: 0xFF,
    };
    pub const IVORY: Color = Color {
        r: 0xFF,
        g: 0xFF,
        b: 0xF0,
        a: 0xFF,
    };
    pub const ANTIQUEWHITE: Color = Color {
        r: 0xFA,
        g: 0xEB,
        b: 0xD7,
        a: 0xFF,
    };
    pub const LINEN: Color = Color {
        r: 0xFA,
        g: 0xF0,
        b: 0xE6,
        a: 0xFF,
    };
    pub const LAVENDERBLUSH: Color = Color {
        r: 0xFF,
        g: 0xF0,
        b: 0xF5,
        a: 0xFF,
    };
    pub const MISTYROSE: Color = Color {
        r: 0xFF,
        g: 0xE4,
        b: 0xE1,
        a: 0xFF,
    };

    /// Gray CSS colors ////////////////////////////////////////////////////////
    pub const GAINSBORO: Color = Color {
        r: 0xDC,
        g: 0xDC,
        b: 0xDC,
        a: 0xFF,
    };
    pub const LIGHTGRAY: Color = Color {
        r: 0xD3,
        g: 0xD3,
        b: 0xD3,
        a: 0xFF,
    };
    pub const SILVER: Color = Color {
        r: 0xC0,
        g: 0xC0,
        b: 0xC0,
        a: 0xFF,
    };
    pub const DARKGRAY: Color = Color {
        r: 0xA9,
        g: 0xA9,
        b: 0xA9,
        a: 0xFF,
    };
    pub const GRAY: Color = Color {
        r: 0x80,
        g: 0x80,
        b: 0x80,
        a: 0xFF,
    };
    pub const DIMGRAY: Color = Color {
        r: 0x69,
        g: 0x69,
        b: 0x69,
        a: 0xFF,
    };
    pub const LIGHTSLATEGRAY: Color = Color {
        r: 0x77,
        g: 0x88,
        b: 0x99,
        a: 0xFF,
    };
    pub const SLATEGRAY: Color = Color {
        r: 0x70,
        g: 0x80,
        b: 0x90,
        a: 0xFF,
    };
    pub const DARKSLATEGRAY: Color = Color {
        r: 0x2F,
        g: 0x4F,
        b: 0x4F,
        a: 0xFF,
    };
    pub const BLACK: Color = Color {
        r: 0x00,
        g: 0x00,
        b: 0x00,
        a: 0xFF,
    };

    /// Brown CSS colors ///////////////////////////////////////////////////////
    pub const CORNSILK: Color = Color {
        r: 0xFF,
        g: 0xF8,
        b: 0xDC,
        a: 0xFF,
    };
    pub const BLANCHEDALMOND: Color = Color {
        r: 0xFF,
        g: 0xEB,
        b: 0xCD,
        a: 0xFF,
    };
    pub const BISQUE: Color = Color {
        r: 0xFF,
        g: 0xE4,
        b: 0xC4,
        a: 0xFF,
    };
    pub const NAVAJOWHITE: Color = Color {
        r: 0xFF,
        g: 0xDE,
        b: 0xAD,
        a: 0xFF,
    };
    pub const WHEAT: Color = Color {
        r: 0xF5,
        g: 0xDE,
        b: 0xB3,
        a: 0xFF,
    };
    pub const BURLYWOOD: Color = Color {
        r: 0xDE,
        g: 0xB8,
        b: 0x87,
        a: 0xFF,
    };
    pub const TAN: Color = Color {
        r: 0xD2,
        g: 0xB4,
        b: 0x8C,
        a: 0xFF,
    };
    pub const ROSYBROWN: Color = Color {
        r: 0xBC,
        g: 0x8F,
        b: 0x8F,
        a: 0xFF,
    };
    pub const SANDYBROWN: Color = Color {
        r: 0xF4,
        g: 0xA4,
        b: 0x60,
        a: 0xFF,
    };
    pub const GOLDENROD: Color = Color {
        r: 0xDA,
        g: 0xA5,
        b: 0x20,
        a: 0xFF,
    };
    pub const PERU: Color = Color {
        r: 0xCD,
        g: 0x85,
        b: 0x3F,
        a: 0xFF,
    };
    pub const CHOCOLATE: Color = Color {
        r: 0xD2,
        g: 0x69,
        b: 0x1E,
        a: 0xFF,
    };
    pub const SADDLEBROWN: Color = Color {
        r: 0x8B,
        g: 0x45,
        b: 0x13,
        a: 0xFF,
    };
    pub const SIENNA: Color = Color {
        r: 0xA0,
        g: 0x52,
        b: 0x2D,
        a: 0xFF,
    };
    pub const BROWN: Color = Color {
        r: 0xA5,
        g: 0x2A,
        b: 0x2A,
        a: 0xFF,
    };
    pub const MAROON: Color = Color {
        r: 0x80,
        g: 0x00,
        b: 0x00,
        a: 0xFF,
    };
}

impl Style {
    /// Applies a change to this style, yielding a new changed style
    pub fn apply(&self, modifier: StyleModifier) -> Style {
        Style {
            foreground: modifier.foreground.unwrap_or(self.foreground),
            background: modifier.background.unwrap_or(self.background),
            font_style: modifier.font_style.unwrap_or(self.font_style),
        }
    }
}

impl Default for Style {
    fn default() -> Style {
        Style {
            foreground: Color::BLACK,
            background: Color::WHITE,
            font_style: FontStyle::empty(),
        }
    }
}

impl StyleModifier {
    /// Applies the other modifier to this one, creating a new modifier.
    /// Values in `other` are preferred.
    pub fn apply(&self, other: StyleModifier) -> StyleModifier {
        StyleModifier {
            foreground: other.foreground.or(self.foreground),
            background: other.background.or(self.background),
            font_style: other.font_style.or(self.font_style),
        }
    }
}
<commit_msg>revert 3015827 upon request<commit_after>// Code based on https://github.com/defuz/sublimate/blob/master/src/core/syntax/style.rs
// released under the MIT license by @defuz
use bitflags::bitflags;

/// The foreground, background and font style
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Style {
    /// Foreground color.
    pub foreground: Color,
    /// Background color.
    pub background: Color,
    /// Style of the font.
    pub font_style: FontStyle,
}

/// A change to a `Style` applied incrementally by a theme rule.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct StyleModifier {
    /// Foreground color.
    pub foreground: Option<Color>,
    /// Background color.
    pub background: Option<Color>,
    /// Style of the font.
    pub font_style: Option<FontStyle>,
}

/// RGBA color, these numbers come directly from the theme so
/// for now you might have to do your own color space conversion if you are outputting
/// a different color space from the theme. This can be a problem because some Sublime
/// themes use sRGB and some don't. This is specified in an attribute syntect doesn't parse yet.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Color {
    /// Red component
    pub r: u8,
    /// Green component
    pub g: u8,
    /// Blue component
    pub b: u8,
    /// Alpha component
    pub a: u8,
}

bitflags! {
    /// This can be a combination of `BOLD`, `UNDERLINE` and `ITALIC`
    #[derive(Serialize, Deserialize)]
    pub struct FontStyle: u8 {
        /// Bold font style
        const BOLD = 1;
        /// Underline font style
        const UNDERLINE = 2;
        /// Italic font style
        const ITALIC = 4;
    }
}

impl Color {
    /// Black color (`#000000`)
    pub const BLACK: Color = Color {
        r: 0x00,
        g: 0x00,
        b: 0x00,
        a: 0xFF,
    };

    /// White color (`#FFFFFF`)
    pub const WHITE: Color = Color {
        r: 0xFF,
        g: 0xFF,
        b: 0xFF,
        a: 0xFF,
    };
}

impl Style {
    /// Applies a change to this style, yielding a new changed style
    pub fn apply(&self, modifier: StyleModifier) -> Style {
        Style {
            foreground: modifier.foreground.unwrap_or(self.foreground),
            background: modifier.background.unwrap_or(self.background),
            font_style: modifier.font_style.unwrap_or(self.font_style),
        }
    }
}

impl Default for Style {
    fn default() -> Style {
        Style {
            foreground: Color::BLACK,
            background: Color::WHITE,
            font_style: FontStyle::empty(),
        }
    }
}

impl StyleModifier {
    /// Applies the other modifier to this one, creating a new modifier.
    /// Values in `other` are preferred.
    pub fn apply(&self, other: StyleModifier) -> StyleModifier {
        StyleModifier {
            foreground: other.foreground.or(self.foreground),
            background: other.background.or(self.background),
            font_style: other.font_style.or(self.font_style),
        }
    }
}
<|endoftext|>


<commit_before>use internal::prelude::*;
use serde::de::{
    self,
    Deserialize,
    Deserializer,
    MapAccess,
    Visitor
};
use serde::ser::Serializer;
use super::super::prelude::*;
use std::{
    collections::HashMap,
    mem::transmute,
    fmt
};

/// Determines to what entity an action was used on.
#[derive(Debug)]
#[repr(u8)]
pub enum Target {
    Guild = 10,
    Channel = 20,
    User = 30,
    Role = 40,
    Invite = 50,
    Webhook = 60,
    Emoji = 70,
}

/// Determines the action that was done on a target.
#[derive(Debug)]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
    MessageDelete,
}

impl Action {
    pub fn num(&self) -> u8 {
        use self::Action::*;

        match *self {
            GuildUpdate => 1,
            Action::Channel(ref x) => x.num(),
            Action::ChannelOverwrite(ref x) => x.num(),
            Action::Member(ref x) => x.num(),
            Action::Role(ref x) => x.num(),
            Action::Invite(ref x) => x.num(),
            Action::Webhook(ref x) => x.num(),
            Action::Emoji(ref x) => x.num(),
            Action::MessageDelete => 72,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannel {
    Create = 10,
    Update = 11,
    Delete = 12,
}

impl ActionChannel {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannel::Create => 10,
            ActionChannel::Update => 11,
            ActionChannel::Delete => 12,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannelOverwrite {
    Create = 13,
    Update = 14,
    Delete = 15,
}

impl ActionChannelOverwrite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannelOverwrite::Create => 13,
            ActionChannelOverwrite::Update => 14,
            ActionChannelOverwrite::Delete => 15,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionMember {
    Kick = 20,
    Prune = 21,
    BanAdd = 22,
    BanRemove = 23,
    Update = 24,
    RoleUpdate = 25,
}

impl ActionMember {
    pub fn num(&self) -> u8 {
        match *self {
            ActionMember::Kick => 20,
            ActionMember::Prune => 21,
            ActionMember::BanAdd => 22,
            ActionMember::BanRemove => 23,
            ActionMember::Update => 24,
            ActionMember::RoleUpdate => 25,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionRole {
    Create = 30,
    Update = 31,
    Delete = 32,
}

impl ActionRole {
    pub fn num(&self) -> u8 {
        match *self {
            ActionRole::Create => 30,
            ActionRole::Update => 31,
            ActionRole::Delete => 32,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionInvite {
    Create = 40,
    Update = 41,
    Delete = 42,
}

impl ActionInvite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionInvite::Create => 40,
            ActionInvite::Update => 41,
            ActionInvite::Delete => 42,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionWebhook {
    Create = 50,
    Update = 51,
    Delete = 52,
}

impl ActionWebhook {
    pub fn num(&self) -> u8 {
        match *self {
            ActionWebhook::Create => 50,
            ActionWebhook::Update => 51,
            ActionWebhook::Delete => 52,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionEmoji {
    Create = 60,
    Delete = 61,
    Update = 62,
}

impl ActionEmoji {
    pub fn num(&self) -> u8 {
        match *self {
            ActionEmoji::Create => 60,
            ActionEmoji::Update => 61,
            ActionEmoji::Delete => 62,
        }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Change {
    #[serde(rename = "key")] pub name: String,
    // TODO: Change these to an actual type.
    #[serde(rename = "old_value")] pub old: String,
    #[serde(rename = "new_value")] pub new: String,
}

#[derive(Debug)]
pub struct AuditLogs {
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
    pub webhooks: Vec<Webhook>,
    pub users: Vec<User>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AuditLogEntry {
    /// Determines to what entity an [`action`] was used on.
    ///
    /// [`action`]: #structfield.action
    pub target_id: u64,
    /// Determines what action was done on a [`target`]
    ///
    /// [`target`]: #structfield.target
    #[serde(deserialize_with = "deserialize_action",
            rename = "action_type",
            serialize_with = "serialize_action")]
    pub action: Action,
    /// What was the reasoning by doing an action on a target? If there was one.
    pub reason: Option<String>,
    /// The user that did this action on a target.
    pub user_id: UserId,
    /// What changes were made.
    pub changes: Option<Vec<Change>>,
    /// The id of this entry.
    pub id: AuditLogEntryId,
    /// Some optional data assosiated with this entry.
    pub options: Option<Options>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Options {
    /// Number of days after which inactive members were kicked.
    pub delete_member_days: String,
    /// Number of members removed by the prune
    pub members_removed: String,
    /// Channel in which the messages were deleted
    pub channel_id: ChannelId,
    /// Number of deleted messages.
    pub count: u32,
    /// Id of the overwritten entity
    pub id: u64,
    /// Type of overwritten entity ("member" or "role").
    #[serde(rename = "type")] pub kind: String,
    /// Name of the role if type is "role"
    pub role_name: String,
}

fn deserialize_action<'de, D: Deserializer<'de>>(de: D) -> StdResult<Action, D::Error> {
    struct ActionVisitor;

    impl<'de> Visitor<'de> for ActionVisitor {
        type Value = Action;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("an integer between 1 to 72")
        }

        fn visit_u8<E: de::Error>(self, value: u8) -> StdResult<Action, E> {
            Ok(match value {
                1 => Action::GuildUpdate,
                10...12 => Action::Channel(unsafe { transmute(value) }),
                13...15 => Action::ChannelOverwrite(unsafe { transmute(value) }),
                20...25 => Action::Member(unsafe { transmute(value) }),
                30...32 => Action::Role(unsafe { transmute(value) }),
                40...42 => Action::Invite(unsafe { transmute(value) }),
                50...52 => Action::Webhook(unsafe { transmute(value) }),
                60...62 => Action::Emoji(unsafe { transmute(value) }),
                72 => Action::MessageDelete,
                _ => return Err(E::custom(format!("Unexpected action number: {}", value))),
            })
        }
    }

    de.deserialize_u8(ActionVisitor)
}

fn serialize_action<S: Serializer>(
    action: &Action,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    serializer.serialize_u8(action.num())
}

impl<'de> Deserialize<'de> for AuditLogs {
    fn deserialize<D: Deserializer<'de>>(de: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier)]
        enum Field {
            #[serde(rename = "audit_log_entries")] Entries,
            #[serde(rename = "webhooks")] Webhooks,
            #[serde(rename = "users")] Users,
        }

        struct EntriesVisitor;

        impl<'de> Visitor<'de> for EntriesVisitor {
            type Value = AuditLogs;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("audit log entries")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<AuditLogs, V::Error> {
                let mut audit_log_entries = None;
                let mut users = None;
                let mut webhooks = None;

                while let Some(field) = map.next_key()? {
                    match field {
                        Field::Entries => {
                            if audit_log_entries.is_some() {
                                return Err(de::Error::duplicate_field("entries"));
                            }

                            audit_log_entries = Some(map.next_value::<Vec<AuditLogEntry>>()?);
                        },
                        Field::Webhooks => {
                            if webhooks.is_some() {
                                return Err(de::Error::duplicate_field("webhooks"));
                            }

                            webhooks = Some(map.next_value::<Vec<Webhook>>()?);
                        },
                        Field::Users => {
                            if users.is_some() {
                                return Err(de::Error::duplicate_field("users"));
                            }

                            users = Some(map.next_value::<Vec<User>>()?);
                        },
                    }
                }

                Ok(AuditLogs {
                    entries: audit_log_entries
                        .unwrap()
                        .into_iter()
                        .map(|entry| (entry.id, entry))
                        .collect(),
                    webhooks: webhooks.unwrap(),
                    users: users.unwrap(),
                })
            }
        }

        const FIELD: &[&str] = &["audit_log_entries"];
        de.deserialize_struct("AuditLogs", FIELD, EntriesVisitor)
    }
}
<commit_msg>Handle (de)serializing `target_id` from/to a string<commit_after>use internal::prelude::*;
use serde::de::{
    self,
    Deserialize,
    Deserializer,
    MapAccess,
    Visitor
};
use serde::ser::Serializer;
use super::super::prelude::*;
use std::{
    collections::HashMap,
    mem::transmute,
    fmt
};

/// Determines to what entity an action was used on.
#[derive(Debug)]
#[repr(u8)]
pub enum Target {
    Guild = 10,
    Channel = 20,
    User = 30,
    Role = 40,
    Invite = 50,
    Webhook = 60,
    Emoji = 70,
}

/// Determines the action that was done on a target.
#[derive(Debug)]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
    MessageDelete,
}

impl Action {
    pub fn num(&self) -> u8 {
        use self::Action::*;

        match *self {
            GuildUpdate => 1,
            Action::Channel(ref x) => x.num(),
            Action::ChannelOverwrite(ref x) => x.num(),
            Action::Member(ref x) => x.num(),
            Action::Role(ref x) => x.num(),
            Action::Invite(ref x) => x.num(),
            Action::Webhook(ref x) => x.num(),
            Action::Emoji(ref x) => x.num(),
            Action::MessageDelete => 72,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannel {
    Create = 10,
    Update = 11,
    Delete = 12,
}

impl ActionChannel {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannel::Create => 10,
            ActionChannel::Update => 11,
            ActionChannel::Delete => 12,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannelOverwrite {
    Create = 13,
    Update = 14,
    Delete = 15,
}

impl ActionChannelOverwrite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannelOverwrite::Create => 13,
            ActionChannelOverwrite::Update => 14,
            ActionChannelOverwrite::Delete => 15,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionMember {
    Kick = 20,
    Prune = 21,
    BanAdd = 22,
    BanRemove = 23,
    Update = 24,
    RoleUpdate = 25,
}

impl ActionMember {
    pub fn num(&self) -> u8 {
        match *self {
            ActionMember::Kick => 20,
            ActionMember::Prune => 21,
            ActionMember::BanAdd => 22,
            ActionMember::BanRemove => 23,
            ActionMember::Update => 24,
            ActionMember::RoleUpdate => 25,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionRole {
    Create = 30,
    Update = 31,
    Delete = 32,
}

impl ActionRole {
    pub fn num(&self) -> u8 {
        match *self {
            ActionRole::Create => 30,
            ActionRole::Update => 31,
            ActionRole::Delete => 32,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionInvite {
    Create = 40,
    Update = 41,
    Delete = 42,
}

impl ActionInvite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionInvite::Create => 40,
            ActionInvite::Update => 41,
            ActionInvite::Delete => 42,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionWebhook {
    Create = 50,
    Update = 51,
    Delete = 52,
}

impl ActionWebhook {
    pub fn num(&self) -> u8 {
        match *self {
            ActionWebhook::Create => 50,
            ActionWebhook::Update => 51,
            ActionWebhook::Delete => 52,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionEmoji {
    Create = 60,
    Delete = 61,
    Update = 62,
}

impl ActionEmoji {
    pub fn num(&self) -> u8 {
        match *self {
            ActionEmoji::Create => 60,
            ActionEmoji::Update => 61,
            ActionEmoji::Delete => 62,
        }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Change {
    #[serde(rename = "key")] pub name: String,
    // TODO: Change these to an actual type.
    #[serde(rename = "old_value")] pub old: String,
    #[serde(rename = "new_value")] pub new: String,
}

#[derive(Debug)]
pub struct AuditLogs {
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
    pub webhooks: Vec<Webhook>,
    pub users: Vec<User>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AuditLogEntry {
    /// Determines to what entity an [`action`] was used on.
    ///
    /// [`action`]: #structfield.action
    #[serde(with = "u64_handler")]
    pub target_id: u64,
    /// Determines what action was done on a [`target`]
    ///
    /// [`target`]: #structfield.target
    #[serde(deserialize_with = "deserialize_action",
            rename = "action_type",
            serialize_with = "serialize_action")]
    pub action: Action,
    /// What was the reasoning by doing an action on a target? If there was one.
    pub reason: Option<String>,
    /// The user that did this action on a target.
    pub user_id: UserId,
    /// What changes were made.
    pub changes: Option<Vec<Change>>,
    /// The id of this entry.
    pub id: AuditLogEntryId,
    /// Some optional data assosiated with this entry.
    pub options: Option<Options>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Options {
    /// Number of days after which inactive members were kicked.
    pub delete_member_days: String,
    /// Number of members removed by the prune
    pub members_removed: String,
    /// Channel in which the messages were deleted
    pub channel_id: ChannelId,
    /// Number of deleted messages.
    pub count: u32,
    /// Id of the overwritten entity
    pub id: u64,
    /// Type of overwritten entity ("member" or "role").
    #[serde(rename = "type")] pub kind: String,
    /// Name of the role if type is "role"
    pub role_name: String,
}

mod u64_handler {
    use super::*;

    pub fn deserialize<'de, D: Deserializer<'de>>(des: D) -> StdResult<u64, D::Error> {
        struct U64Visitor;

        impl<'de> Visitor<'de> for U64Visitor {
            type Value = u64;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an integer or a string with a valid number inside")
            }

            // NOTE: Serde internally delegates number types below `u64` to it.
            fn visit_u64<E: de::Error>(self, val: u64) -> StdResult<u64, E> {
                Ok(val)
            }

            fn visit_str<E: de::Error>(self, string: &str) -> StdResult<u64, E> {
                string.parse().map_err(|e| de::Error::custom(e))
            }
        }

        des.deserialize_any(U64Visitor)
    }

    pub fn serialize<S: Serializer>(num: &u64, s: S) -> StdResult<S::Ok, S::Error> {
        s.serialize_u64(*num)
    }
}

fn deserialize_action<'de, D: Deserializer<'de>>(de: D) -> StdResult<Action, D::Error> {
    struct ActionVisitor;

    impl<'de> Visitor<'de> for ActionVisitor {
        type Value = Action;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("an integer between 1 to 72")
        }

        // NOTE: Serde internally delegates number types below `u64` to it.
        fn visit_u64<E: de::Error>(self, value: u64) -> StdResult<Action, E> {
            let value = value as u8;

            Ok(match value {
                1 => Action::GuildUpdate,
                10...12 => Action::Channel(unsafe { transmute(value) }),
                13...15 => Action::ChannelOverwrite(unsafe { transmute(value) }),
                20...25 => Action::Member(unsafe { transmute(value) }),
                30...32 => Action::Role(unsafe { transmute(value) }),
                40...42 => Action::Invite(unsafe { transmute(value) }),
                50...52 => Action::Webhook(unsafe { transmute(value) }),
                60...62 => Action::Emoji(unsafe { transmute(value) }),
                72 => Action::MessageDelete,
                _ => return Err(E::custom(format!("Unexpected action number: {}", value))),
            })
        }
    }

    de.deserialize_any(ActionVisitor)
}

fn serialize_action<S: Serializer>(
    action: &Action,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    serializer.serialize_u8(action.num())
}

impl<'de> Deserialize<'de> for AuditLogs {
    fn deserialize<D: Deserializer<'de>>(de: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier)]
        enum Field {
            #[serde(rename = "audit_log_entries")] Entries,
            #[serde(rename = "webhooks")] Webhooks,
            #[serde(rename = "users")] Users,
        }

        struct EntriesVisitor;

        impl<'de> Visitor<'de> for EntriesVisitor {
            type Value = AuditLogs;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("audit log entries")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<AuditLogs, V::Error> {
                let mut audit_log_entries = None;
                let mut users = None;
                let mut webhooks = None;

                while let Some(field) = map.next_key()? {
                    match field {
                        Field::Entries => {
                            if audit_log_entries.is_some() {
                                return Err(de::Error::duplicate_field("entries"));
                            }

                            audit_log_entries = Some(map.next_value::<Vec<AuditLogEntry>>()?);
                        },
                        Field::Webhooks => {
                            if webhooks.is_some() {
                                return Err(de::Error::duplicate_field("webhooks"));
                            }

                            webhooks = Some(map.next_value::<Vec<Webhook>>()?);
                        },
                        Field::Users => {
                            if users.is_some() {
                                return Err(de::Error::duplicate_field("users"));
                            }

                            users = Some(map.next_value::<Vec<User>>()?);
                        },
                    }
                }

                Ok(AuditLogs {
                    entries: audit_log_entries
                        .unwrap()
                        .into_iter()
                        .map(|entry| (entry.id, entry))
                        .collect(),
                    webhooks: webhooks.unwrap(),
                    users: users.unwrap(),
                })
            }
        }

        const FIELD: &[&str] = &["audit_log_entries"];
        de.deserialize_struct("AuditLogs", FIELD, EntriesVisitor)
    }
}
<|endoftext|>


<commit_before>//! An analysis to determine which locals require allocas and
//! which do not.

use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::{self, Location, TerminatorKind};
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
use rustc::mir::traversal;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, HasTyCtxt};
use super::FunctionCx;
use crate::traits::*;

pub fn non_ssa_locals<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
    fx: &FunctionCx<'a, 'tcx, Bx>
) -> BitSet<mir::Local> {
    let mir = fx.mir;
    let mut analyzer = LocalAnalyzer::new(fx);

    analyzer.visit_mir(mir);

    for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() {
        let ty = fx.monomorphize(&ty);
        debug!("local {} has type {:?}", index, ty);
        let layout = fx.cx.layout_of(ty);
        if fx.cx.is_backend_immediate(layout) {
            // These sorts of types are immediates that we can store
            // in an Value without an alloca.
        } else if fx.cx.is_backend_scalar_pair(layout) {
            // We allow pairs and uses of any of their 2 fields.
        } else {
            // These sorts of types require an alloca. Note that
            // is_llvm_immediate() may *still* be true, particularly
            // for newtypes, but we currently force some types
            // (e.g., structs) into an alloca unconditionally, just so
            // that we don't have to deal with having two pathways
            // (gep vs extractvalue etc).
            analyzer.not_ssa(mir::Local::new(index));
        }
    }

    analyzer.non_ssa_locals
}

struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> {
    fx: &'mir FunctionCx<'a, 'tcx, Bx>,
    dominators: Dominators<mir::BasicBlock>,
    non_ssa_locals: BitSet<mir::Local>,
    // The location of the first visited direct assignment to each
    // local, or an invalid location (out of bounds `block` index).
    first_assignment: IndexVec<mir::Local, Location>
}

impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
    fn new(fx: &'mir FunctionCx<'a, 'tcx, Bx>) -> Self {
        let invalid_location =
            mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location();
        let mut analyzer = LocalAnalyzer {
            fx,
            dominators: fx.mir.dominators(),
            non_ssa_locals: BitSet::new_empty(fx.mir.local_decls.len()),
            first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls)
        };

        // Arguments get assigned to by means of the function being called
        for arg in fx.mir.args_iter() {
            analyzer.first_assignment[arg] = mir::START_BLOCK.start_location();
        }

        analyzer
    }

    fn first_assignment(&self, local: mir::Local) -> Option<Location> {
        let location = self.first_assignment[local];
        if location.block.index() < self.fx.mir.basic_blocks().len() {
            Some(location)
        } else {
            None
        }
    }

    fn not_ssa(&mut self, local: mir::Local) {
        debug!("marking {:?} as non-SSA", local);
        self.non_ssa_locals.insert(local);
    }

    fn assign(&mut self, local: mir::Local, location: Location) {
        if self.first_assignment(local).is_some() {
            self.not_ssa(local);
        } else {
            self.first_assignment[local] = location;
        }
    }
}

impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
    for LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
    fn visit_assign(&mut self,
                    place: &mir::Place<'tcx>,
                    rvalue: &mir::Rvalue<'tcx>,
                    location: Location) {
        debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);

        if let mir::Place::Base(mir::PlaceBase::Local(index)) = *place {
            self.assign(index, location);
            if !self.fx.rvalue_creates_operand(rvalue) {
                self.not_ssa(index);
            }
        } else {
            self.visit_place(
                place,
                PlaceContext::MutatingUse(MutatingUseContext::Store),
                location
            );
        }

        self.visit_rvalue(rvalue, location);
    }

    fn visit_terminator_kind(&mut self,
                             kind: &mir::TerminatorKind<'tcx>,
                             location: Location) {
        let check = match *kind {
            mir::TerminatorKind::Call {
                func: mir::Operand::Constant(ref c),
                ref args, ..
            } => match c.ty.sty {
                ty::FnDef(did, _) => Some((did, args)),
                _ => None,
            },
            _ => None,
        };
        if let Some((def_id, args)) = check {
            if Some(def_id) == self.fx.cx.tcx().lang_items().box_free_fn() {
                // box_free(x) shares with `drop x` the property that it
                // is not guaranteed to be statically dominated by the
                // definition of x, so x must always be in an alloca.
                if let mir::Operand::Move(ref place) = args[0] {
                    self.visit_place(
                        place,
                        PlaceContext::MutatingUse(MutatingUseContext::Drop),
                        location
                    );
                }
            }
        }

        self.super_terminator_kind(kind, location);
    }

    fn visit_place(&mut self,
                   place: &mir::Place<'tcx>,
                   context: PlaceContext,
                   location: Location) {
        debug!("visit_place(place={:?}, context={:?})", place, context);
        let cx = self.fx.cx;

        if let mir::Place::Projection(ref proj) = *place {
            // Allow uses of projections that are ZSTs or from scalar fields.
            let is_consume = match context {
                PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
                PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true,
                _ => false
            };
            if is_consume {
                let base_ty = proj.base.ty(self.fx.mir, cx.tcx());
                let base_ty = self.fx.monomorphize(&base_ty);

                // ZSTs don't require any actual memory access.
                let elem_ty = base_ty
                    .projection_ty(cx.tcx(), &proj.elem)
                    .ty;
                let elem_ty = self.fx.monomorphize(&elem_ty);
                if cx.layout_of(elem_ty).is_zst() {
                    return;
                }

                if let mir::ProjectionElem::Field(..) = proj.elem {
                    let layout = cx.layout_of(base_ty.ty);
                    if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
                        // Recurse with the same context, instead of `Projection`,
                        // potentially stopping at non-operand projections,
                        // which would trigger `not_ssa` on locals.
                        self.visit_place(&proj.base, context, location);
                        return;
                    }
                }
            }

            // A deref projection only reads the pointer, never needs the place.
            if let mir::ProjectionElem::Deref = proj.elem {
                return self.visit_place(
                    &proj.base,
                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
                    location
                );
            }
        }

        self.super_place(place, context, location);
    }

    fn visit_local(&mut self,
                   &local: &mir::Local,
                   context: PlaceContext,
                   location: Location) {
        match context {
            PlaceContext::MutatingUse(MutatingUseContext::Call) => {
                self.assign(local, location);
            }

            PlaceContext::NonUse(_) |
            PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}

            PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
            PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => {
                // Reads from uninitialized variables (e.g., in dead code, after
                // optimizations) require locals to be in (uninitialized) memory.
                // N.B., there can be uninitialized reads of a local visited after
                // an assignment to that local, if they happen on disjoint paths.
                let ssa_read = match self.first_assignment(local) {
                    Some(assignment_location) => {
                        assignment_location.dominates(location, &self.dominators)
                    }
                    None => false
                };
                if !ssa_read {
                    self.not_ssa(local);
                }
            }

            PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
            PlaceContext::MutatingUse(MutatingUseContext::Store) |
            PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
            PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
            PlaceContext::MutatingUse(MutatingUseContext::Projection) |
            PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
            PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
            PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
            PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
                self.not_ssa(local);
            }

            PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
                let ty = mir::Place::Base(mir::PlaceBase::Local(local)).ty(self.fx.mir,
                                                                           self.fx.cx.tcx());
                let ty = self.fx.monomorphize(&ty.ty);

                // Only need the place if we're actually dropping it.
                if self.fx.cx.type_needs_drop(ty) {
                    self.not_ssa(local);
                }
            }
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CleanupKind {
    NotCleanup,
    Funclet,
    Internal { funclet: mir::BasicBlock }
}

impl CleanupKind {
    pub fn funclet_bb(self, for_bb: mir::BasicBlock) -> Option<mir::BasicBlock> {
        match self {
            CleanupKind::NotCleanup => None,
            CleanupKind::Funclet => Some(for_bb),
            CleanupKind::Internal { funclet } => Some(funclet),
        }
    }
}

pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock, CleanupKind> {
    fn discover_masters<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
                              mir: &mir::Mir<'tcx>) {
        for (bb, data) in mir.basic_blocks().iter_enumerated() {
            match data.terminator().kind {
                TerminatorKind::Goto { .. } |
                TerminatorKind::Resume |
                TerminatorKind::Abort |
                TerminatorKind::Return |
                TerminatorKind::GeneratorDrop |
                TerminatorKind::Unreachable |
                TerminatorKind::SwitchInt { .. } |
                TerminatorKind::Yield { .. } |
                TerminatorKind::FalseEdges { .. } |
                TerminatorKind::FalseUnwind { .. } => {
                    /* nothing to do */
                }
                TerminatorKind::Call { cleanup: unwind, .. } |
                TerminatorKind::Assert { cleanup: unwind, .. } |
                TerminatorKind::DropAndReplace { unwind, .. } |
                TerminatorKind::Drop { unwind, .. } => {
                    if let Some(unwind) = unwind {
                        debug!("cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
                               bb, data, unwind);
                        result[unwind] = CleanupKind::Funclet;
                    }
                }
            }
        }
    }

    fn propagate<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
                       mir: &mir::Mir<'tcx>) {
        let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks());

        let mut set_successor = |funclet: mir::BasicBlock, succ| {
            match funclet_succs[funclet] {
                ref mut s @ None => {
                    debug!("set_successor: updating successor of {:?} to {:?}",
                           funclet, succ);
                    *s = Some(succ);
                },
                Some(s) => if s != succ {
                    span_bug!(mir.span, "funclet {:?} has 2 parents - {:?} and {:?}",
                              funclet, s, succ);
                }
            }
        };

        for (bb, data) in traversal::reverse_postorder(mir) {
            let funclet = match result[bb] {
                CleanupKind::NotCleanup => continue,
                CleanupKind::Funclet => bb,
                CleanupKind::Internal { funclet } => funclet,
            };

            debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}",
                   bb, data, result[bb], funclet);

            for &succ in data.terminator().successors() {
                let kind = result[succ];
                debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}",
                       funclet, succ, kind);
                match kind {
                    CleanupKind::NotCleanup => {
                        result[succ] = CleanupKind::Internal { funclet };
                    }
                    CleanupKind::Funclet => {
                        if funclet != succ {
                            set_successor(funclet, succ);
                        }
                    }
                    CleanupKind::Internal { funclet: succ_funclet } => {
                        if funclet != succ_funclet {
                            // `succ` has 2 different funclet going into it, so it must
                            // be a funclet by itself.

                            debug!("promoting {:?} to a funclet and updating {:?}", succ,
                                   succ_funclet);
                            result[succ] = CleanupKind::Funclet;
                            set_successor(succ_funclet, succ);
                            set_successor(funclet, succ);
                        }
                    }
                }
            }
        }
    }

    let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, mir.basic_blocks());

    discover_masters(&mut result, mir);
    propagate(&mut result, mir);
    debug!("cleanup_kinds: result={:?}", result);
    result
}
<commit_msg>Rollup merge of #60862 - spastorino:get-ty-from-local_decls, r=oli-obk<commit_after>//! An analysis to determine which locals require allocas and
//! which do not.

use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::{self, Location, TerminatorKind};
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
use rustc::mir::traversal;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, HasTyCtxt};
use super::FunctionCx;
use crate::traits::*;

pub fn non_ssa_locals<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
    fx: &FunctionCx<'a, 'tcx, Bx>
) -> BitSet<mir::Local> {
    let mir = fx.mir;
    let mut analyzer = LocalAnalyzer::new(fx);

    analyzer.visit_mir(mir);

    for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() {
        let ty = fx.monomorphize(&ty);
        debug!("local {} has type {:?}", index, ty);
        let layout = fx.cx.layout_of(ty);
        if fx.cx.is_backend_immediate(layout) {
            // These sorts of types are immediates that we can store
            // in an Value without an alloca.
        } else if fx.cx.is_backend_scalar_pair(layout) {
            // We allow pairs and uses of any of their 2 fields.
        } else {
            // These sorts of types require an alloca. Note that
            // is_llvm_immediate() may *still* be true, particularly
            // for newtypes, but we currently force some types
            // (e.g., structs) into an alloca unconditionally, just so
            // that we don't have to deal with having two pathways
            // (gep vs extractvalue etc).
            analyzer.not_ssa(mir::Local::new(index));
        }
    }

    analyzer.non_ssa_locals
}

struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> {
    fx: &'mir FunctionCx<'a, 'tcx, Bx>,
    dominators: Dominators<mir::BasicBlock>,
    non_ssa_locals: BitSet<mir::Local>,
    // The location of the first visited direct assignment to each
    // local, or an invalid location (out of bounds `block` index).
    first_assignment: IndexVec<mir::Local, Location>
}

impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
    fn new(fx: &'mir FunctionCx<'a, 'tcx, Bx>) -> Self {
        let invalid_location =
            mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location();
        let mut analyzer = LocalAnalyzer {
            fx,
            dominators: fx.mir.dominators(),
            non_ssa_locals: BitSet::new_empty(fx.mir.local_decls.len()),
            first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls)
        };

        // Arguments get assigned to by means of the function being called
        for arg in fx.mir.args_iter() {
            analyzer.first_assignment[arg] = mir::START_BLOCK.start_location();
        }

        analyzer
    }

    fn first_assignment(&self, local: mir::Local) -> Option<Location> {
        let location = self.first_assignment[local];
        if location.block.index() < self.fx.mir.basic_blocks().len() {
            Some(location)
        } else {
            None
        }
    }

    fn not_ssa(&mut self, local: mir::Local) {
        debug!("marking {:?} as non-SSA", local);
        self.non_ssa_locals.insert(local);
    }

    fn assign(&mut self, local: mir::Local, location: Location) {
        if self.first_assignment(local).is_some() {
            self.not_ssa(local);
        } else {
            self.first_assignment[local] = location;
        }
    }
}

impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
    for LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
    fn visit_assign(&mut self,
                    place: &mir::Place<'tcx>,
                    rvalue: &mir::Rvalue<'tcx>,
                    location: Location) {
        debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);

        if let mir::Place::Base(mir::PlaceBase::Local(index)) = *place {
            self.assign(index, location);
            if !self.fx.rvalue_creates_operand(rvalue) {
                self.not_ssa(index);
            }
        } else {
            self.visit_place(
                place,
                PlaceContext::MutatingUse(MutatingUseContext::Store),
                location
            );
        }

        self.visit_rvalue(rvalue, location);
    }

    fn visit_terminator_kind(&mut self,
                             kind: &mir::TerminatorKind<'tcx>,
                             location: Location) {
        let check = match *kind {
            mir::TerminatorKind::Call {
                func: mir::Operand::Constant(ref c),
                ref args, ..
            } => match c.ty.sty {
                ty::FnDef(did, _) => Some((did, args)),
                _ => None,
            },
            _ => None,
        };
        if let Some((def_id, args)) = check {
            if Some(def_id) == self.fx.cx.tcx().lang_items().box_free_fn() {
                // box_free(x) shares with `drop x` the property that it
                // is not guaranteed to be statically dominated by the
                // definition of x, so x must always be in an alloca.
                if let mir::Operand::Move(ref place) = args[0] {
                    self.visit_place(
                        place,
                        PlaceContext::MutatingUse(MutatingUseContext::Drop),
                        location
                    );
                }
            }
        }

        self.super_terminator_kind(kind, location);
    }

    fn visit_place(&mut self,
                   place: &mir::Place<'tcx>,
                   context: PlaceContext,
                   location: Location) {
        debug!("visit_place(place={:?}, context={:?})", place, context);
        let cx = self.fx.cx;

        if let mir::Place::Projection(ref proj) = *place {
            // Allow uses of projections that are ZSTs or from scalar fields.
            let is_consume = match context {
                PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
                PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true,
                _ => false
            };
            if is_consume {
                let base_ty = proj.base.ty(self.fx.mir, cx.tcx());
                let base_ty = self.fx.monomorphize(&base_ty);

                // ZSTs don't require any actual memory access.
                let elem_ty = base_ty
                    .projection_ty(cx.tcx(), &proj.elem)
                    .ty;
                let elem_ty = self.fx.monomorphize(&elem_ty);
                if cx.layout_of(elem_ty).is_zst() {
                    return;
                }

                if let mir::ProjectionElem::Field(..) = proj.elem {
                    let layout = cx.layout_of(base_ty.ty);
                    if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
                        // Recurse with the same context, instead of `Projection`,
                        // potentially stopping at non-operand projections,
                        // which would trigger `not_ssa` on locals.
                        self.visit_place(&proj.base, context, location);
                        return;
                    }
                }
            }

            // A deref projection only reads the pointer, never needs the place.
            if let mir::ProjectionElem::Deref = proj.elem {
                return self.visit_place(
                    &proj.base,
                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
                    location
                );
            }
        }

        self.super_place(place, context, location);
    }

    fn visit_local(&mut self,
                   &local: &mir::Local,
                   context: PlaceContext,
                   location: Location) {
        match context {
            PlaceContext::MutatingUse(MutatingUseContext::Call) => {
                self.assign(local, location);
            }

            PlaceContext::NonUse(_) |
            PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}

            PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
            PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => {
                // Reads from uninitialized variables (e.g., in dead code, after
                // optimizations) require locals to be in (uninitialized) memory.
                // N.B., there can be uninitialized reads of a local visited after
                // an assignment to that local, if they happen on disjoint paths.
                let ssa_read = match self.first_assignment(local) {
                    Some(assignment_location) => {
                        assignment_location.dominates(location, &self.dominators)
                    }
                    None => false
                };
                if !ssa_read {
                    self.not_ssa(local);
                }
            }

            PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
            PlaceContext::MutatingUse(MutatingUseContext::Store) |
            PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
            PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
            PlaceContext::MutatingUse(MutatingUseContext::Projection) |
            PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
            PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
            PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
            PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
                self.not_ssa(local);
            }

            PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
                let ty = self.fx.mir.local_decls[local].ty;
                let ty = self.fx.monomorphize(&ty);

                // Only need the place if we're actually dropping it.
                if self.fx.cx.type_needs_drop(ty) {
                    self.not_ssa(local);
                }
            }
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CleanupKind {
    NotCleanup,
    Funclet,
    Internal { funclet: mir::BasicBlock }
}

impl CleanupKind {
    pub fn funclet_bb(self, for_bb: mir::BasicBlock) -> Option<mir::BasicBlock> {
        match self {
            CleanupKind::NotCleanup => None,
            CleanupKind::Funclet => Some(for_bb),
            CleanupKind::Internal { funclet } => Some(funclet),
        }
    }
}

pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock, CleanupKind> {
    fn discover_masters<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
                              mir: &mir::Mir<'tcx>) {
        for (bb, data) in mir.basic_blocks().iter_enumerated() {
            match data.terminator().kind {
                TerminatorKind::Goto { .. } |
                TerminatorKind::Resume |
                TerminatorKind::Abort |
                TerminatorKind::Return |
                TerminatorKind::GeneratorDrop |
                TerminatorKind::Unreachable |
                TerminatorKind::SwitchInt { .. } |
                TerminatorKind::Yield { .. } |
                TerminatorKind::FalseEdges { .. } |
                TerminatorKind::FalseUnwind { .. } => {
                    /* nothing to do */
                }
                TerminatorKind::Call { cleanup: unwind, .. } |
                TerminatorKind::Assert { cleanup: unwind, .. } |
                TerminatorKind::DropAndReplace { unwind, .. } |
                TerminatorKind::Drop { unwind, .. } => {
                    if let Some(unwind) = unwind {
                        debug!("cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
                               bb, data, unwind);
                        result[unwind] = CleanupKind::Funclet;
                    }
                }
            }
        }
    }

    fn propagate<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
                       mir: &mir::Mir<'tcx>) {
        let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks());

        let mut set_successor = |funclet: mir::BasicBlock, succ| {
            match funclet_succs[funclet] {
                ref mut s @ None => {
                    debug!("set_successor: updating successor of {:?} to {:?}",
                           funclet, succ);
                    *s = Some(succ);
                },
                Some(s) => if s != succ {
                    span_bug!(mir.span, "funclet {:?} has 2 parents - {:?} and {:?}",
                              funclet, s, succ);
                }
            }
        };

        for (bb, data) in traversal::reverse_postorder(mir) {
            let funclet = match result[bb] {
                CleanupKind::NotCleanup => continue,
                CleanupKind::Funclet => bb,
                CleanupKind::Internal { funclet } => funclet,
            };

            debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}",
                   bb, data, result[bb], funclet);

            for &succ in data.terminator().successors() {
                let kind = result[succ];
                debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}",
                       funclet, succ, kind);
                match kind {
                    CleanupKind::NotCleanup => {
                        result[succ] = CleanupKind::Internal { funclet };
                    }
                    CleanupKind::Funclet => {
                        if funclet != succ {
                            set_successor(funclet, succ);
                        }
                    }
                    CleanupKind::Internal { funclet: succ_funclet } => {
                        if funclet != succ_funclet {
                            // `succ` has 2 different funclet going into it, so it must
                            // be a funclet by itself.

                            debug!("promoting {:?} to a funclet and updating {:?}", succ,
                                   succ_funclet);
                            result[succ] = CleanupKind::Funclet;
                            set_successor(succ_funclet, succ);
                            set_successor(funclet, succ);
                        }
                    }
                }
            }
        }
    }

    let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, mir.basic_blocks());

    discover_masters(&mut result, mir);
    propagate(&mut result, mir);
    debug!("cleanup_kinds: result={:?}", result);
    result
}
<|endoftext|>


<commit_before>use std::io::{File, Truncate, Write};
use std::os;
use std::thread::Thread;

pub mod branchify;
pub mod status;
pub mod read_method;

fn main() {
    Thread::spawn(move || {
        let output_dir = Path::new(os::getenv("OUT_DIR").unwrap());
        read_method::generate(output_dir).unwrap();
    });

    let output_dir = Path::new(os::getenv("OUT_DIR").unwrap());
    status::generate(output_dir).unwrap();
}

pub fn get_writer(mut output_dir: Path, filename: &str) -> Box<Writer + 'static> {
    output_dir.push(filename);
    match File::open_mode(&output_dir, Truncate, Write) {
        Ok(writer) => box writer as Box<Writer>,
        Err(e) => panic!("Unable to write file: {}", e.desc),
    }
}
<commit_msg>Convert box to Box::new()<commit_after>use std::io::{File, Truncate, Write};
use std::os;
use std::thread::Thread;

pub mod branchify;
pub mod status;
pub mod read_method;

fn main() {
    Thread::spawn(move || {
        let output_dir = Path::new(os::getenv("OUT_DIR").unwrap());
        read_method::generate(output_dir).unwrap();
    });

    let output_dir = Path::new(os::getenv("OUT_DIR").unwrap());
    status::generate(output_dir).unwrap();
}

pub fn get_writer(mut output_dir: Path, filename: &str) -> Box<Writer + 'static> {
    output_dir.push(filename);
    match File::open_mode(&output_dir, Truncate, Write) {
        Ok(writer) => Box::new(writer),
        Err(e) => panic!("Unable to write file: {}", e.desc),
    }
}
<|endoftext|>