<commit_before>use std::borrow::Cow;

use scroll::{self, Pread};
use error;

use pe::section_table;
use pe::utils;
use pe::data_directories;

#[derive(Debug, Clone)]
pub struct HintNameTableEntry<'a> {
    pub hint: u16,
    pub name: &'a str,
}

impl<'a> HintNameTableEntry<'a> {
    fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<Self> {
        let mut offset = &mut offset;
        let hint = bytes.gread_with(offset, scroll::LE)?;
        let name = bytes.pread::<&'a str>(*offset)?;
        Ok(HintNameTableEntry { hint: hint, name: name })
    }
}

#[derive(Debug, Clone)]
pub enum SyntheticImportLookupTableEntry<'a> {
    OrdinalNumber(u16),
    HintNameTableRVA ((u32, HintNameTableEntry<'a>)), // [u8; 31] bitfield :/
}

#[derive(Debug)]
pub struct ImportLookupTableEntry<'a> {
    pub bitfield: u32,
    pub synthetic: SyntheticImportLookupTableEntry<'a>,
}

pub type ImportLookupTable<'a> = Vec<ImportLookupTableEntry<'a>>;

pub const IMPORT_BY_ORDINAL_32: u32 = 0x8000_0000;
pub const IMPORT_RVA_MASK_32: u32 = 0x8fff_ffff;

impl<'a> ImportLookupTableEntry<'a> {
    pub fn parse(bytes: &'a [u8], mut offset: usize, sections: &[section_table::SectionTable])
                                                                      -> error::Result<ImportLookupTable<'a>> {
        let le = scroll::LE;
        let mut offset = &mut offset;
        let mut table = Vec::new();
        loop {
            let bitfield: u32 = bytes.gread_with(offset, le)?;
            if bitfield == 0 {
                debug!("imports done");
                break;
            } else {
                let synthetic = {
                    use self::SyntheticImportLookupTableEntry::*;
                    if bitfield & IMPORT_BY_ORDINAL_32 == IMPORT_BY_ORDINAL_32 {
                        let ordinal = (0xffff & bitfield) as u16;
                        debug!("importing by ordinal {:#x}", ordinal);
                        OrdinalNumber(ordinal)
                    } else {
                        let rva = bitfield & IMPORT_RVA_MASK_32;
                        let hentry = {
                            debug!("searching for RVA {:#x}", rva);
                            let offset = utils::find_offset(rva as usize, sections).ok_or(error::Error::Malformed(format!("Cannot map rva {:#x} into offset for import lookup table entry", rva)))?;
                            debug!("offset {:#x}", offset);
                            HintNameTableEntry::parse(bytes, offset)?
                        };
                        HintNameTableRVA ((rva, hentry))
                    }
                };
                let entry = ImportLookupTableEntry { bitfield: bitfield, synthetic: synthetic };
                table.push(entry);
            }
        }
        Ok(table)
    }
}

// get until entry is 0
pub type ImportAddressTable = Vec<u32>;

pub const SIZEOF_IMPORT_ADDRESS_TABLE_ENTRY: usize = 4;

#[repr(C)]
#[derive(Debug)]
#[derive(Pread, Pwrite, SizeWith)]
pub struct ImportDirectoryEntry {
    pub import_lookup_table_rva: u32,
    pub time_date_stamp: u32,
    pub forwarder_chain: u32,
    pub name_rva: u32,
    pub import_address_table_rva: u32,
}

pub const SIZEOF_IMPORT_DIRECTORY_ENTRY: usize = 20;

impl ImportDirectoryEntry {
    pub fn is_null (&self) -> bool {
        (self.import_lookup_table_rva == 0) &&
            (self.time_date_stamp == 0) &&
            (self.forwarder_chain == 0) &&
            (self.name_rva == 0) &&
            (self.import_address_table_rva == 0)
    }
}

#[derive(Debug)]
pub struct SyntheticImportDirectoryEntry<'a> {
    pub import_directory_entry: ImportDirectoryEntry,
    /// Computed
    pub name: &'a str,
    /// The import lookup table is a vector of either ordinals, or RVAs + import names
    pub import_lookup_table: Option<ImportLookupTable<'a>>,
    /// Computed
    pub import_address_table: ImportAddressTable,
}

impl<'a> SyntheticImportDirectoryEntry<'a> {
    pub fn parse(bytes: &'a [u8], import_directory_entry: ImportDirectoryEntry, sections: &[section_table::SectionTable]) -> error::Result<SyntheticImportDirectoryEntry<'a>> {
        const LE: scroll::Endian = scroll::LE;
        let name_rva = import_directory_entry.name_rva;
        let name = utils::try_name(bytes, name_rva as usize, sections)?;
        let import_lookup_table = {
            let import_lookup_table_rva = import_directory_entry.import_lookup_table_rva;
            debug!("Synthesizing lookup table imports for {} lib, with import lookup table rva: {:#x}", name, import_lookup_table_rva);
            if let Some(import_lookup_table_offset) = utils::find_offset(import_lookup_table_rva as usize, sections) {
                let import_lookup_table = ImportLookupTableEntry::parse(bytes, import_lookup_table_offset, sections)?;
                debug!("Successfully synthesized import lookup table entry: {:#?}", import_lookup_table);
                Some(import_lookup_table)
            } else {
                None
            }
        };
        let import_address_table_offset = &mut utils::find_offset(import_directory_entry.import_address_table_rva as usize, sections).ok_or(error::Error::Malformed(format!("Cannot map import_address_table_rva {:#x} into offset for {}", import_directory_entry.import_address_table_rva, name)))?;
        let mut import_address_table = Vec::new();
        loop {
            let import_address = bytes.gread_with(import_address_table_offset, LE)?;
            if import_address == 0 { break } else { import_address_table.push(import_address); }
        }
        Ok(SyntheticImportDirectoryEntry {
            import_directory_entry: import_directory_entry,
            name: name,
            import_lookup_table: import_lookup_table,
            import_address_table: import_address_table
        })
    }
}

#[derive(Debug)]
/// Contains a list of synthesized import data for this binary, e.g., which symbols from which libraries it is importing from
pub struct ImportData<'a> {
    pub import_data: Vec<SyntheticImportDirectoryEntry<'a>>,
}

impl<'a> ImportData<'a> {
    pub fn parse(bytes: &'a[u8], dd: &data_directories::DataDirectory, sections: &[section_table::SectionTable]) -> error::Result<ImportData<'a>> {
        let import_directory_table_rva = dd.virtual_address as usize;
        debug!("import_directory_table_rva {:#x}", import_directory_table_rva);
        let mut offset = &mut utils::find_offset(import_directory_table_rva, sections).ok_or(error::Error::Malformed(format!("Cannot create ImportData; cannot map import_directory_table_rva {:#x} into offset", import_directory_table_rva)))?;;
        debug!("import data offset {:#x}", offset);
        let mut import_data = Vec::new();
        loop {
            let import_directory_entry: ImportDirectoryEntry = bytes.gread_with(offset, scroll::LE)?;
            debug!("{:#?}", import_directory_entry);
            if import_directory_entry.is_null() {
                break;
            } else {
                let entry = SyntheticImportDirectoryEntry::parse(bytes, import_directory_entry, sections)?;
                debug!("entry {:#?}", entry);
                import_data.push(entry);
            }
        }
        debug!("finished ImportData");
        Ok(ImportData { import_data: import_data})
    }
}

#[derive(Debug)]
/// A synthesized symbol import, the name is pre-indexed, and the binary offset is computed, as well as which dll it belongs to
pub struct Import<'a> {
    pub name: Cow<'a, str>,
    pub dll: &'a str,
    pub ordinal: u16,
    pub offset: usize,
    pub rva: usize,
    pub size: usize,
}

impl<'a> Import<'a> {
    pub fn parse(_bytes: &'a [u8], import_data: &ImportData<'a>, _sections: &[section_table::SectionTable]) -> error::Result<Vec<Import<'a>>> {
        let mut imports = Vec::new();
        for data in &import_data.import_data {
            if let Some(ref import_lookup_table) = data.import_lookup_table {
                let dll = data.name;
                let import_base = data.import_directory_entry.import_address_table_rva as usize;
                debug!("Getting imports from {}", &dll);
                for (i, entry) in import_lookup_table.iter().enumerate() {
                    let offset = import_base + (i * SIZEOF_IMPORT_ADDRESS_TABLE_ENTRY);
                    use self::SyntheticImportLookupTableEntry::*;
                    let (rva, name, ordinal) =
                        match &entry.synthetic {
                            &HintNameTableRVA ((rva, ref hint_entry)) => {
                                let res = (rva, Cow::Borrowed(hint_entry.name), hint_entry.hint.clone());
                                // if hint_entry.name = "" && hint_entry.hint = 0 {
                                //     println!("<PE.Import> warning hint/name table rva from {} without hint {:#x}", dll, rva);
                                // }
                                res
                            },
                            &OrdinalNumber(ordinal) => {
                                let name = format!("ORDINAL {}", ordinal);
                                (0x0, Cow::Owned(name), ordinal)
                            }
                        };
                    let import =
                        Import {
                            name: name,
                            ordinal: ordinal, dll: dll,
                            size: 4, offset: offset, rva: rva as usize
                        };
                    imports.push(import);
                }
            }
        }
        Ok (imports)
    }
}
<commit_msg>pe.import: skip RVAs in import lookup table that cannot be remapped to an offset. ref #28<commit_after>use std::borrow::Cow;

use scroll::{self, Pread};
use error;

use pe::section_table;
use pe::utils;
use pe::data_directories;

#[derive(Debug, Clone)]
pub struct HintNameTableEntry<'a> {
    pub hint: u16,
    pub name: &'a str,
}

impl<'a> HintNameTableEntry<'a> {
    fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<Self> {
        let mut offset = &mut offset;
        let hint = bytes.gread_with(offset, scroll::LE)?;
        let name = bytes.pread::<&'a str>(*offset)?;
        Ok(HintNameTableEntry { hint: hint, name: name })
    }
}

#[derive(Debug, Clone)]
pub enum SyntheticImportLookupTableEntry<'a> {
    OrdinalNumber(u16),
    HintNameTableRVA ((u32, HintNameTableEntry<'a>)), // [u8; 31] bitfield :/
}

#[derive(Debug)]
pub struct ImportLookupTableEntry<'a> {
    pub bitfield: u32,
    pub synthetic: SyntheticImportLookupTableEntry<'a>,
}

pub type ImportLookupTable<'a> = Vec<ImportLookupTableEntry<'a>>;

pub const IMPORT_BY_ORDINAL_32: u32 = 0x8000_0000;
pub const IMPORT_RVA_MASK_32: u32 = 0x8fff_ffff;

impl<'a> ImportLookupTableEntry<'a> {
    pub fn parse(bytes: &'a [u8], mut offset: usize, sections: &[section_table::SectionTable])
                                                                      -> error::Result<ImportLookupTable<'a>> {
        let le = scroll::LE;
        let mut offset = &mut offset;
        let mut table = Vec::new();
        loop {
            let bitfield: u32 = bytes.gread_with(offset, le)?;
            if bitfield == 0 {
                debug!("imports done");
                break;
            } else {
                let synthetic = {
                    debug!("bitfield {:#x}", bitfield);
                    use self::SyntheticImportLookupTableEntry::*;
                    if bitfield & IMPORT_BY_ORDINAL_32 == IMPORT_BY_ORDINAL_32 {
                        let ordinal = (0xffff & bitfield) as u16;
                        debug!("importing by ordinal {:#x}", ordinal);
                        OrdinalNumber(ordinal)
                    } else {
                        let rva = bitfield & IMPORT_RVA_MASK_32;
                        let hentry = {
                            debug!("searching for RVA {:#x}", rva);
                            if let Some(offset) = utils::find_offset(rva as usize, sections) {
                                debug!("offset {:#x}", offset);
                                HintNameTableEntry::parse(bytes, offset)?
                            } else {
                                warn!("Entry {} has bad RVA: {:#x}", table.len(), rva);
                                continue
                            }
                        };
                        HintNameTableRVA ((rva, hentry))
                    }
                };
                let entry = ImportLookupTableEntry { bitfield: bitfield, synthetic: synthetic };
                table.push(entry);
            }
        }
        Ok(table)
    }
}

// get until entry is 0
pub type ImportAddressTable = Vec<u32>;

pub const SIZEOF_IMPORT_ADDRESS_TABLE_ENTRY: usize = 4;

#[repr(C)]
#[derive(Debug)]
#[derive(Pread, Pwrite, SizeWith)]
pub struct ImportDirectoryEntry {
    pub import_lookup_table_rva: u32,
    pub time_date_stamp: u32,
    pub forwarder_chain: u32,
    pub name_rva: u32,
    pub import_address_table_rva: u32,
}

pub const SIZEOF_IMPORT_DIRECTORY_ENTRY: usize = 20;

impl ImportDirectoryEntry {
    pub fn is_null (&self) -> bool {
        (self.import_lookup_table_rva == 0) &&
            (self.time_date_stamp == 0) &&
            (self.forwarder_chain == 0) &&
            (self.name_rva == 0) &&
            (self.import_address_table_rva == 0)
    }
}

#[derive(Debug)]
pub struct SyntheticImportDirectoryEntry<'a> {
    pub import_directory_entry: ImportDirectoryEntry,
    /// Computed
    pub name: &'a str,
    /// The import lookup table is a vector of either ordinals, or RVAs + import names
    pub import_lookup_table: Option<ImportLookupTable<'a>>,
    /// Computed
    pub import_address_table: ImportAddressTable,
}

impl<'a> SyntheticImportDirectoryEntry<'a> {
    pub fn parse(bytes: &'a [u8], import_directory_entry: ImportDirectoryEntry, sections: &[section_table::SectionTable]) -> error::Result<SyntheticImportDirectoryEntry<'a>> {
        const LE: scroll::Endian = scroll::LE;
        let name_rva = import_directory_entry.name_rva;
        let name = utils::try_name(bytes, name_rva as usize, sections)?;
        let import_lookup_table = {
            let import_lookup_table_rva = import_directory_entry.import_lookup_table_rva;
            debug!("Synthesizing lookup table imports for {} lib, with import lookup table rva: {:#x}", name, import_lookup_table_rva);
            if let Some(import_lookup_table_offset) = utils::find_offset(import_lookup_table_rva as usize, sections) {
                let import_lookup_table = ImportLookupTableEntry::parse(bytes, import_lookup_table_offset, sections)?;
                debug!("Successfully synthesized import lookup table entry: {:#?}", import_lookup_table);
                Some(import_lookup_table)
            } else {
                None
            }
        };
        let import_address_table_offset = &mut utils::find_offset(import_directory_entry.import_address_table_rva as usize, sections).ok_or(error::Error::Malformed(format!("Cannot map import_address_table_rva {:#x} into offset for {}", import_directory_entry.import_address_table_rva, name)))?;
        let mut import_address_table = Vec::new();
        loop {
            let import_address = bytes.gread_with(import_address_table_offset, LE)?;
            if import_address == 0 { break } else { import_address_table.push(import_address); }
        }
        Ok(SyntheticImportDirectoryEntry {
            import_directory_entry: import_directory_entry,
            name: name,
            import_lookup_table: import_lookup_table,
            import_address_table: import_address_table
        })
    }
}

#[derive(Debug)]
/// Contains a list of synthesized import data for this binary, e.g., which symbols from which libraries it is importing from
pub struct ImportData<'a> {
    pub import_data: Vec<SyntheticImportDirectoryEntry<'a>>,
}

impl<'a> ImportData<'a> {
    pub fn parse(bytes: &'a[u8], dd: &data_directories::DataDirectory, sections: &[section_table::SectionTable]) -> error::Result<ImportData<'a>> {
        let import_directory_table_rva = dd.virtual_address as usize;
        debug!("import_directory_table_rva {:#x}", import_directory_table_rva);
        let mut offset = &mut utils::find_offset(import_directory_table_rva, sections).ok_or(error::Error::Malformed(format!("Cannot create ImportData; cannot map import_directory_table_rva {:#x} into offset", import_directory_table_rva)))?;;
        debug!("import data offset {:#x}", offset);
        let mut import_data = Vec::new();
        loop {
            let import_directory_entry: ImportDirectoryEntry = bytes.gread_with(offset, scroll::LE)?;
            debug!("{:#?}", import_directory_entry);
            if import_directory_entry.is_null() {
                break;
            } else {
                let entry = SyntheticImportDirectoryEntry::parse(bytes, import_directory_entry, sections)?;
                debug!("entry {:#?}", entry);
                import_data.push(entry);
            }
        }
        debug!("finished ImportData");
        Ok(ImportData { import_data: import_data})
    }
}

#[derive(Debug)]
/// A synthesized symbol import, the name is pre-indexed, and the binary offset is computed, as well as which dll it belongs to
pub struct Import<'a> {
    pub name: Cow<'a, str>,
    pub dll: &'a str,
    pub ordinal: u16,
    pub offset: usize,
    pub rva: usize,
    pub size: usize,
}

impl<'a> Import<'a> {
    pub fn parse(_bytes: &'a [u8], import_data: &ImportData<'a>, _sections: &[section_table::SectionTable]) -> error::Result<Vec<Import<'a>>> {
        let mut imports = Vec::new();
        for data in &import_data.import_data {
            if let Some(ref import_lookup_table) = data.import_lookup_table {
                let dll = data.name;
                let import_base = data.import_directory_entry.import_address_table_rva as usize;
                debug!("Getting imports from {}", &dll);
                for (i, entry) in import_lookup_table.iter().enumerate() {
                    let offset = import_base + (i * SIZEOF_IMPORT_ADDRESS_TABLE_ENTRY);
                    use self::SyntheticImportLookupTableEntry::*;
                    let (rva, name, ordinal) =
                        match &entry.synthetic {
                            &HintNameTableRVA ((rva, ref hint_entry)) => {
                                let res = (rva, Cow::Borrowed(hint_entry.name), hint_entry.hint.clone());
                                // if hint_entry.name = "" && hint_entry.hint = 0 {
                                //     println!("<PE.Import> warning hint/name table rva from {} without hint {:#x}", dll, rva);
                                // }
                                res
                            },
                            &OrdinalNumber(ordinal) => {
                                let name = format!("ORDINAL {}", ordinal);
                                (0x0, Cow::Owned(name), ordinal)
                            }
                        };
                    let import =
                        Import {
                            name: name,
                            ordinal: ordinal, dll: dll,
                            size: 4, offset: offset, rva: rva as usize
                        };
                    imports.push(import);
                }
            }
        }
        Ok (imports)
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

use dioxus::prelude::*;
use rand::prelude::*;

fn main() {
    dioxus::web::launch(app);
}

fn app1(cx: Scope) -> Element {
    cx.render(rsx!{
        div { "hello, wasm!" }
    })
}

#[derive(Clone, PartialEq)]
struct Label {
    key: usize,
    labels: Vec<&'static str>,
}

impl Label {
    fn new_list(num: usize, key_from: usize) -> Vec<Self> {
        let mut rng = SmallRng::from_entropy();
        let mut labels = Vec::with_capacity(num);
        for x in 0..num {
            labels.push(Label {
                key: x as usize + key_from,
                labels: vec![
                    *ADJECTIVES.choose(&mut rng).unwrap(),
                    *COLOURS.choose(&mut rng).unwrap(),
                    *NOUNS.choose(&mut rng).unwrap(),
                ],
            });
        }
        labels
    }
}

#[derive(Clone, PartialEq)]
struct LabelsContainer {
    last_key: usize,
    labels: Vec<Label>,
}

impl LabelsContainer {
    fn new(num: usize, last_key: usize) -> LabelsContainer {
        let labels = Label::new_list(num, last_key + 1);
        LabelsContainer {
            labels,
            last_key: last_key + num,
        }
    }

    fn append(&mut self, num: usize) {
        self.labels.extend(Label::new_list(1_000, self.last_key + 1));
        self.last_key += num;
    }

    fn overwrite(&mut self, num: usize) {
        self.labels = Label::new_list(num, self.last_key + 1);
        self.last_key += num;
    }

    fn swap(&mut self, a: usize, b: usize) {
        if self.labels.len() > a + 1 && self.labels.len() > b {
            self.labels.swap(a, b);
        }
    }

    #[feature(int_roundings)]
    fn remove(&mut self, index: usize) {
        self.labels.remove(index as usize);
    }

}

fn app(cx: Scope) -> Element {
    let labels_container = use_ref(&cx, || LabelsContainer::new(0, 0));
    let selected: &UseState<Option<usize>> = use_state(&cx, || None);

    cx.render(rsx! {
        div { class: "container",
            div { class: "jumbotron",
                div { class: "row",
                    div { class: "col-md-6", h1 { "Dioxus" } }
                    div { class: "col-md-6",
                        div { class: "row",
                            ActionButton { name: "Create 1,000 rows", id: "run",
                                onclick: move |_| labels_container.write().overwrite(1_000),
                            }
                            ActionButton { name: "Create 10,000 rows", id: "runlots",
                                onclick: move |_| labels_container.write().overwrite(10_000),
                            }
                            ActionButton { name: "Append 1,000 rows", id: "add",
                                onclick: move |_| labels_container.write().append(1_000),
                            }
                            ActionButton { name: "Update every 10th row", id: "update",
                                onclick: move |_| labels_container.write().labels.iter_mut().step_by(10).for_each(|item| item.labels.push("!!!")),
                            }
                            ActionButton { name: "Clear", id: "clear",
                                onclick: move |_| labels_container.write().overwrite(0),
                            }
                            ActionButton { name: "Swap rows", id: "swaprows",
                                onclick: move |_| labels_container.write().swap(1, 998),
                            }
                        }
                    }
                }
            }
            table { class: "table table-hover table-striped test-data",
                tbody { id: "tbody",
                    labels_container.read().labels.iter().enumerate().map(|(index, item)| {
                        let key = item.key;
                        let is_in_danger = if (*selected).map(|s| s == item.key).unwrap_or(false) {"danger"} else {""};
                        rsx!(tr { key: "{key}", class: "{is_in_danger}",
                            td { class:"col-md-1", "{key}" }
                            td { class:"col-md-4", onclick: move |_| selected.set(Some(key)),
                                a { class: "lbl", [item.labels.join(" ").as_str()] }
                            }
                            td { class: "col-md-1",
                                a { class: "remove", onclick: move |_| { labels_container.write().remove(index); },
                                    span { class: "glyphicon glyphicon-remove remove", aria_hidden: "true" }
                                }
                            }
                            td { class: "col-md-6" }
                        })
                    })
                }
             }
            span { class: "preloadicon glyphicon glyphicon-remove", aria_hidden: "true" }
        }
    })
}

#[derive(Props)]
struct ActionButtonProps<'a> {
    name: &'a str,
    id: &'a str,
    onclick: EventHandler<'a>,
}

fn ActionButton<'a>(cx: Scope<'a, ActionButtonProps<'a>>) -> Element {
    cx.render(rsx! {
        div {
            class: "col-sm-6 smallpad",
            button {
                class:"btn btn-primary btn-block",
                r#type: "button",
                id: "{cx.props.id}",
                onclick: move |_| cx.props.onclick.call(()),

                "{cx.props.name}"
            }
        }
    })
}

static ADJECTIVES: &[&str] = &[
    "pretty",
    "large",
    "big",
    "small",
    "tall",
    "short",
    "long",
    "handsome",
    "plain",
    "quaint",
    "clean",
    "elegant",
    "easy",
    "angry",
    "crazy",
    "helpful",
    "mushy",
    "odd",
    "unsightly",
    "adorable",
    "important",
    "inexpensive",
    "cheap",
    "expensive",
    "fancy",
];

static COLOURS: &[&str] = &[
    "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
    "orange",
];

static NOUNS: &[&str] = &[
    "table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger",
    "pizza", "mouse", "keyboard",
];
<commit_msg>Enable interning for strings on the JS/RS boundary<commit_after>#![allow(non_snake_case)]

use dioxus::prelude::*;
use rand::prelude::*;

fn main() {
    // for performance reasons, we want to cache these strings on the edge of js/rust boundary
    for &name in ADJECTIVES
        .iter()
        .chain(NOUNS.iter())
        .chain(COLOURS.iter())
        .chain(OTHER.iter())
    {
        wasm_bindgen::intern(name);
    }

    dioxus::web::launch(app);
}

fn app1(cx: Scope) -> Element {
    cx.render(rsx!{
        div { "hello, wasm!" }
    })
}

#[derive(Clone, PartialEq)]
struct Label {
    key: usize,
    labels: Vec<&'static str>,
}

impl Label {
    fn new_list(num: usize, key_from: usize) -> Vec<Self> {
        let mut rng = SmallRng::from_entropy();
        let mut labels = Vec::with_capacity(num);
        for x in 0..num {
            labels.push(Label {
                key: x as usize + key_from,
                labels: vec![
                    *ADJECTIVES.choose(&mut rng).unwrap(),
                    *COLOURS.choose(&mut rng).unwrap(),
                    *NOUNS.choose(&mut rng).unwrap(),
                ],
            });
        }
        labels
    }
}

#[derive(Clone, PartialEq)]
struct LabelsContainer {
    last_key: usize,
    labels: Vec<Label>,
}

impl LabelsContainer {
    fn new(num: usize, last_key: usize) -> LabelsContainer {
        let labels = Label::new_list(num, last_key + 1);
        LabelsContainer {
            labels,
            last_key: last_key + num,
        }
    }

    fn append(&mut self, num: usize) {
        self.labels.extend(Label::new_list(1_000, self.last_key + 1));
        self.last_key += num;
    }

    fn overwrite(&mut self, num: usize) {
        self.labels = Label::new_list(num, self.last_key + 1);
        self.last_key += num;
    }

    fn swap(&mut self, a: usize, b: usize) {
        if self.labels.len() > a + 1 && self.labels.len() > b {
            self.labels.swap(a, b);
        }
    }

    #[feature(int_roundings)]
    fn remove(&mut self, index: usize) {
        self.labels.remove(index as usize);
    }

}

fn app(cx: Scope) -> Element {
    let labels_container = use_ref(&cx, || LabelsContainer::new(0, 0));
    let selected: &UseState<Option<usize>> = use_state(&cx, || None);

    cx.render(rsx! {
        div { class: "container",
            div { class: "jumbotron",
                div { class: "row",
                    div { class: "col-md-6", h1 { "Dioxus" } }
                    div { class: "col-md-6",
                        div { class: "row",
                            ActionButton { name: "Create 1,000 rows", id: "run",
                                onclick: move |_| labels_container.write().overwrite(1_000),
                            }
                            ActionButton { name: "Create 10,000 rows", id: "runlots",
                                onclick: move |_| labels_container.write().overwrite(10_000),
                            }
                            ActionButton { name: "Append 1,000 rows", id: "add",
                                onclick: move |_| labels_container.write().append(1_000),
                            }
                            ActionButton { name: "Update every 10th row", id: "update",
                                onclick: move |_| labels_container.write().labels.iter_mut().step_by(10).for_each(|item| item.labels.push("!!!")),
                            }
                            ActionButton { name: "Clear", id: "clear",
                                onclick: move |_| labels_container.write().overwrite(0),
                            }
                            ActionButton { name: "Swap rows", id: "swaprows",
                                onclick: move |_| labels_container.write().swap(1, 998),
                            }
                        }
                    }
                }
            }
            table { class: "table table-hover table-striped test-data",
                tbody { id: "tbody",
                    labels_container.read().labels.iter().enumerate().map(|(index, item)| {
                        let key = item.key;
                        let is_in_danger = if (*selected).map(|s| s == item.key).unwrap_or(false) {"danger"} else {""};
                        rsx!(tr { key: "{key}", class: "{is_in_danger}",
                            td { class:"col-md-1", "{key}" }
                            td { class:"col-md-4", onclick: move |_| selected.set(Some(key)),
                                a { class: "lbl", [item.labels.join(" ").as_str()] }
                            }
                            td { class: "col-md-1",
                                a { class: "remove", onclick: move |_| { labels_container.write().remove(index); },
                                    span { class: "glyphicon glyphicon-remove remove", aria_hidden: "true" }
                                }
                            }
                            td { class: "col-md-6" }
                        })
                    })
                }
             }
            span { class: "preloadicon glyphicon glyphicon-remove", aria_hidden: "true" }
        }
    })
}

#[derive(Props)]
struct ActionButtonProps<'a> {
    name: &'a str,
    id: &'a str,
    onclick: EventHandler<'a>,
}

fn ActionButton<'a>(cx: Scope<'a, ActionButtonProps<'a>>) -> Element {
    cx.render(rsx! {
        div {
            class: "col-sm-6 smallpad",
            button {
                class:"btn btn-primary btn-block",
                r#type: "button",
                id: "{cx.props.id}",
                onclick: move |_| cx.props.onclick.call(()),

                "{cx.props.name}"
            }
        }
    })
}

static ADJECTIVES: &[&str] = &[
    "pretty",
    "large",
    "big",
    "small",
    "tall",
    "short",
    "long",
    "handsome",
    "plain",
    "quaint",
    "clean",
    "elegant",
    "easy",
    "angry",
    "crazy",
    "helpful",
    "mushy",
    "odd",
    "unsightly",
    "adorable",
    "important",
    "inexpensive",
    "cheap",
    "expensive",
    "fancy",
];

static COLOURS: &[&str] = &[
    "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
    "orange",
];

static NOUNS: &[&str] = &[
    "table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger",
    "pizza", "mouse", "keyboard",
];
<|endoftext|>


<commit_before>use super::job_queue::*;
use super::queue_state::*;
use super::core::*;
use super::active_queue::*;
use super::wake_queue::*;

use futures::prelude::*;
use futures::channel::oneshot;
use futures::task;

use std::mem;
use std::sync::*;
use std::pin::{Pin};

///
/// The possible states of a future result
///
enum FutureResultState<T> {
    None,
    Some(T),
    ReturnedViaFuture
}

///
/// The possible states of a waker that will wake up a queue that's being drained as part of polling a future
///
enum DrainWakerState {
    /// The drain waker has never been woken before
    NotWoken,

    /// This has been woken but the waker is not set
    Woken,

    /// This has been woken and the waker is set
    WillWakeWithWaker(task::Waker)
}

///
/// Waker that will wake up a queue being drained. We set the waker with a delay so it's possible to switch to
/// a waker that will wake a future on a background queue if necessary.
///
struct DrainWaker {
    state: Mutex<DrainWakerState>
}

impl DrainWaker {
    ///
    /// Creates a new drain waker
    ///
    fn new() -> DrainWaker {
        DrainWaker {
            state: Mutex::new(DrainWakerState::NotWoken)
        }
    }

    ///
    /// Sets the waker to be called when this drain waker is woken
    ///
    fn wake_with(&self, new_waker: task::Waker) {
        use self::DrainWakerState::*;

        // Update the state and determine if we need to invoke the waker immediately (if it's been woken before the waker was set)
        let to_wake = {
            // Fetch the current state
            let mut new_state   = self.state.lock().expect("Drain waker state");
            let mut state       = Woken;
            mem::swap(&mut *new_state, &mut state);

            // Update the state based on this action
            match state {
                Woken                           => { *new_state = Woken; Some(new_waker) },
                NotWoken                        => { *new_state = WillWakeWithWaker(new_waker); None },
                WillWakeWithWaker(_old_waker)   => { *new_state = WillWakeWithWaker(new_waker); None }
            }
        };

        // Wake up the waker, if we need to call it immediately
        to_wake.map(|to_wake| to_wake.wake());
    }
}

impl task::ArcWake for DrainWaker {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        use self::DrainWakerState::*;

        // If the current state contains a waker, we'll call it once we've unlocked the mutex
        let to_wake = {
            // Fetch the current state
            let mut new_state   = arc_self.state.lock().expect("Drain waker state");
            let mut state       = Woken;
            mem::swap(&mut *new_state, &mut state);

            // Update the state based on this action
            match state {
                NotWoken                    => { *new_state = Woken; None },
                Woken                       => { *new_state = Woken; None },
                WillWakeWithWaker(waker)    => { *new_state = Woken; Some(waker) }
            }
        };

        // Wake up the waker
        to_wake.map(|to_wake| to_wake.wake());
    }
}

///
/// Signalling structure used to return the result of a scheduler future
///
struct SchedulerFutureResult<T> {
    /// The result of the future, or None if it has not been generated yet
    result: FutureResultState<Result<T, oneshot::Canceled>>,

    /// The waker to be called when the future is available
    waker: Option<task::Waker>
}

///
/// Wrapper that cancels the future if it is dropped before it is signalled
///
pub (super) struct SchedulerFutureSignaller<T>(Arc<Mutex<SchedulerFutureResult<T>>>);

///
/// Future representing a task pending on a scheduler
///
/// If polled when no threads are available, this future will run synchronously on the current thread
/// (stealing its execution time rather than blocking)
///
pub struct SchedulerFuture<T> {
    /// The queue which will eventually evaluate the result of this future
    queue: Arc<JobQueue>,

    /// The scheduler core that this future belongs to
    scheduler: Arc<SchedulerCore>,

    /// A container for the result of this scheduler future
    result: Arc<Mutex<SchedulerFutureResult<T>>>
}

impl<T> FutureResultState<T> {
    ///
    /// Returns true if no result has ever been generated for this future
    ///
    fn is_none(&self) -> bool {
        match self {
            FutureResultState::None                 => true,
            FutureResultState::Some(_)              => false,
            FutureResultState::ReturnedViaFuture    => false
        }
    }

    ///
    /// If a result has been generated by this future and has not previously been taken, returns it. Panics if the result has already
    /// been returned and is no longer available.
    ///
    fn take(&mut self) -> Option<T> {
        // Move the value out of this object
        let mut new_value = FutureResultState::ReturnedViaFuture;
        mem::swap(self, &mut new_value);

        // Return it if it contains a value
        match new_value {
            FutureResultState::None                 => { *self = FutureResultState::None; None },
            FutureResultState::ReturnedViaFuture    => { *self = FutureResultState::ReturnedViaFuture; panic!("Future result has already been returned") },
            FutureResultState::Some(value)          => { Some(value) }
        }
    }
}

impl<T> Drop for SchedulerFutureSignaller<T> {
    fn drop(&mut self) {
        let waker = {
            let mut future_result = self.0.lock().expect("Scheduler future result");

            // If no result has been generated, then mark the future as canceled
            if future_result.result.is_none() {
                // Mark the future as canceled
                future_result.result = FutureResultState::Some(Err(oneshot::Canceled));

                // Wake up anything that was polling it
                let waker = future_result.waker.take();
                waker
            } else {
                // Result is already set, so don't wake anything up
                None
            }
        };

        // If we need to wake the future, then do so here (note that we're outside of the lock when we do this)
        waker.map(|waker| waker.wake());
    }
}

impl<T> SchedulerFutureSignaller<T> {
    ///
    /// Signals that the result of the calculation is available
    ///
    pub (super) fn signal(self, result: T) {
        let waker = {
            let mut future_result = self.0.lock().expect("Scheduler futuer result");

            // Set the result
            future_result.result = FutureResultState::Some(Ok(result));

            // Retrieve the waker
            future_result.waker.take()
        };

        // If we retrieved a waker from the result, wake it up
        waker.map(|waker| waker.wake());
    }
}

///
/// Possible actions we can take based on the state of the signal for the future
///
enum SchedulerAction<T> {
    /// Queue is running elsewhere: we should wait for it to reach the point where the future's result is available
    WaitForCompletion,

    /// Future has already completed: we should return the value to sender
    ReturnValue(T),

    /// We've claimed the 'running' state of the queue and should drain it
    DrainQueue,

    /// The queue has panicked
    Panic
}

impl<T> SchedulerFuture<T> {
    ///
    /// Creates a new scheduler future and the result needed to signal it
    ///
    pub (super) fn new(queue: &Arc<JobQueue>, core: Arc<SchedulerCore>) -> (SchedulerFuture<T>, SchedulerFutureSignaller<T>) {
        // Create an unfinished result
        let result = SchedulerFutureResult {
            result: FutureResultState::None,
            waker:  None
        };
        let result = Arc::new(Mutex::new(result));

        // Insert into a future
        let future = SchedulerFuture {
            queue:      Arc::clone(queue),
            scheduler:  core,
            result:     Arc::clone(&result)
        };

        (future, SchedulerFutureSignaller(result))
    }

    ///
    /// We moved the queue into the running state and need to drain it until we've got a result
    ///
    fn drain_queue(&mut self, context: &mut task::Context) -> task::Poll<Result<T, oneshot::Canceled>> {
        debug_assert!(self.queue.core.lock().expect("JobQueue core lock").state.is_running());

        // Set the queue as active
        let _active     = ActiveQueue { queue: &*self.queue };
        let mut result;

        // While there is no result, run a job from the queue
        loop {
            // See if the result has arrived yet
            result = self.result.lock().expect("Scheduler future result").result.take();
            if !result.is_none() { break; }

            // Run the next job in the queue
            if let Some(mut job) = self.queue.dequeue() {
                // Queue is running
                debug_assert!(self.queue.core.lock().expect("Job queue core").state.is_running());

                // Create a context to poll in (we may need to reschedule in the background)
                let waker               = Arc::new(DrainWaker::new());
                let waker_ref           = task::waker_ref(&waker);
                let mut drain_context   = task::Context::from_waker(&waker_ref);

                // Poll the queue
                let poll_result = job.run(&mut drain_context);

                match poll_result {
                    task::Poll::Ready(())   => {
                        // Keep running jobs and checking the results if ready
                    },

                    task::Poll::Pending     => {
                        // Requeue the job
                        self.queue.requeue(job);

                        // If the result was supplied, break out of the loop and reschedule the queue
                        result = self.result.lock().expect("Scheduler future result").result.take();
                        if result.is_some() {
                            // Wake the queue in the background if needed (the result has arrived)
                            self.queue.core.lock().expect("JobQueue core lock").state = QueueState::WaitingForWake;

                            let queue_waker = WakeQueue(Arc::clone(&self.queue), Arc::clone(&self.scheduler));
                            let queue_waker = Arc::new(queue_waker);
                            let queue_waker = task::waker(queue_waker);

                            waker.wake_with(queue_waker);

                            // The future is ready (job will be rescheduled in the background)
                            return task::Poll::Ready(result.unwrap());
                        } else {
                            // Wait for the next poll
                            self.queue.core.lock().expect("JobQueue core lock").state = QueueState::WaitingForPoll;

                            // Use the context waker
                            waker.wake_with(context.waker().clone());

                            // Result is pending
                            return task::Poll::Pending;
                        }
                    }
                }
            } else {
                // Queue is empty and our result hasn't arrived yet?!

                // Assume the future will resolve eventually: move the queue in to the background
                self.result.lock().expect("Scheduler future result").waker = Some(context.waker().clone());

                // Reschedule the queue
                self.queue.core.lock().expect("JobQueue core lock").state = QueueState::Idle;
                self.scheduler.reschedule_queue(&self.queue, Arc::clone(&self.scheduler));

                return task::Poll::Pending;
            }
        }

        // Reschedule the queue if there are any events left pending
        // Note: the queue is already pending when we start running events from it here.
        // This means it'll get dequeued by a thread eventually: maybe while it's running
        // here. As we've set the queue state to running while we're busy, the thread won't
        // start the queue while it's already running.
        self.queue.core.lock().expect("JobQueue core lock").state = QueueState::Idle;
        self.scheduler.reschedule_queue(&self.queue, Arc::clone(&self.scheduler));

        // Result must be available by this point
        task::Poll::Ready(result.unwrap())
    }
}

impl<T> Future for SchedulerFuture<T> {
    type Output = Result<T, oneshot::Canceled>;

    ///
    /// Polls this future
    ///
    fn poll(mut self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
        // Lock the result and determine which action to take
        let next_action = {
            let mut future_result = self.result.lock().expect("Scheduler future result");

            if let Some(result) = future_result.result.take() {
                // The result is available: we should return it immediately
                SchedulerAction::ReturnValue(result)
            } else {
                // If the queue is idle when this is called, we need to schedule this task on this thread rather than one owned by the background process
                let run_action = {
                    let mut core = self.queue.core.lock().expect("JobQueue core lock");

                    match core.state {
                        QueueState::Running             => SchedulerAction::WaitForCompletion,
                        QueueState::WaitingForWake      => SchedulerAction::WaitForCompletion,
                        QueueState::WaitingForUnpark    => SchedulerAction::WaitForCompletion,
                        QueueState::AwokenWhileRunning  => SchedulerAction::WaitForCompletion,
                        QueueState::Panicked            => SchedulerAction::Panic,
                        QueueState::WaitingForPoll      => { core.state = QueueState::Running; SchedulerAction::DrainQueue },
                        QueueState::Pending             => { core.state = QueueState::Running; SchedulerAction::DrainQueue },
                        QueueState::Idle                => { core.state = QueueState::Running; SchedulerAction::DrainQueue }
                    }
                };

                if let SchedulerAction::WaitForCompletion = run_action {
                    // Wake us up when the future is available
                    future_result.waker = Some(context.waker().clone());
                }

                run_action
            }
        };

        match next_action {
            SchedulerAction::WaitForCompletion  => task::Poll::Pending,
            SchedulerAction::ReturnValue(value) => task::Poll::Ready(value),
            SchedulerAction::DrainQueue         => self.drain_queue(context),
            SchedulerAction::Panic              => panic!("Cannot schedule jobs on a panicked queue"),
        }
    }
}

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

    #[test]
    fn returns_immediately_if_signaled() {
        use futures::executor;

        let scheduler           = scheduler();
        let queue               = queue();
        let (future, signaller) = SchedulerFuture::new(&queue, Arc::clone(&scheduler.core));

        signaller.signal(42);

        assert!(executor::block_on(future) == Ok(42));
    }

    #[test]
    fn cancels_when_dropped() {
        use futures::executor;

        let scheduler           = scheduler();
        let queue               = queue();
        let future              = { SchedulerFuture::<i32>::new(&queue, Arc::clone(&scheduler.core)).0 };

        assert!(executor::block_on(future) == Err(oneshot::Canceled));
    }

    #[test]
    fn signals_from_another_thread() {
        use futures::executor;
        use std::thread;
        use std::time::Duration;

        let scheduler           = scheduler();
        let queue               = queue();
        let (future, signaller) = SchedulerFuture::new(&queue, Arc::clone(&scheduler.core));

        thread::spawn(move || {
            thread::sleep(Duration::from_millis(100));

            signaller.signal(42);
        });

        assert!(executor::block_on(future) == Ok(42));
    }

    #[test]
    fn forces_queue_drain() {
        use futures::executor;
        use std::thread;
        use std::time::Duration;

        let scheduler   = scheduler();
        let queue       = queue();

        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        let (future, signaller) = SchedulerFuture::new(&queue, Arc::clone(&scheduler.core));

        scheduler.desync(&queue, move || {
            thread::sleep(Duration::from_millis(100));

            signaller.signal(42);
        });

        assert!(executor::block_on(future) == Ok(42));
    }
}
<commit_msg>Fix typo<commit_after>use super::job_queue::*;
use super::queue_state::*;
use super::core::*;
use super::active_queue::*;
use super::wake_queue::*;

use futures::prelude::*;
use futures::channel::oneshot;
use futures::task;

use std::mem;
use std::sync::*;
use std::pin::{Pin};

///
/// The possible states of a future result
///
enum FutureResultState<T> {
    None,
    Some(T),
    ReturnedViaFuture
}

///
/// The possible states of a waker that will wake up a queue that's being drained as part of polling a future
///
enum DrainWakerState {
    /// The drain waker has never been woken before
    NotWoken,

    /// This has been woken but the waker is not set
    Woken,

    /// This has been woken and the waker is set
    WillWakeWithWaker(task::Waker)
}

///
/// Waker that will wake up a queue being drained. We set the waker with a delay so it's possible to switch to
/// a waker that will wake a future on a background queue if necessary.
///
struct DrainWaker {
    state: Mutex<DrainWakerState>
}

impl DrainWaker {
    ///
    /// Creates a new drain waker
    ///
    fn new() -> DrainWaker {
        DrainWaker {
            state: Mutex::new(DrainWakerState::NotWoken)
        }
    }

    ///
    /// Sets the waker to be called when this drain waker is woken
    ///
    fn wake_with(&self, new_waker: task::Waker) {
        use self::DrainWakerState::*;

        // Update the state and determine if we need to invoke the waker immediately (if it's been woken before the waker was set)
        let to_wake = {
            // Fetch the current state
            let mut new_state   = self.state.lock().expect("Drain waker state");
            let mut state       = Woken;
            mem::swap(&mut *new_state, &mut state);

            // Update the state based on this action
            match state {
                Woken                           => { *new_state = Woken; Some(new_waker) },
                NotWoken                        => { *new_state = WillWakeWithWaker(new_waker); None },
                WillWakeWithWaker(_old_waker)   => { *new_state = WillWakeWithWaker(new_waker); None }
            }
        };

        // Wake up the waker, if we need to call it immediately
        to_wake.map(|to_wake| to_wake.wake());
    }
}

impl task::ArcWake for DrainWaker {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        use self::DrainWakerState::*;

        // If the current state contains a waker, we'll call it once we've unlocked the mutex
        let to_wake = {
            // Fetch the current state
            let mut new_state   = arc_self.state.lock().expect("Drain waker state");
            let mut state       = Woken;
            mem::swap(&mut *new_state, &mut state);

            // Update the state based on this action
            match state {
                NotWoken                    => { *new_state = Woken; None },
                Woken                       => { *new_state = Woken; None },
                WillWakeWithWaker(waker)    => { *new_state = Woken; Some(waker) }
            }
        };

        // Wake up the waker
        to_wake.map(|to_wake| to_wake.wake());
    }
}

///
/// Signalling structure used to return the result of a scheduler future
///
struct SchedulerFutureResult<T> {
    /// The result of the future, or None if it has not been generated yet
    result: FutureResultState<Result<T, oneshot::Canceled>>,

    /// The waker to be called when the future is available
    waker: Option<task::Waker>
}

///
/// Wrapper that cancels the future if it is dropped before it is signalled
///
pub (super) struct SchedulerFutureSignaller<T>(Arc<Mutex<SchedulerFutureResult<T>>>);

///
/// Future representing a task pending on a scheduler
///
/// If polled when no threads are available, this future will run synchronously on the current thread
/// (stealing its execution time rather than blocking)
///
pub struct SchedulerFuture<T> {
    /// The queue which will eventually evaluate the result of this future
    queue: Arc<JobQueue>,

    /// The scheduler core that this future belongs to
    scheduler: Arc<SchedulerCore>,

    /// A container for the result of this scheduler future
    result: Arc<Mutex<SchedulerFutureResult<T>>>
}

impl<T> FutureResultState<T> {
    ///
    /// Returns true if no result has ever been generated for this future
    ///
    fn is_none(&self) -> bool {
        match self {
            FutureResultState::None                 => true,
            FutureResultState::Some(_)              => false,
            FutureResultState::ReturnedViaFuture    => false
        }
    }

    ///
    /// If a result has been generated by this future and has not previously been taken, returns it. Panics if the result has already
    /// been returned and is no longer available.
    ///
    fn take(&mut self) -> Option<T> {
        // Move the value out of this object
        let mut new_value = FutureResultState::ReturnedViaFuture;
        mem::swap(self, &mut new_value);

        // Return it if it contains a value
        match new_value {
            FutureResultState::None                 => { *self = FutureResultState::None; None },
            FutureResultState::ReturnedViaFuture    => { *self = FutureResultState::ReturnedViaFuture; panic!("Future result has already been returned") },
            FutureResultState::Some(value)          => { Some(value) }
        }
    }
}

impl<T> Drop for SchedulerFutureSignaller<T> {
    fn drop(&mut self) {
        let waker = {
            let mut future_result = self.0.lock().expect("Scheduler future result");

            // If no result has been generated, then mark the future as canceled
            if future_result.result.is_none() {
                // Mark the future as canceled
                future_result.result = FutureResultState::Some(Err(oneshot::Canceled));

                // Wake up anything that was polling it
                let waker = future_result.waker.take();
                waker
            } else {
                // Result is already set, so don't wake anything up
                None
            }
        };

        // If we need to wake the future, then do so here (note that we're outside of the lock when we do this)
        waker.map(|waker| waker.wake());
    }
}

impl<T> SchedulerFutureSignaller<T> {
    ///
    /// Signals that the result of the calculation is available
    ///
    pub (super) fn signal(self, result: T) {
        let waker = {
            let mut future_result = self.0.lock().expect("Scheduler future result");

            // Set the result
            future_result.result = FutureResultState::Some(Ok(result));

            // Retrieve the waker
            future_result.waker.take()
        };

        // If we retrieved a waker from the result, wake it up
        waker.map(|waker| waker.wake());
    }
}

///
/// Possible actions we can take based on the state of the signal for the future
///
enum SchedulerAction<T> {
    /// Queue is running elsewhere: we should wait for it to reach the point where the future's result is available
    WaitForCompletion,

    /// Future has already completed: we should return the value to sender
    ReturnValue(T),

    /// We've claimed the 'running' state of the queue and should drain it
    DrainQueue,

    /// The queue has panicked
    Panic
}

impl<T> SchedulerFuture<T> {
    ///
    /// Creates a new scheduler future and the result needed to signal it
    ///
    pub (super) fn new(queue: &Arc<JobQueue>, core: Arc<SchedulerCore>) -> (SchedulerFuture<T>, SchedulerFutureSignaller<T>) {
        // Create an unfinished result
        let result = SchedulerFutureResult {
            result: FutureResultState::None,
            waker:  None
        };
        let result = Arc::new(Mutex::new(result));

        // Insert into a future
        let future = SchedulerFuture {
            queue:      Arc::clone(queue),
            scheduler:  core,
            result:     Arc::clone(&result)
        };

        (future, SchedulerFutureSignaller(result))
    }

    ///
    /// We moved the queue into the running state and need to drain it until we've got a result
    ///
    fn drain_queue(&mut self, context: &mut task::Context) -> task::Poll<Result<T, oneshot::Canceled>> {
        debug_assert!(self.queue.core.lock().expect("JobQueue core lock").state.is_running());

        // Set the queue as active
        let _active     = ActiveQueue { queue: &*self.queue };
        let mut result;

        // While there is no result, run a job from the queue
        loop {
            // See if the result has arrived yet
            result = self.result.lock().expect("Scheduler future result").result.take();
            if !result.is_none() { break; }

            // Run the next job in the queue
            if let Some(mut job) = self.queue.dequeue() {
                // Queue is running
                debug_assert!(self.queue.core.lock().expect("Job queue core").state.is_running());

                // Create a context to poll in (we may need to reschedule in the background)
                let waker               = Arc::new(DrainWaker::new());
                let waker_ref           = task::waker_ref(&waker);
                let mut drain_context   = task::Context::from_waker(&waker_ref);

                // Poll the queue
                let poll_result = job.run(&mut drain_context);

                match poll_result {
                    task::Poll::Ready(())   => {
                        // Keep running jobs and checking the results if ready
                    },

                    task::Poll::Pending     => {
                        // Requeue the job
                        self.queue.requeue(job);

                        // If the result was supplied, break out of the loop and reschedule the queue
                        result = self.result.lock().expect("Scheduler future result").result.take();
                        if result.is_some() {
                            // Wake the queue in the background if needed (the result has arrived)
                            self.queue.core.lock().expect("JobQueue core lock").state = QueueState::WaitingForWake;

                            let queue_waker = WakeQueue(Arc::clone(&self.queue), Arc::clone(&self.scheduler));
                            let queue_waker = Arc::new(queue_waker);
                            let queue_waker = task::waker(queue_waker);

                            waker.wake_with(queue_waker);

                            // The future is ready (job will be rescheduled in the background)
                            return task::Poll::Ready(result.unwrap());
                        } else {
                            // Wait for the next poll
                            self.queue.core.lock().expect("JobQueue core lock").state = QueueState::WaitingForPoll;

                            // Use the context waker
                            waker.wake_with(context.waker().clone());

                            // Result is pending
                            return task::Poll::Pending;
                        }
                    }
                }
            } else {
                // Queue is empty and our result hasn't arrived yet?!

                // Assume the future will resolve eventually: move the queue in to the background
                self.result.lock().expect("Scheduler future result").waker = Some(context.waker().clone());

                // Reschedule the queue
                self.queue.core.lock().expect("JobQueue core lock").state = QueueState::Idle;
                self.scheduler.reschedule_queue(&self.queue, Arc::clone(&self.scheduler));

                return task::Poll::Pending;
            }
        }

        // Reschedule the queue if there are any events left pending
        // Note: the queue is already pending when we start running events from it here.
        // This means it'll get dequeued by a thread eventually: maybe while it's running
        // here. As we've set the queue state to running while we're busy, the thread won't
        // start the queue while it's already running.
        self.queue.core.lock().expect("JobQueue core lock").state = QueueState::Idle;
        self.scheduler.reschedule_queue(&self.queue, Arc::clone(&self.scheduler));

        // Result must be available by this point
        task::Poll::Ready(result.unwrap())
    }
}

impl<T> Future for SchedulerFuture<T> {
    type Output = Result<T, oneshot::Canceled>;

    ///
    /// Polls this future
    ///
    fn poll(mut self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
        // Lock the result and determine which action to take
        let next_action = {
            let mut future_result = self.result.lock().expect("Scheduler future result");

            if let Some(result) = future_result.result.take() {
                // The result is available: we should return it immediately
                SchedulerAction::ReturnValue(result)
            } else {
                // If the queue is idle when this is called, we need to schedule this task on this thread rather than one owned by the background process
                let run_action = {
                    let mut core = self.queue.core.lock().expect("JobQueue core lock");

                    match core.state {
                        QueueState::Running             => SchedulerAction::WaitForCompletion,
                        QueueState::WaitingForWake      => SchedulerAction::WaitForCompletion,
                        QueueState::WaitingForUnpark    => SchedulerAction::WaitForCompletion,
                        QueueState::AwokenWhileRunning  => SchedulerAction::WaitForCompletion,
                        QueueState::Panicked            => SchedulerAction::Panic,
                        QueueState::WaitingForPoll      => { core.state = QueueState::Running; SchedulerAction::DrainQueue },
                        QueueState::Pending             => { core.state = QueueState::Running; SchedulerAction::DrainQueue },
                        QueueState::Idle                => { core.state = QueueState::Running; SchedulerAction::DrainQueue }
                    }
                };

                if let SchedulerAction::WaitForCompletion = run_action {
                    // Wake us up when the future is available
                    future_result.waker = Some(context.waker().clone());
                }

                run_action
            }
        };

        match next_action {
            SchedulerAction::WaitForCompletion  => task::Poll::Pending,
            SchedulerAction::ReturnValue(value) => task::Poll::Ready(value),
            SchedulerAction::DrainQueue         => self.drain_queue(context),
            SchedulerAction::Panic              => panic!("Cannot schedule jobs on a panicked queue"),
        }
    }
}

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

    #[test]
    fn returns_immediately_if_signaled() {
        use futures::executor;

        let scheduler           = scheduler();
        let queue               = queue();
        let (future, signaller) = SchedulerFuture::new(&queue, Arc::clone(&scheduler.core));

        signaller.signal(42);

        assert!(executor::block_on(future) == Ok(42));
    }

    #[test]
    fn cancels_when_dropped() {
        use futures::executor;

        let scheduler           = scheduler();
        let queue               = queue();
        let future              = { SchedulerFuture::<i32>::new(&queue, Arc::clone(&scheduler.core)).0 };

        assert!(executor::block_on(future) == Err(oneshot::Canceled));
    }

    #[test]
    fn signals_from_another_thread() {
        use futures::executor;
        use std::thread;
        use std::time::Duration;

        let scheduler           = scheduler();
        let queue               = queue();
        let (future, signaller) = SchedulerFuture::new(&queue, Arc::clone(&scheduler.core));

        thread::spawn(move || {
            thread::sleep(Duration::from_millis(100));

            signaller.signal(42);
        });

        assert!(executor::block_on(future) == Ok(42));
    }

    #[test]
    fn forces_queue_drain() {
        use futures::executor;
        use std::thread;
        use std::time::Duration;

        let scheduler   = scheduler();
        let queue       = queue();

        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        let (future, signaller) = SchedulerFuture::new(&queue, Arc::clone(&scheduler.core));

        scheduler.desync(&queue, move || {
            thread::sleep(Duration::from_millis(100));

            signaller.signal(42);
        });

        assert!(executor::block_on(future) == Ok(42));
    }
}
<|endoftext|>


<commit_before>//! Work around Rust not yet implemented trait upcast
//! https://github.com/rust-lang/rust/issues/5665#issuecomment-31582946

use std::any::Any;
use std::mem;

/// Hack against lack of upcasting in Rust
pub trait AsAny {
    fn as_any(&self) -> &Any;
    fn as_any_mut(&mut self) -> &mut Any;
    fn into_any_box(self: Box<Self>) -> Box<Any>;
    fn set_from_any(&mut self, any: Box<Any>);
    fn swap_with_any(&mut self, any: &mut Any);
}

impl<T: 'static> AsAny for T {
    fn as_any(&self) -> &Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut Any {
        self
    }

    fn into_any_box(self: Box<Self>) -> Box<Any> {
        Box::new(*self)
    }

    fn set_from_any(&mut self, any: Box<Any>) {
        *self = *any.downcast().expect("wrong type");
    }

    fn swap_with_any(&mut self, any: &mut Any) {
        let that = any.downcast_mut().expect("wrong type");
        mem::swap(self, that);
    }
}
<commit_msg>Remove unused AsAny function<commit_after>//! Work around Rust not yet implemented trait upcast
//! https://github.com/rust-lang/rust/issues/5665#issuecomment-31582946

use std::any::Any;

/// Hack against lack of upcasting in Rust
pub trait AsAny {
    fn as_any(&self) -> &Any;
    fn as_any_mut(&mut self) -> &mut Any;
    fn into_any_box(self: Box<Self>) -> Box<Any>;
}

impl<T: 'static> AsAny for T {
    fn as_any(&self) -> &Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut Any {
        self
    }

    fn into_any_box(self: Box<Self>) -> Box<Any> {
        Box::new(*self)
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc. All rights reserved.
//
// 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.

//! Data structures for tracking the state of the front-end's line cache
//! and preparing render plans to update it.

use std::cmp::{max, min};

const SCROLL_SLOP: usize = 2;
const PRESERVE_EXTENT: usize = 1000;

/// The line cache shadow tracks the state of the line cache in the front-end.
/// Any content marked as valid here is up-to-date in the current state of the
/// view. Also, if `dirty` is false, then the entire line cache is valid.
pub struct LineCacheShadow {
    spans: Vec<Span>,
    dirty: bool,
}

pub const TEXT_VALID: u8 = 1;
pub const STYLES_VALID: u8 = 2;
pub const CURSOR_VALID: u8 = 4;
pub const ALL_VALID: u8 = 7;

pub struct Span {
    /// Number of lines in this span. Units are visual lines in the
    /// current state of the view.
    pub n: usize,
    /// Starting line number. Units are visual lines in the front end's
    /// current cache state (i.e. the last one rendered). Note: this is
    /// irrelevant if validity is 0.
    pub start_line_num: usize,
    /// Validity of lines in this span, consisting of the above constants or'ed.
    pub validity: u8,
}

/// Builder for `LineCacheShadow` object.
pub struct Builder {
    spans: Vec<Span>,
    dirty: bool,
}

#[derive(Clone, Copy, PartialEq)]
pub enum RenderTactic {
    /// Discard all content for this span. Used to keep storage reasonable.
    Discard,
    /// Preserve existing content.
    Preserve,
    /// Render content if it is invalid.
    Render,
}

pub struct RenderPlan {
    /// Each span is a number of lines and a tactic.
    pub spans: Vec<(usize, RenderTactic)>,
}

pub struct PlanIterator<'a> {
    lc_shadow: &'a LineCacheShadow,
    plan: &'a RenderPlan,
    shadow_ix: usize,
    shadow_line_num: usize,
    plan_ix: usize,
    plan_line_num: usize,
}

pub struct PlanSegment {
    /// Line number of start of segment, visual lines in current view state.
    pub our_line_num: usize,
    /// Line number of start of segment, visual lines in client's cache, if validity != 0.
    pub their_line_num: usize,
    /// Number of visual lines in this segment.
    pub n: usize,
    /// Validity of this segment in client's cache.
    pub validity: u8,
    /// Tactic for rendering this segment.
    pub tactic: RenderTactic,
}

impl Builder {
    pub fn new() -> Builder {
        Builder { spans: Vec::new(), dirty: false }
    }

    pub fn build(self) -> LineCacheShadow {
        LineCacheShadow { spans: self.spans, dirty: self.dirty }
    }

    pub fn add_span(&mut self, n: usize, start_line_num: usize, validity: u8) {
        if n > 0 {
            if let Some(last) = self.spans.last_mut() {
                if last.validity == validity &&
                    (validity == 0 || last.start_line_num + last.n == start_line_num)
                {
                    last.n += n;
                    return;
                }
            }
            self.spans.push(Span { n, start_line_num, validity });
        }
    }

    pub fn set_dirty(&mut self, dirty: bool) {
        self.dirty = dirty;
    }
}

impl LineCacheShadow {
    pub fn edit(&mut self, start: usize, end: usize, replace: usize) {
        let mut b = Builder::new();
        let mut line_num = 0;
        let mut i = 0;
        while i < self.spans.len() {
            let span = &self.spans[i];
            if line_num + span.n <= start {
                b.add_span(span.n, span.start_line_num, span.validity);
                line_num += span.n;
                i += 1;
            } else {
                b.add_span(start - line_num, span.start_line_num, span.validity);
                break;
            }
        }
        b.add_span(replace, 0, 0);
        for span in &self.spans[i..] {
            if line_num + span.n > end {
                let offset = end.saturating_sub(line_num);
                b.add_span(span.n - offset, span.start_line_num + offset, span.validity);
            }
            line_num += span.n;
        }
        b.set_dirty(true);
        *self = b.build();
    }

    pub fn partial_invalidate(&mut self, start: usize, end: usize, invalid: u8) {
        let mut clean = true;
        let mut line_num = 0;
        for span in &self.spans {
            if start < line_num + span.n && end > line_num && (span.validity & invalid) != 0 {
                clean = false;
                break;
            }
            line_num += span.n;
        }
        if clean {
            return;
        }

        let mut b = Builder::new();
        let mut line_num = 0;
        for span in &self.spans {
            if start > line_num {
                b.add_span(min(span.n, start - line_num), span.start_line_num, span.validity);
            }
            let invalid_start = max(start, line_num);
            let invalid_end = min(end, line_num + span.n);
            if invalid_end > invalid_start {
                b.add_span(invalid_end - invalid_start,
                    span.start_line_num + (invalid_start - line_num),
                    span.validity & !invalid);
            }
            if line_num + span.n > end {
                let offset = end.saturating_sub(line_num);
                b.add_span(span.n - offset, span.start_line_num + offset, span.validity);
            }
            line_num += span.n;
        }
        b.set_dirty(true);
        *self = b.build();
    }

    pub fn needs_render(&self, plan: &RenderPlan) -> bool {
        self.dirty || self.iter_with_plan(plan).any(|seg|
            seg.tactic == RenderTactic::Render && seg.validity != ALL_VALID
        )
    }

    pub fn spans(&self) -> &[Span] {
        &self.spans
    }

    pub fn iter_with_plan<'a>(&'a self, plan: &'a RenderPlan) -> PlanIterator<'a> {
        PlanIterator { lc_shadow: self, plan,
            shadow_ix: 0, shadow_line_num: 0, plan_ix: 0, plan_line_num: 0 }
    }
}

impl Default for LineCacheShadow {
    fn default() -> LineCacheShadow {
        Builder::new().build()
    }
}

impl<'a> Iterator for PlanIterator<'a> {
    type Item = PlanSegment;

    fn next(&mut self) -> Option<PlanSegment> {
        if self.shadow_ix == self.lc_shadow.spans.len() || self.plan_ix == self.plan.spans.len() {
            return None;
        }
        let shadow_span = &self.lc_shadow.spans[self.shadow_ix];
        let plan_span = &self.plan.spans[self.plan_ix];
        let start = max(self.shadow_line_num, self.plan_line_num);
        let end = min(self.shadow_line_num + shadow_span.n, self.plan_line_num + plan_span.0);
        let result = PlanSegment {
            our_line_num: start,
            their_line_num: shadow_span.start_line_num + (start - self.shadow_line_num),
            n: end - start,
            validity: shadow_span.validity,
            tactic: plan_span.1,
        };
        if end == self.shadow_line_num + shadow_span.n {
            self.shadow_line_num = end;
            self.shadow_ix += 1;
        }
        if end == self.plan_line_num + plan_span.0 {
            self.plan_line_num = end;
            self.plan_ix += 1;
        }
        Some(result)
    }
}

impl RenderPlan {
    /// This function implements the policy of what to discard, what to preserve, and
    /// what to render.
    pub fn create(total_height: usize, first_line: usize, height: usize) -> RenderPlan {
        let mut spans = Vec::new();
        let mut last = 0;
        if first_line > PRESERVE_EXTENT {
            last = first_line - PRESERVE_EXTENT;
            spans.push((last, RenderTactic::Discard));
        }
        if first_line > SCROLL_SLOP {
            let n = first_line - SCROLL_SLOP - last;
            spans.push((n, RenderTactic::Preserve));
            last += n;
        }
        let render_end = min(first_line + height + SCROLL_SLOP, total_height);
        spans.push((render_end - last, RenderTactic::Render));
        last = render_end;
        let preserve_end = min(first_line + height + PRESERVE_EXTENT, total_height);
        if preserve_end > last {
            spans.push((preserve_end - last, RenderTactic::Preserve));
            last = preserve_end;
        }
        if total_height > last {
            spans.push((total_height - last, RenderTactic::Discard));
        }
        RenderPlan { spans }
    }

    /// Upgrade a range of lines to the "Render" tactic.
    pub fn request_lines(&mut self, start: usize, end: usize) {
        let mut spans: Vec<(usize, RenderTactic)> = Vec::new();
        let mut i = 0;
        let mut line_num = 0;
        while i < self.spans.len() {
            let span = &self.spans[i];
            if line_num + span.0 <= start {
                spans.push(*span);
                line_num += span.0;
                i += 1;
            } else {
                if line_num < start {
                    spans.push((start - line_num, span.1));
                }
                break;
            }
        }
        spans.push((end - start, RenderTactic::Render));
        for span in &self.spans[i..] {
            if line_num + span.0 > end {
                let offset = end.saturating_sub(line_num);
                spans.push((span.0 - offset, span.1));
            }
            line_num += span.0;
        }
        self.spans = spans;
    }
}
<commit_msg>Clamp start of render request region<commit_after>// Copyright 2017 Google Inc. All rights reserved.
//
// 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.

//! Data structures for tracking the state of the front-end's line cache
//! and preparing render plans to update it.

use std::cmp::{max, min};

const SCROLL_SLOP: usize = 2;
const PRESERVE_EXTENT: usize = 1000;

/// The line cache shadow tracks the state of the line cache in the front-end.
/// Any content marked as valid here is up-to-date in the current state of the
/// view. Also, if `dirty` is false, then the entire line cache is valid.
pub struct LineCacheShadow {
    spans: Vec<Span>,
    dirty: bool,
}

pub const TEXT_VALID: u8 = 1;
pub const STYLES_VALID: u8 = 2;
pub const CURSOR_VALID: u8 = 4;
pub const ALL_VALID: u8 = 7;

pub struct Span {
    /// Number of lines in this span. Units are visual lines in the
    /// current state of the view.
    pub n: usize,
    /// Starting line number. Units are visual lines in the front end's
    /// current cache state (i.e. the last one rendered). Note: this is
    /// irrelevant if validity is 0.
    pub start_line_num: usize,
    /// Validity of lines in this span, consisting of the above constants or'ed.
    pub validity: u8,
}

/// Builder for `LineCacheShadow` object.
pub struct Builder {
    spans: Vec<Span>,
    dirty: bool,
}

#[derive(Clone, Copy, PartialEq)]
pub enum RenderTactic {
    /// Discard all content for this span. Used to keep storage reasonable.
    Discard,
    /// Preserve existing content.
    Preserve,
    /// Render content if it is invalid.
    Render,
}

pub struct RenderPlan {
    /// Each span is a number of lines and a tactic.
    pub spans: Vec<(usize, RenderTactic)>,
}

pub struct PlanIterator<'a> {
    lc_shadow: &'a LineCacheShadow,
    plan: &'a RenderPlan,
    shadow_ix: usize,
    shadow_line_num: usize,
    plan_ix: usize,
    plan_line_num: usize,
}

pub struct PlanSegment {
    /// Line number of start of segment, visual lines in current view state.
    pub our_line_num: usize,
    /// Line number of start of segment, visual lines in client's cache, if validity != 0.
    pub their_line_num: usize,
    /// Number of visual lines in this segment.
    pub n: usize,
    /// Validity of this segment in client's cache.
    pub validity: u8,
    /// Tactic for rendering this segment.
    pub tactic: RenderTactic,
}

impl Builder {
    pub fn new() -> Builder {
        Builder { spans: Vec::new(), dirty: false }
    }

    pub fn build(self) -> LineCacheShadow {
        LineCacheShadow { spans: self.spans, dirty: self.dirty }
    }

    pub fn add_span(&mut self, n: usize, start_line_num: usize, validity: u8) {
        if n > 0 {
            if let Some(last) = self.spans.last_mut() {
                if last.validity == validity &&
                    (validity == 0 || last.start_line_num + last.n == start_line_num)
                {
                    last.n += n;
                    return;
                }
            }
            self.spans.push(Span { n, start_line_num, validity });
        }
    }

    pub fn set_dirty(&mut self, dirty: bool) {
        self.dirty = dirty;
    }
}

impl LineCacheShadow {
    pub fn edit(&mut self, start: usize, end: usize, replace: usize) {
        let mut b = Builder::new();
        let mut line_num = 0;
        let mut i = 0;
        while i < self.spans.len() {
            let span = &self.spans[i];
            if line_num + span.n <= start {
                b.add_span(span.n, span.start_line_num, span.validity);
                line_num += span.n;
                i += 1;
            } else {
                b.add_span(start - line_num, span.start_line_num, span.validity);
                break;
            }
        }
        b.add_span(replace, 0, 0);
        for span in &self.spans[i..] {
            if line_num + span.n > end {
                let offset = end.saturating_sub(line_num);
                b.add_span(span.n - offset, span.start_line_num + offset, span.validity);
            }
            line_num += span.n;
        }
        b.set_dirty(true);
        *self = b.build();
    }

    pub fn partial_invalidate(&mut self, start: usize, end: usize, invalid: u8) {
        let mut clean = true;
        let mut line_num = 0;
        for span in &self.spans {
            if start < line_num + span.n && end > line_num && (span.validity & invalid) != 0 {
                clean = false;
                break;
            }
            line_num += span.n;
        }
        if clean {
            return;
        }

        let mut b = Builder::new();
        let mut line_num = 0;
        for span in &self.spans {
            if start > line_num {
                b.add_span(min(span.n, start - line_num), span.start_line_num, span.validity);
            }
            let invalid_start = max(start, line_num);
            let invalid_end = min(end, line_num + span.n);
            if invalid_end > invalid_start {
                b.add_span(invalid_end - invalid_start,
                    span.start_line_num + (invalid_start - line_num),
                    span.validity & !invalid);
            }
            if line_num + span.n > end {
                let offset = end.saturating_sub(line_num);
                b.add_span(span.n - offset, span.start_line_num + offset, span.validity);
            }
            line_num += span.n;
        }
        b.set_dirty(true);
        *self = b.build();
    }

    pub fn needs_render(&self, plan: &RenderPlan) -> bool {
        self.dirty || self.iter_with_plan(plan).any(|seg|
            seg.tactic == RenderTactic::Render && seg.validity != ALL_VALID
        )
    }

    pub fn spans(&self) -> &[Span] {
        &self.spans
    }

    pub fn iter_with_plan<'a>(&'a self, plan: &'a RenderPlan) -> PlanIterator<'a> {
        PlanIterator { lc_shadow: self, plan,
            shadow_ix: 0, shadow_line_num: 0, plan_ix: 0, plan_line_num: 0 }
    }
}

impl Default for LineCacheShadow {
    fn default() -> LineCacheShadow {
        Builder::new().build()
    }
}

impl<'a> Iterator for PlanIterator<'a> {
    type Item = PlanSegment;

    fn next(&mut self) -> Option<PlanSegment> {
        if self.shadow_ix == self.lc_shadow.spans.len() || self.plan_ix == self.plan.spans.len() {
            return None;
        }
        let shadow_span = &self.lc_shadow.spans[self.shadow_ix];
        let plan_span = &self.plan.spans[self.plan_ix];
        let start = max(self.shadow_line_num, self.plan_line_num);
        let end = min(self.shadow_line_num + shadow_span.n, self.plan_line_num + plan_span.0);
        let result = PlanSegment {
            our_line_num: start,
            their_line_num: shadow_span.start_line_num + (start - self.shadow_line_num),
            n: end - start,
            validity: shadow_span.validity,
            tactic: plan_span.1,
        };
        if end == self.shadow_line_num + shadow_span.n {
            self.shadow_line_num = end;
            self.shadow_ix += 1;
        }
        if end == self.plan_line_num + plan_span.0 {
            self.plan_line_num = end;
            self.plan_ix += 1;
        }
        Some(result)
    }
}

impl RenderPlan {
    /// This function implements the policy of what to discard, what to preserve, and
    /// what to render.
    pub fn create(total_height: usize, first_line: usize, height: usize) -> RenderPlan {
        let mut spans = Vec::new();
        let mut last = 0;
        let first_line = min(first_line, total_height);
        if first_line > PRESERVE_EXTENT {
            last = first_line - PRESERVE_EXTENT;
            spans.push((last, RenderTactic::Discard));
        }
        if first_line > SCROLL_SLOP {
            let n = first_line - SCROLL_SLOP - last;
            spans.push((n, RenderTactic::Preserve));
            last += n;
        }
        let render_end = min(first_line + height + SCROLL_SLOP, total_height);
        spans.push((render_end - last, RenderTactic::Render));
        last = render_end;
        let preserve_end = min(first_line + height + PRESERVE_EXTENT, total_height);
        if preserve_end > last {
            spans.push((preserve_end - last, RenderTactic::Preserve));
            last = preserve_end;
        }
        if total_height > last {
            spans.push((total_height - last, RenderTactic::Discard));
        }
        RenderPlan { spans }
    }

    /// Upgrade a range of lines to the "Render" tactic.
    pub fn request_lines(&mut self, start: usize, end: usize) {
        let mut spans: Vec<(usize, RenderTactic)> = Vec::new();
        let mut i = 0;
        let mut line_num = 0;
        while i < self.spans.len() {
            let span = &self.spans[i];
            if line_num + span.0 <= start {
                spans.push(*span);
                line_num += span.0;
                i += 1;
            } else {
                if line_num < start {
                    spans.push((start - line_num, span.1));
                }
                break;
            }
        }
        spans.push((end - start, RenderTactic::Render));
        for span in &self.spans[i..] {
            if line_num + span.0 > end {
                let offset = end.saturating_sub(line_num);
                spans.push((span.0 - offset, span.1));
            }
            line_num += span.0;
        }
        self.spans = spans;
    }
}
<|endoftext|>