<commit_before>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.static_root_path.unwrap_or(page.root_path);
    format!(
        "<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
            \
        </button>\

\

\
    \
    \
        <form class=\"search-form\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           disabled \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                <button type=\"button\" class=\"help-button\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\

\
    {after_content}\

    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = page.description,
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
        },
        in_header = layout.external_html.in_header,
        before_content = layout.external_html.before_content,
        after_content = layout.external_html.after_content,
        sidebar = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<commit_msg>Auto merge of #83094 - GuillaumeGomez:crates-js-location, r=Nemo157<commit_after>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.static_root_path.unwrap_or(page.root_path);
    format!(
        "<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
            \
        </button>\

\

\
    \
    \
        <form class=\"search-form\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           disabled \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                <button type=\"button\" class=\"help-button\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\

\
    {after_content}\

    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = page.description,
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
        },
        in_header = layout.external_html.in_header,
        before_content = layout.external_html.before_content,
        after_content = layout.external_html.after_content,
        sidebar = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub type CellID = usize;
pub type CallbackID = usize;

struct Cell<'a, T: Copy> {
    value: T,
    last_value: T,
    dependents: Vec<CellID>,
    cell_type: CellType<'a, T>,
    callbacks_issued: usize,
    callbacks: HashMap<CallbackID, Box<FnMut(T) -> () + 'a>>,
}

enum CellType<'a, T: Copy> {
    Input,
    Compute(Vec<CellID>, Box<Fn(&[T]) -> T + 'a>),
}

impl <'a, T: Copy> Cell<'a, T> {
    fn new(initial: T, cell_type: CellType<'a, T>) -> Self {
        Cell {
            value: initial,
            last_value: initial,
            dependents: Vec::new(),
            cell_type: cell_type,
            callbacks_issued: 0,
            callbacks: HashMap::new(),
        }
    }
}

pub struct Reactor<'a, T: Copy> {
    cells: Vec<Cell<'a, T>>,
}

impl <'a, T: Copy + PartialEq> Reactor<'a, T> {
    pub fn new() -> Self {
        Reactor{
            cells: Vec::new(),
        }
    }

    pub fn create_input(&mut self, initial: T) -> CellID {
        self.cells.push(Cell::new(initial, CellType::Input));
        self.cells.len() - 1
    }

    pub fn create_compute<F: Fn(&[T]) -> T + 'a>(&mut self, dependencies: &[CellID], compute_func: F) -> Result<CellID, CellID> {
        // Check all dependencies' validity before modifying any of them,
        // so that we don't perform an incorrect partial write.
        if let Some(&invalid) = dependencies.iter().find(|&dep| *dep >= self.cells.len()) {
            return Err(invalid);
        }
        let new_id = self.cells.len();
        for &id in dependencies {
            self.cells.get_mut(id).unwrap().dependents.push(new_id);
        }
        let inputs: Vec<_> = dependencies.iter().map(|&id| self.value(id).unwrap()).collect();
        let initial = compute_func(&inputs);
        self.cells.push(Cell::new(initial, CellType::Compute(dependencies.iter().cloned().collect(), Box::new(compute_func))));
        Ok(new_id)
    }

    pub fn value(&self, id: CellID) -> Option<T> {
        self.cells.get(id).map(|c| c.value)
    }

    pub fn set_value(&mut self, id: CellID, new_value: T) -> Result<(), &'static str> {
        match self.cells.get_mut(id) {
            Some(c) => match c.cell_type {
                CellType::Input => {
                    c.value = new_value;
                    Ok(c.dependents.clone())
                },
                CellType::Compute(_, _) => Err("Can't set compute cell value directly"),
            },
            None => Err("Can't set nonexistent cell"),
        }.map(|deps| {
            for &d in deps.iter() {
                self.update_dependent(d);
            }
            // We can only fire callbacks after all dependents have updated.
            // So we can't combine this for loop with the one above!
            for d in deps {
                self.fire_callbacks(d);
            }
        })
    }

    pub fn add_callback<F: FnMut(T) -> () + 'a>(&mut self, id: CellID, callback: F) -> Option<CallbackID> {
        match self.cells.get_mut(id) {
            Some(c) => {
                c.callbacks_issued += 1;
                c.callbacks.insert(c.callbacks_issued, Box::new(callback));
                Some(c.callbacks_issued)
            },
            None => None,
        }
    }

    pub fn remove_callback(&mut self, cell: CellID, callback: CallbackID) -> Result<(), &'static str> {
        match self.cells.get_mut(cell) {
            Some(c) => match c.callbacks.remove(&callback) {
                Some(_) => Ok(()),
                None => Err("Can't remove nonexistent callback"),
            },
            None => Err("Can't remove callback from nonexistent cell"),
        }
    }

    fn update_dependent(&mut self, id: CellID) {
        let (new_value, dependents) = {
            // This block limits the scope of the self.cells borrow.
            // This is necessary becaue we borrow it mutably below.
            let (dependencies, f, dependents) = match self.cells.get(id) {
                Some(c) => match c.cell_type {
                    CellType::Input => panic!("Input cell can't be a dependent"),
                    CellType::Compute(ref dependencies, ref f) => (dependencies, f, c.dependents.clone()),
                },
                None => panic!("Cell to update disappeared while querying"),
            };
            let inputs: Vec<_> = dependencies.iter().map(|&id| self.value(id).unwrap()).collect();
            (f(&inputs), dependents)
        };

        match self.cells.get_mut(id) {
            Some(c) => {
                if c.value == new_value {
                    // No change here, we don't need to update our dependents.
                    // (It wouldn't hurt to, but it would be unnecessary work)
                    return;
                }
                c.value = new_value;
            },
            None => panic!("Cell to update disappeared while updating"),
        }

        for d in dependents {
            self.update_dependent(d);
        }
    }

    fn fire_callbacks(&mut self, id: CellID) {
        let dependents = match self.cells.get_mut(id) {
            Some(c) => {
                if c.value == c.last_value {
                    // Value hasn't changed since last callback fire.
                    // We thus shouldn't fire the callbacks.
                    return
                }
                for cb in c.callbacks.values_mut() {
                    cb(c.value);
                }
                c.last_value = c.value;
                c.dependents.clone()
            },
            None => panic!("Callback cell disappeared"),
        };

        for d in dependents {
            self.fire_callbacks(d);
        }
    }
}
<commit_msg>react: Use Option::map in add_callback example<commit_after>use std::collections::HashMap;

pub type CellID = usize;
pub type CallbackID = usize;

struct Cell<'a, T: Copy> {
    value: T,
    last_value: T,
    dependents: Vec<CellID>,
    cell_type: CellType<'a, T>,
    callbacks_issued: usize,
    callbacks: HashMap<CallbackID, Box<FnMut(T) -> () + 'a>>,
}

enum CellType<'a, T: Copy> {
    Input,
    Compute(Vec<CellID>, Box<Fn(&[T]) -> T + 'a>),
}

impl <'a, T: Copy> Cell<'a, T> {
    fn new(initial: T, cell_type: CellType<'a, T>) -> Self {
        Cell {
            value: initial,
            last_value: initial,
            dependents: Vec::new(),
            cell_type: cell_type,
            callbacks_issued: 0,
            callbacks: HashMap::new(),
        }
    }
}

pub struct Reactor<'a, T: Copy> {
    cells: Vec<Cell<'a, T>>,
}

impl <'a, T: Copy + PartialEq> Reactor<'a, T> {
    pub fn new() -> Self {
        Reactor{
            cells: Vec::new(),
        }
    }

    pub fn create_input(&mut self, initial: T) -> CellID {
        self.cells.push(Cell::new(initial, CellType::Input));
        self.cells.len() - 1
    }

    pub fn create_compute<F: Fn(&[T]) -> T + 'a>(&mut self, dependencies: &[CellID], compute_func: F) -> Result<CellID, CellID> {
        // Check all dependencies' validity before modifying any of them,
        // so that we don't perform an incorrect partial write.
        if let Some(&invalid) = dependencies.iter().find(|&dep| *dep >= self.cells.len()) {
            return Err(invalid);
        }
        let new_id = self.cells.len();
        for &id in dependencies {
            self.cells.get_mut(id).unwrap().dependents.push(new_id);
        }
        let inputs: Vec<_> = dependencies.iter().map(|&id| self.value(id).unwrap()).collect();
        let initial = compute_func(&inputs);
        self.cells.push(Cell::new(initial, CellType::Compute(dependencies.iter().cloned().collect(), Box::new(compute_func))));
        Ok(new_id)
    }

    pub fn value(&self, id: CellID) -> Option<T> {
        self.cells.get(id).map(|c| c.value)
    }

    pub fn set_value(&mut self, id: CellID, new_value: T) -> Result<(), &'static str> {
        match self.cells.get_mut(id) {
            Some(c) => match c.cell_type {
                CellType::Input => {
                    c.value = new_value;
                    Ok(c.dependents.clone())
                },
                CellType::Compute(_, _) => Err("Can't set compute cell value directly"),
            },
            None => Err("Can't set nonexistent cell"),
        }.map(|deps| {
            for &d in deps.iter() {
                self.update_dependent(d);
            }
            // We can only fire callbacks after all dependents have updated.
            // So we can't combine this for loop with the one above!
            for d in deps {
                self.fire_callbacks(d);
            }
        })
    }

    pub fn add_callback<F: FnMut(T) -> () + 'a>(&mut self, id: CellID, callback: F) -> Option<CallbackID> {
        self.cells.get_mut(id).map(|c| {
            c.callbacks_issued += 1;
            c.callbacks.insert(c.callbacks_issued, Box::new(callback));
            c.callbacks_issued
        })
    }

    pub fn remove_callback(&mut self, cell: CellID, callback: CallbackID) -> Result<(), &'static str> {
        match self.cells.get_mut(cell) {
            Some(c) => match c.callbacks.remove(&callback) {
                Some(_) => Ok(()),
                None => Err("Can't remove nonexistent callback"),
            },
            None => Err("Can't remove callback from nonexistent cell"),
        }
    }

    fn update_dependent(&mut self, id: CellID) {
        let (new_value, dependents) = {
            // This block limits the scope of the self.cells borrow.
            // This is necessary becaue we borrow it mutably below.
            let (dependencies, f, dependents) = match self.cells.get(id) {
                Some(c) => match c.cell_type {
                    CellType::Input => panic!("Input cell can't be a dependent"),
                    CellType::Compute(ref dependencies, ref f) => (dependencies, f, c.dependents.clone()),
                },
                None => panic!("Cell to update disappeared while querying"),
            };
            let inputs: Vec<_> = dependencies.iter().map(|&id| self.value(id).unwrap()).collect();
            (f(&inputs), dependents)
        };

        match self.cells.get_mut(id) {
            Some(c) => {
                if c.value == new_value {
                    // No change here, we don't need to update our dependents.
                    // (It wouldn't hurt to, but it would be unnecessary work)
                    return;
                }
                c.value = new_value;
            },
            None => panic!("Cell to update disappeared while updating"),
        }

        for d in dependents {
            self.update_dependent(d);
        }
    }

    fn fire_callbacks(&mut self, id: CellID) {
        let dependents = match self.cells.get_mut(id) {
            Some(c) => {
                if c.value == c.last_value {
                    // Value hasn't changed since last callback fire.
                    // We thus shouldn't fire the callbacks.
                    return
                }
                for cb in c.callbacks.values_mut() {
                    cb(c.value);
                }
                c.last_value = c.value;
                c.dependents.clone()
            },
            None => panic!("Callback cell disappeared"),
        };

        for d in dependents {
            self.fire_callbacks(d);
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use core::mem;

/// A Multiboot tag structure is just a queryable blob of bytes. The implementation presently
/// assumes that the size is at least 8 bytes (for the end tag), and does not check this.
const BOOT_COMMAND_LINE: u32   = 1;
const BOOT_LOADER_NAME: u32    = 2;
const MODULE: u32            = 3;
const MEMORY_INFORMATION: u32 = 4;
const BIOS_BOOT_DEVICE: u32    = 5;
const MEMORY_MAP: u32         = 6;
const VBE_INFO: u32           = 7;
const FRAME_BUFFER_INFO: u32   = 8;
const ELF_SYMBOLS: u32        = 9;
const APM_TABLE: u32          = 10;

type TagType = u32;

type TagSize = u32;

#[repr(C)]
struct Tag {
	// Pointer to the first byte of the Tag block.
	ptr: *const u8,
}

impl Tag {
	fn tag_type(&self) -> TagType {
		let ptr = self.ptr as *const u32;
		unsafe {
			*ptr
		}
	}

	fn size(&self) -> TagSize {
		let ptr = ((self.ptr as usize) + 4) as *const u32;
		unsafe {
			*ptr
		}
	}
}<commit_msg>Remove unused type synonyms.<commit_after>#![allow(dead_code)]
use core::mem;

/// A Multiboot tag structure is just a queryable blob of bytes. The implementation presently
/// assumes that the size is at least 8 bytes (for the end tag), and does not check this.
const BOOT_COMMAND_LINE: u32   = 1;
const BOOT_LOADER_NAME: u32    = 2;
const MODULE: u32            = 3;
const MEMORY_INFORMATION: u32 = 4;
const BIOS_BOOT_DEVICE: u32    = 5;
const MEMORY_MAP: u32         = 6;
const VBE_INFO: u32           = 7;
const FRAME_BUFFER_INFO: u32   = 8;
const ELF_SYMBOLS: u32        = 9;
const APM_TABLE: u32          = 10;

#[repr(C)]
struct Tag {
	// Pointer to the first byte of the Tag block.
	ptr: *const u8,
}

impl Tag {
	fn tag_type(&self) -> u32 {
		let ptr = self.ptr as *const u32;
		unsafe {
			*ptr
		}
	}

	fn size(&self) -> u32 {
		let ptr = ((self.ptr as usize) + 4) as *const u32;
		unsafe {
			*ptr
		}
	}
}<|endoftext|>


<commit_before>use node_types::{escape_name, node_type_name, Entry, Field, Storage, TypeName};
use std::collections::BTreeMap as Map;
use std::collections::BTreeSet as Set;
use std::fmt;
use std::path::Path;
use tracing::{error, info, span, Level};
use tree_sitter::{Language, Node, Parser, Tree};

pub struct Extractor {
    pub parser: Parser,
    pub schema: Vec<Entry>,
}

pub fn create(language: Language, schema: Vec<Entry>) -> Extractor {
    let mut parser = Parser::new();
    parser.set_language(language).unwrap();

    Extractor { parser, schema }
}
impl Extractor {
    pub fn extract<'a>(&'a mut self, path: &Path) -> std::io::Result<Program> {
        let span = span!(
            Level::TRACE,
            "extract",
            file = %path.display()
        );

        let _enter = span.enter();

        info!("extracting: {}", path.display());

        let source = std::fs::read(&path)?;
        let tree = &self
            .parser
            .parse(&source, None)
            .expect("Failed to parse file");
        let mut visitor = Visitor {
            source: &source,
            trap_output: vec![TrapEntry::Comment(format!(
                "Auto-generated TRAP file for {}",
                path.display()
            ))],
            counter: -1,
            // TODO: should we handle path strings that are not valid UTF8 better?
            path: format!("{}", path.display()),
            stack: Vec::new(),
            tables: build_schema_lookup(&self.schema),
            union_types: build_union_type_lookup(&self.schema),
        };
        traverse(&tree, &mut visitor);

        &self.parser.reset();
        Ok(Program(visitor.trap_output))
    }
}

fn build_schema_lookup<'a>(schema: &'a Vec<Entry>) -> Map<&'a TypeName, &'a Entry> {
    let mut map = std::collections::BTreeMap::new();
    for entry in schema {
        if let Entry::Table { type_name, .. } = entry {
            map.insert(type_name, entry);
        }
    }
    map
}

fn build_union_type_lookup<'a>(schema: &'a Vec<Entry>) -> Map<&'a TypeName, &'a Set<TypeName>> {
    let mut union_types = std::collections::BTreeMap::new();
    for entry in schema {
        if let Entry::Union { type_name, members } = entry {
            union_types.insert(type_name, members);
        }
    }
    union_types
}

struct Visitor<'a> {
    /// The file path of the source code (as string)
    path: String,
    /// The source code as a UTF-8 byte array
    source: &'a Vec<u8>,
    /// The accumulated trap entries
    trap_output: Vec<TrapEntry>,
    /// A counter for generating fresh labels
    counter: i32,
    /// A lookup table from type name to dbscheme table entries
    tables: Map<&'a TypeName, &'a Entry>,
    /// A lookup table for union types mapping a type name to its direct members
    union_types: Map<&'a TypeName, &'a Set<TypeName>>,
    /// A stack for gathering information from hild nodes. Whenever a node is entered
    /// an empty list is pushed. All children append their data (field name, label, type) to
    /// the the list. When the visitor leaves a node the list containing the child data is popped
    /// from the stack and matched against the dbscheme for the node. If the expectations are met
    /// the corresponding row definitions are added to the trap_output.
    stack: Vec<Vec<(Option<&'static str>, Label, TypeName)>>,
}

impl Visitor<'_> {
    fn enter_node(&mut self, node: Node) -> bool {
        if node.is_error() {
            error!("{}:{}: parse error", &self.path, node.start_position().row);
            return false;
        }
        if node.is_missing() {
            error!(
                "{}:{}: parse error: expecting '{}'",
                &self.path,
                node.start_position().row,
                node.kind()
            );
            return false;
        }

        if node.is_extra() {
            return false;
        }

        self.stack.push(Vec::new());
        return true;
    }

    fn leave_node(&mut self, field_name: Option<&'static str>, node: Node) {
        if node.is_extra() || node.is_error() || node.is_missing() {
            return;
        }
        let child_nodes = self.stack.pop().expect("Vistor: empty stack");
        let table = self.tables.get(&TypeName {
            kind: node.kind().to_owned(),
            named: node.is_named(),
        });
        if let Some(Entry::Table { fields, .. }) = table {
            self.counter += 1;
            let id = Label::Normal(self.counter);
            let loc = Label::Location(self.counter);
            self.trap_output.push(TrapEntry::New(id));
            self.trap_output.push(TrapEntry::New(loc));
            self.trap_output
                .push(location_for(&self.source, &self.path, loc, node));
            let table_name = node_type_name(node.kind(), node.is_named());
            let args: Option<Vec<Arg>>;
            if fields.is_empty() {
                args = Some(vec![sliced_source_arg(self.source, node)]);
            } else {
                args = self.complex_node(&node, fields, child_nodes, id);
            }
            if let Some(args) = args {
                self.trap_output
                    .push(TrapEntry::Definition(table_name, id, args, loc));
            }
            if let Some(parent) = self.stack.last_mut() {
                parent.push((
                    field_name,
                    id,
                    TypeName {
                        kind: node.kind().to_owned(),
                        named: node.is_named(),
                    },
                ))
            };
        } else {
            error!(
                "{}:{}: unknown table type: '{}'",
                &self.path,
                node.start_position().row,
                node.kind()
            );
        }
    }
    fn complex_node(
        &mut self,
        node: &Node,
        fields: &Vec<Field>,
        child_nodes: Vec<(Option<&str>, Label, TypeName)>,
        parent_id: Label,
    ) -> Option<Vec<Arg>> {
        let mut map: Map<&Option<String>, (&Field, Vec<Label>)> = std::collections::BTreeMap::new();
        for field in fields {
            map.insert(&field.name, (field, Vec::new()));
        }
        for (child_field, child_id, child_type) in child_nodes {
            if let Some((field, values)) = map.get_mut(&child_field.map(|x| x.to_owned())) {
                //TODO: handle error and missing nodes
                if self.type_matches(&child_type, &field.types) {
                    values.push(child_id);
                } else if field.name.is_some() {
                    error!(
                        "{}:{}: type mismatch for field {}::{} with type {:?} != {:?}",
                        &self.path,
                        node.start_position().row,
                        node.kind(),
                        child_field.unwrap_or("child"),
                        child_type,
                        field.types
                    )
                }
            } else {
                if child_field.is_some() || child_type.named {
                    error!(
                        "{}:{}: value for unknown field: {}::{} and type {:?}",
                        &self.path,
                        node.start_position().row,
                        node.kind(),
                        &child_field.unwrap_or("child"),
                        &child_type
                    );
                }
            }
        }
        let mut args = Vec::new();
        let mut is_valid = true;
        for field in fields {
            let child_ids = &map.get(&field.name).unwrap().1;
            match &field.storage {
                Storage::Column => {
                    if child_ids.len() == 1 {
                        args.push(Arg::Label(*child_ids.first().unwrap()));
                    } else {
                        is_valid = false;
                        error!(
                            "{}:{}: {} for field: {}::{}",
                            &self.path,
                            node.start_position().row,
                            if child_ids.is_empty() {
                                "missing value"
                            } else {
                                "too many values"
                            },
                            node.kind(),
                            &field.get_name()
                        )
                    }
                }
                Storage::Table(has_index) => {
                    for (index, child_id) in child_ids.iter().enumerate() {
                        if !*has_index && index > 0 {
                            error!(
                                "saw multiple occurrences of field that should occur at most once"
                            );
                            break;
                        }
                        self.trap_output.push(TrapEntry::ChildOf(
                            node_type_name(&field.parent.kind, field.parent.named),
                            parent_id,
                            field.get_name(),
                            if *has_index { Some(Index(index)) } else { None },
                            *child_id,
                        ));
                    }
                }
            }
        }
        if is_valid {
            Some(args)
        } else {
            None
        }
    }
    fn type_matches(&self, tp: &TypeName, types: &Set<TypeName>) -> bool {
        if types.contains(tp) {
            return true;
        }
        for other in types.iter() {
            if let Some(x) = self.union_types.get(other) {
                if self.type_matches(tp, x) {
                    return true;
                }
            }
        }
        return false;
    }
}

// Emit a slice of a source file as an Arg.
fn sliced_source_arg(source: &Vec<u8>, n: Node) -> Arg {
    let range = n.byte_range();
    Arg::String(String::from(
        std::str::from_utf8(&source[range.start..range.end]).expect("Failed to decode string"),
    ))
}

// Emit a 'Located' TrapEntry for the provided node, appropriately calibrated.
fn location_for<'a>(source: &Vec<u8>, fp: &String, label: Label, n: Node) -> TrapEntry {
    // Tree-sitter row, column values are 0-based while CodeQL starts
    // counting at 1. In addition Tree-sitter's row and column for the
    // end position are exclusive while CodeQL's end positions are inclusive.
    // This means that all values should be incremented by 1 and in addition the
    // end position needs to be shift 1 to the left. In most cases this means
    // simply incrementing all values except the end column except in cases where
    // the end column is 0 (start of a line). In such cases the end position must be
    // set to the end of the previous line.
    let start_line = n.start_position().row + 1;
    let start_col = n.start_position().column + 1;
    let mut end_line = n.end_position().row + 1;
    let mut end_col = n.end_position().column;
    if start_line > end_line || start_line == end_line && start_col > end_col {
        // the range is empty, clip it to sensible values
        end_line = start_line;
        end_col = start_col - 1;
    } else if end_col == 0 {
        // end_col = 0 means that we are at the start of a line
        // unfortunately 0 is invalid as column number, therefore
        // we should update the end location to be the end of the
        // previous line
        let mut index = n.end_byte();
        if index > 0 && index <= source.len() {
            index -= 1;
            if source[index] != b'\n' {
                error!("expecting a line break symbol, but none found while correcting end column value");
            }
            end_line -= 1;
            end_col = 1;
            while index > 0 && source[index - 1] != b'\n' {
                index -= 1;
                end_col += 1;
            }
        } else {
            error!(
                "cannot correct end column value: end_byte index {} is not in range [1,{}]",
                index,
                source.len()
            );
        }
    }
    TrapEntry::Located(vec![
        Arg::Label(label),
        Arg::String(fp.to_owned()),
        Arg::Int(start_line),
        Arg::Int(start_col),
        Arg::Int(end_line),
        Arg::Int(end_col),
    ])
}

fn traverse(tree: &Tree, visitor: &mut Visitor) {
    let cursor = &mut tree.walk();
    visitor.enter_node(cursor.node());
    let mut recurse = true;
    loop {
        if recurse && cursor.goto_first_child() {
            recurse = visitor.enter_node(cursor.node());
        } else {
            visitor.leave_node(cursor.field_name(), cursor.node());

            if cursor.goto_next_sibling() {
                recurse = visitor.enter_node(cursor.node());
            } else if cursor.goto_parent() {
                recurse = false;
            } else {
                break;
            }
        }
    }
}

pub struct Program(Vec<TrapEntry>);

impl fmt::Display for Program {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut text = String::new();
        for trap_entry in &self.0 {
            text.push_str(&format!("{}\n", trap_entry));
        }
        write!(f, "{}", text)
    }
}

enum TrapEntry {
    // @id = *@
    New(Label),
    // @node_def(self, arg?, location)@
    Definition(String, Label, Vec<Arg>, Label),
    // @node_child(self, index, parent)@
    ChildOf(String, Label, String, Option<Index>, Label),
    // @location(loc, path, r1, c1, r2, c2)
    Located(Vec<Arg>),
    Comment(String),
}
impl fmt::Display for TrapEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            TrapEntry::New(id) => write!(f, "{} = *", id),
            TrapEntry::Definition(n, id, args, loc) => {
                let mut args_str = String::new();
                for arg in args {
                    args_str.push_str(&format!("{}, ", arg));
                }
                write!(
                    f,
                    "{}({}, {}{})",
                    escape_name(&format!("{}_def", &n)),
                    id,
                    args_str,
                    loc
                )
            }
            TrapEntry::ChildOf(pname, id, fname, idx, p) => match idx {
                Some(idx) => write!(
                    f,
                    "{}({}, {}, {})",
                    escape_name(&format!("{}_{}", &pname, &fname)),
                    id,
                    idx,
                    p
                ),
                None => write!(
                    f,
                    "{}({}, {})",
                    escape_name(&format!("{}_{}", &pname, &fname)),
                    id,
                    p
                ),
            },
            TrapEntry::Located(args) => write!(
                f,
                "location({}, {}, {}, {}, {}, {})",
                args.get(0).unwrap(),
                args.get(1).unwrap(),
                args.get(2).unwrap(),
                args.get(3).unwrap(),
                args.get(4).unwrap(),
                args.get(5).unwrap(),
            ),
            TrapEntry::Comment(line) => write!(f, "// {}", line),
        }
    }
}

#[derive(Debug, Copy, Clone)]
enum Label {
    // Identifiers of the form #0, #1...
    Normal(i32), // #0, #1, etc.
    // Location identifiers of the form #0_loc, #1_loc...
    Location(i32), // #0_loc, #1_loc, etc.
}

impl fmt::Display for Label {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Label::Normal(x) => write!(f, "#{}", x),
            Label::Location(x) => write!(f, "#{}_loc", x),
        }
    }
}

// Numeric indices.
#[derive(Debug, Copy, Clone)]
struct Index(usize);

impl fmt::Display for Index {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

// Some untyped argument to a TrapEntry.
#[derive(Debug)]
enum Arg {
    Label(Label),
    Int(usize),
    String(String),
}

impl fmt::Display for Arg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Arg::Label(x) => write!(f, "{}", x),
            Arg::Int(x) => write!(f, "{}", x),
            Arg::String(x) => write!(f, "\"{}\"", x.replace("\"", "\"\"")),
        }
    }
}
<commit_msg>Add more info to error message<commit_after>use node_types::{escape_name, node_type_name, Entry, Field, Storage, TypeName};
use std::collections::BTreeMap as Map;
use std::collections::BTreeSet as Set;
use std::fmt;
use std::path::Path;
use tracing::{error, info, span, Level};
use tree_sitter::{Language, Node, Parser, Tree};

pub struct Extractor {
    pub parser: Parser,
    pub schema: Vec<Entry>,
}

pub fn create(language: Language, schema: Vec<Entry>) -> Extractor {
    let mut parser = Parser::new();
    parser.set_language(language).unwrap();

    Extractor { parser, schema }
}
impl Extractor {
    pub fn extract<'a>(&'a mut self, path: &Path) -> std::io::Result<Program> {
        let span = span!(
            Level::TRACE,
            "extract",
            file = %path.display()
        );

        let _enter = span.enter();

        info!("extracting: {}", path.display());

        let source = std::fs::read(&path)?;
        let tree = &self
            .parser
            .parse(&source, None)
            .expect("Failed to parse file");
        let mut visitor = Visitor {
            source: &source,
            trap_output: vec![TrapEntry::Comment(format!(
                "Auto-generated TRAP file for {}",
                path.display()
            ))],
            counter: -1,
            // TODO: should we handle path strings that are not valid UTF8 better?
            path: format!("{}", path.display()),
            stack: Vec::new(),
            tables: build_schema_lookup(&self.schema),
            union_types: build_union_type_lookup(&self.schema),
        };
        traverse(&tree, &mut visitor);

        &self.parser.reset();
        Ok(Program(visitor.trap_output))
    }
}

fn build_schema_lookup<'a>(schema: &'a Vec<Entry>) -> Map<&'a TypeName, &'a Entry> {
    let mut map = std::collections::BTreeMap::new();
    for entry in schema {
        if let Entry::Table { type_name, .. } = entry {
            map.insert(type_name, entry);
        }
    }
    map
}

fn build_union_type_lookup<'a>(schema: &'a Vec<Entry>) -> Map<&'a TypeName, &'a Set<TypeName>> {
    let mut union_types = std::collections::BTreeMap::new();
    for entry in schema {
        if let Entry::Union { type_name, members } = entry {
            union_types.insert(type_name, members);
        }
    }
    union_types
}

struct Visitor<'a> {
    /// The file path of the source code (as string)
    path: String,
    /// The source code as a UTF-8 byte array
    source: &'a Vec<u8>,
    /// The accumulated trap entries
    trap_output: Vec<TrapEntry>,
    /// A counter for generating fresh labels
    counter: i32,
    /// A lookup table from type name to dbscheme table entries
    tables: Map<&'a TypeName, &'a Entry>,
    /// A lookup table for union types mapping a type name to its direct members
    union_types: Map<&'a TypeName, &'a Set<TypeName>>,
    /// A stack for gathering information from hild nodes. Whenever a node is entered
    /// an empty list is pushed. All children append their data (field name, label, type) to
    /// the the list. When the visitor leaves a node the list containing the child data is popped
    /// from the stack and matched against the dbscheme for the node. If the expectations are met
    /// the corresponding row definitions are added to the trap_output.
    stack: Vec<Vec<(Option<&'static str>, Label, TypeName)>>,
}

impl Visitor<'_> {
    fn enter_node(&mut self, node: Node) -> bool {
        if node.is_error() {
            error!("{}:{}: parse error", &self.path, node.start_position().row);
            return false;
        }
        if node.is_missing() {
            error!(
                "{}:{}: parse error: expecting '{}'",
                &self.path,
                node.start_position().row,
                node.kind()
            );
            return false;
        }

        if node.is_extra() {
            return false;
        }

        self.stack.push(Vec::new());
        return true;
    }

    fn leave_node(&mut self, field_name: Option<&'static str>, node: Node) {
        if node.is_extra() || node.is_error() || node.is_missing() {
            return;
        }
        let child_nodes = self.stack.pop().expect("Vistor: empty stack");
        let table = self.tables.get(&TypeName {
            kind: node.kind().to_owned(),
            named: node.is_named(),
        });
        if let Some(Entry::Table { fields, .. }) = table {
            self.counter += 1;
            let id = Label::Normal(self.counter);
            let loc = Label::Location(self.counter);
            self.trap_output.push(TrapEntry::New(id));
            self.trap_output.push(TrapEntry::New(loc));
            self.trap_output
                .push(location_for(&self.source, &self.path, loc, node));
            let table_name = node_type_name(node.kind(), node.is_named());
            let args: Option<Vec<Arg>>;
            if fields.is_empty() {
                args = Some(vec![sliced_source_arg(self.source, node)]);
            } else {
                args = self.complex_node(&node, fields, child_nodes, id);
            }
            if let Some(args) = args {
                self.trap_output
                    .push(TrapEntry::Definition(table_name, id, args, loc));
            }
            if let Some(parent) = self.stack.last_mut() {
                parent.push((
                    field_name,
                    id,
                    TypeName {
                        kind: node.kind().to_owned(),
                        named: node.is_named(),
                    },
                ))
            };
        } else {
            error!(
                "{}:{}: unknown table type: '{}'",
                &self.path,
                node.start_position().row,
                node.kind()
            );
        }
    }
    fn complex_node(
        &mut self,
        node: &Node,
        fields: &Vec<Field>,
        child_nodes: Vec<(Option<&str>, Label, TypeName)>,
        parent_id: Label,
    ) -> Option<Vec<Arg>> {
        let mut map: Map<&Option<String>, (&Field, Vec<Label>)> = std::collections::BTreeMap::new();
        for field in fields {
            map.insert(&field.name, (field, Vec::new()));
        }
        for (child_field, child_id, child_type) in child_nodes {
            if let Some((field, values)) = map.get_mut(&child_field.map(|x| x.to_owned())) {
                //TODO: handle error and missing nodes
                if self.type_matches(&child_type, &field.types) {
                    values.push(child_id);
                } else if field.name.is_some() {
                    error!(
                        "{}:{}: type mismatch for field {}::{} with type {:?} != {:?}",
                        &self.path,
                        node.start_position().row,
                        node.kind(),
                        child_field.unwrap_or("child"),
                        child_type,
                        field.types
                    )
                }
            } else {
                if child_field.is_some() || child_type.named {
                    error!(
                        "{}:{}: value for unknown field: {}::{} and type {:?}",
                        &self.path,
                        node.start_position().row,
                        node.kind(),
                        &child_field.unwrap_or("child"),
                        &child_type
                    );
                }
            }
        }
        let mut args = Vec::new();
        let mut is_valid = true;
        for field in fields {
            let child_ids = &map.get(&field.name).unwrap().1;
            match &field.storage {
                Storage::Column => {
                    if child_ids.len() == 1 {
                        args.push(Arg::Label(*child_ids.first().unwrap()));
                    } else {
                        is_valid = false;
                        error!(
                            "{}:{}: {} for field: {}::{}",
                            &self.path,
                            node.start_position().row,
                            if child_ids.is_empty() {
                                "missing value"
                            } else {
                                "too many values"
                            },
                            node.kind(),
                            &field.get_name()
                        )
                    }
                }
                Storage::Table(has_index) => {
                    for (index, child_id) in child_ids.iter().enumerate() {
                        if !*has_index && index > 0 {
                            error!(
                                "{}:{}: too many values for field: {}::{}",
                                &self.path,
                                node.start_position().row,
                                node.kind(),
                                &field.get_name()
                            );
                            break;
                        }
                        self.trap_output.push(TrapEntry::ChildOf(
                            node_type_name(&field.parent.kind, field.parent.named),
                            parent_id,
                            field.get_name(),
                            if *has_index { Some(Index(index)) } else { None },
                            *child_id,
                        ));
                    }
                }
            }
        }
        if is_valid {
            Some(args)
        } else {
            None
        }
    }
    fn type_matches(&self, tp: &TypeName, types: &Set<TypeName>) -> bool {
        if types.contains(tp) {
            return true;
        }
        for other in types.iter() {
            if let Some(x) = self.union_types.get(other) {
                if self.type_matches(tp, x) {
                    return true;
                }
            }
        }
        return false;
    }
}

// Emit a slice of a source file as an Arg.
fn sliced_source_arg(source: &Vec<u8>, n: Node) -> Arg {
    let range = n.byte_range();
    Arg::String(String::from(
        std::str::from_utf8(&source[range.start..range.end]).expect("Failed to decode string"),
    ))
}

// Emit a 'Located' TrapEntry for the provided node, appropriately calibrated.
fn location_for<'a>(source: &Vec<u8>, fp: &String, label: Label, n: Node) -> TrapEntry {
    // Tree-sitter row, column values are 0-based while CodeQL starts
    // counting at 1. In addition Tree-sitter's row and column for the
    // end position are exclusive while CodeQL's end positions are inclusive.
    // This means that all values should be incremented by 1 and in addition the
    // end position needs to be shift 1 to the left. In most cases this means
    // simply incrementing all values except the end column except in cases where
    // the end column is 0 (start of a line). In such cases the end position must be
    // set to the end of the previous line.
    let start_line = n.start_position().row + 1;
    let start_col = n.start_position().column + 1;
    let mut end_line = n.end_position().row + 1;
    let mut end_col = n.end_position().column;
    if start_line > end_line || start_line == end_line && start_col > end_col {
        // the range is empty, clip it to sensible values
        end_line = start_line;
        end_col = start_col - 1;
    } else if end_col == 0 {
        // end_col = 0 means that we are at the start of a line
        // unfortunately 0 is invalid as column number, therefore
        // we should update the end location to be the end of the
        // previous line
        let mut index = n.end_byte();
        if index > 0 && index <= source.len() {
            index -= 1;
            if source[index] != b'\n' {
                error!("expecting a line break symbol, but none found while correcting end column value");
            }
            end_line -= 1;
            end_col = 1;
            while index > 0 && source[index - 1] != b'\n' {
                index -= 1;
                end_col += 1;
            }
        } else {
            error!(
                "cannot correct end column value: end_byte index {} is not in range [1,{}]",
                index,
                source.len()
            );
        }
    }
    TrapEntry::Located(vec![
        Arg::Label(label),
        Arg::String(fp.to_owned()),
        Arg::Int(start_line),
        Arg::Int(start_col),
        Arg::Int(end_line),
        Arg::Int(end_col),
    ])
}

fn traverse(tree: &Tree, visitor: &mut Visitor) {
    let cursor = &mut tree.walk();
    visitor.enter_node(cursor.node());
    let mut recurse = true;
    loop {
        if recurse && cursor.goto_first_child() {
            recurse = visitor.enter_node(cursor.node());
        } else {
            visitor.leave_node(cursor.field_name(), cursor.node());

            if cursor.goto_next_sibling() {
                recurse = visitor.enter_node(cursor.node());
            } else if cursor.goto_parent() {
                recurse = false;
            } else {
                break;
            }
        }
    }
}

pub struct Program(Vec<TrapEntry>);

impl fmt::Display for Program {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut text = String::new();
        for trap_entry in &self.0 {
            text.push_str(&format!("{}\n", trap_entry));
        }
        write!(f, "{}", text)
    }
}

enum TrapEntry {
    // @id = *@
    New(Label),
    // @node_def(self, arg?, location)@
    Definition(String, Label, Vec<Arg>, Label),
    // @node_child(self, index, parent)@
    ChildOf(String, Label, String, Option<Index>, Label),
    // @location(loc, path, r1, c1, r2, c2)
    Located(Vec<Arg>),
    Comment(String),
}
impl fmt::Display for TrapEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            TrapEntry::New(id) => write!(f, "{} = *", id),
            TrapEntry::Definition(n, id, args, loc) => {
                let mut args_str = String::new();
                for arg in args {
                    args_str.push_str(&format!("{}, ", arg));
                }
                write!(
                    f,
                    "{}({}, {}{})",
                    escape_name(&format!("{}_def", &n)),
                    id,
                    args_str,
                    loc
                )
            }
            TrapEntry::ChildOf(pname, id, fname, idx, p) => match idx {
                Some(idx) => write!(
                    f,
                    "{}({}, {}, {})",
                    escape_name(&format!("{}_{}", &pname, &fname)),
                    id,
                    idx,
                    p
                ),
                None => write!(
                    f,
                    "{}({}, {})",
                    escape_name(&format!("{}_{}", &pname, &fname)),
                    id,
                    p
                ),
            },
            TrapEntry::Located(args) => write!(
                f,
                "location({}, {}, {}, {}, {}, {})",
                args.get(0).unwrap(),
                args.get(1).unwrap(),
                args.get(2).unwrap(),
                args.get(3).unwrap(),
                args.get(4).unwrap(),
                args.get(5).unwrap(),
            ),
            TrapEntry::Comment(line) => write!(f, "// {}", line),
        }
    }
}

#[derive(Debug, Copy, Clone)]
enum Label {
    // Identifiers of the form #0, #1...
    Normal(i32), // #0, #1, etc.
    // Location identifiers of the form #0_loc, #1_loc...
    Location(i32), // #0_loc, #1_loc, etc.
}

impl fmt::Display for Label {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Label::Normal(x) => write!(f, "#{}", x),
            Label::Location(x) => write!(f, "#{}_loc", x),
        }
    }
}

// Numeric indices.
#[derive(Debug, Copy, Clone)]
struct Index(usize);

impl fmt::Display for Index {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

// Some untyped argument to a TrapEntry.
#[derive(Debug)]
enum Arg {
    Label(Label),
    Int(usize),
    String(String),
}

impl fmt::Display for Arg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Arg::Label(x) => write!(f, "{}", x),
            Arg::Int(x) => write!(f, "{}", x),
            Arg::String(x) => write!(f, "\"{}\"", x.replace("\"", "\"\"")),
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std;
use libc::c_char;
use std::ffi::CStr;

use std::io::Write;
use std::io::stdout;

use nom::*;

use tls_parser::tls::{TlsMessage,TlsMessageHandshake,tls_parser_many};
use tls_parser::tls_ciphers::TlsCipherSuite;
use tls_parser::tls_extensions::parse_tls_extensions;
use der_parser::der::parse_der;

pub struct TlsParserState<'a> {
    pub o: Option<&'a[u8]>,

    cipher: u16,
}

impl<'a> TlsParserState<'a> {
    pub fn new(i: &'a[u8]) -> TlsParserState<'a> {
        TlsParserState{o:Some(i),cipher:0}
    }

    fn send(&self, value: i32) -> bool {
        debug!("=============================================================");
        debug!("inner send: {}", value);
        debug!("o: {:?}", self.o);
        debug!("cipher: {:?}", self.cipher);
        debug!("=============================================================");
        let _ = stdout().flush();
        true
    }
}

impl<'a> Drop for TlsParserState<'a> {
    fn drop(&mut self) {
        debug!("DROP");
    }
}

#[no_mangle]
pub extern "C" fn rusticata_new_tls_parser_state<'a>() -> Box<TlsParserState<'a>> {
    Box::new(TlsParserState::new(b"blah"))
}

#[no_mangle]
pub extern fn rusticata_free_tls_parser_state<'a>(_: Box<TlsParserState<'a>>)
{
    debug!("rusticata_free_tls_parser_state()");
}

#[no_mangle]
pub extern fn rusticata_use_tls_parser_state<'a>(this: &TlsParserState<'a>, value: i32) -> bool
{
    debug!("rusticata_use_tls_parser_state({:?})", value);
    this.send(value)
}

#[no_mangle]
pub extern fn rusticata_tls_get_cipher<'a>(this: &TlsParserState<'a>) -> u32
{
    this.cipher as u32
}

#[no_mangle]
pub extern fn rusticata_tls_cipher_of_string(value: *const c_char) -> u32
{
    let c_str = unsafe { CStr::from_ptr(value) };
    let s = c_str.to_str().unwrap();
    match TlsCipherSuite::from_name(s) {
        Some(c) => c.id as u32,
        None    => 0,
    }
}

#[no_mangle]
pub extern "C" fn rusticata_probe_tls(input: *const c_char, input_len: u32, offset: u32) -> i32 {
    return 0;
}

#[no_mangle]
pub extern "C" fn rusticata_parse_der(value: *const c_char, len: u32) -> i32 {
    debug!("[rust] rusticata_parse_der");

    let data_len = len as usize;
    let data : &[u8] = unsafe { std::slice::from_raw_parts(value as *mut u8, data_len) };

    let d = parse_der(data);
    debug!("d: {:?}", d);

    0
}

#[no_mangle]
pub extern "C" fn rusticata_tls_decode<'a>(direction: u8, value: *const c_char, len: u32, this: &'a mut TlsParserState<'a>) -> &'a mut TlsParserState<'a> {
    debug!("[rust] suri_tls_decode");

    let data_len = len as usize;
    let data : &[u8] = unsafe { std::slice::from_raw_parts(value as *mut u8, data_len) };

    debug!("  direction: {}", direction);
    debug!("  len: {}", data_len);
    debug!("  data: {:?}", data);

    let d = tls_parser_many(data);
    debug!("d: {:?}", d);

    // XXX match d with nom::IResult::Done, check if ServerHello, and print selected cipher
    match d {
        IResult::Done(rem,p) => {
            debug!("TLS parser successful {} element(s)", p.len());
            for ref record in &p {
                debug!("{:?}", record);
                match record.msg {
                    TlsMessage::Handshake(ref m) => {
                        match *m {
                            TlsMessageHandshake::ClientHello(ref content) => {
                                let blah = parse_tls_extensions(content.ext);
                                debug!("ext {:?}", blah);
                            },
                            TlsMessageHandshake::ServerHello(ref content) => {
                                this.cipher = content.cipher;
                                match TlsCipherSuite::from_id(content.cipher) {
                                    Some(c) => debug!("Selected cipher: {:?}", c),
                                    _ => warn!("Unknown cipher 0x{:x}", content.cipher),
                                };
                                let blah = parse_tls_extensions(content.ext);
                                debug!("extensions: {:?}", blah);
                            },
                            _ => (),
                        }
                    },
                    TlsMessage::Heartbeat(ref d) => {
                        if d.payload_len as usize > d.payload.len() {
                            warn!("Heartbeat message with incorrect length {}. Heartbleed attempt ?",d.payload.len());
                        }
                    },
                    _ => (),
                }
            }
            if rem.len() > 0 { warn!("** unparsed ** {:?}",rem); };
        },
        IResult::Error(e) => error!("TLS parser reported an error: {:?}", e),
        IResult::Incomplete(e) => error!("TLS parser reported incomplete input: {:?}", e),
    };

    this
}
<commit_msg>Implement simple probe function<commit_after>extern crate libc;

use std;
use libc::c_char;
use std::ffi::CStr;

use std::io::Write;
use std::io::stdout;

use nom::*;

use tls_parser::tls::{TlsMessage,TlsMessageHandshake,tls_parser_many};
use tls_parser::tls_ciphers::TlsCipherSuite;
use tls_parser::tls_extensions::parse_tls_extensions;
use der_parser::der::parse_der;

pub struct TlsParserState<'a> {
    pub o: Option<&'a[u8]>,

    cipher: u16,
}

impl<'a> TlsParserState<'a> {
    pub fn new(i: &'a[u8]) -> TlsParserState<'a> {
        TlsParserState{o:Some(i),cipher:0}
    }

    fn send(&self, value: i32) -> bool {
        debug!("=============================================================");
        debug!("inner send: {}", value);
        debug!("o: {:?}", self.o);
        debug!("cipher: {:?}", self.cipher);
        debug!("=============================================================");
        let _ = stdout().flush();
        true
    }
}

impl<'a> Drop for TlsParserState<'a> {
    fn drop(&mut self) {
        debug!("DROP");
    }
}

#[no_mangle]
pub extern "C" fn rusticata_new_tls_parser_state<'a>() -> Box<TlsParserState<'a>> {
    Box::new(TlsParserState::new(b"blah"))
}

#[no_mangle]
pub extern fn rusticata_free_tls_parser_state<'a>(_: Box<TlsParserState<'a>>)
{
    debug!("rusticata_free_tls_parser_state()");
}

#[no_mangle]
pub extern fn rusticata_use_tls_parser_state<'a>(this: &TlsParserState<'a>, value: i32) -> bool
{
    debug!("rusticata_use_tls_parser_state({:?})", value);
    this.send(value)
}

#[no_mangle]
pub extern fn rusticata_tls_get_cipher<'a>(this: &TlsParserState<'a>) -> u32
{
    this.cipher as u32
}

#[no_mangle]
pub extern fn rusticata_tls_cipher_of_string(value: *const c_char) -> u32
{
    let c_str = unsafe { CStr::from_ptr(value) };
    let s = c_str.to_str().unwrap();
    match TlsCipherSuite::from_name(s) {
        Some(c) => c.id as u32,
        None    => 0,
    }
}

#[no_mangle]
pub extern "C" fn rusticata_probe_tls(input: *const c_char, input_len: u32, _offset: *const c_char) -> u32 {
    let data_len = input_len as usize;
    let data : &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, data_len) };

    if data.len() > 2 {
        // first byte is record type (between 0x14 and 0x17, 0x16 is handhake)
        // second is TLS version major (0x3)
        // third is TLS version minor (0x0 for SSLv3, 0x1 for TLSv1.0, etc.)
        match (data[0],data[1],data[2]) {
            (0x14...0x17,0x03,0...3) => return 1,
            _ => (),
        };
    };

    return 0;
}

#[no_mangle]
pub extern "C" fn rusticata_parse_der(value: *const c_char, len: u32) -> i32 {
    debug!("[rust] rusticata_parse_der");

    let data_len = len as usize;
    let data : &[u8] = unsafe { std::slice::from_raw_parts(value as *mut u8, data_len) };

    let d = parse_der(data);
    debug!("d: {:?}", d);

    0
}

#[no_mangle]
pub extern "C" fn rusticata_tls_decode<'a>(direction: u8, value: *const c_char, len: u32, this: &'a mut TlsParserState<'a>) -> &'a mut TlsParserState<'a> {
    debug!("[rust] suri_tls_decode");

    let data_len = len as usize;
    let data : &[u8] = unsafe { std::slice::from_raw_parts(value as *mut u8, data_len) };

    debug!("  direction: {}", direction);
    debug!("  len: {}", data_len);
    debug!("  data: {:?}", data);

    let d = tls_parser_many(data);
    debug!("d: {:?}", d);

    // XXX match d with nom::IResult::Done, check if ServerHello, and print selected cipher
    match d {
        IResult::Done(rem,p) => {
            debug!("TLS parser successful {} element(s)", p.len());
            for ref record in &p {
                debug!("{:?}", record);
                match record.msg {
                    TlsMessage::Handshake(ref m) => {
                        match *m {
                            TlsMessageHandshake::ClientHello(ref content) => {
                                let blah = parse_tls_extensions(content.ext);
                                debug!("ext {:?}", blah);
                            },
                            TlsMessageHandshake::ServerHello(ref content) => {
                                this.cipher = content.cipher;
                                match TlsCipherSuite::from_id(content.cipher) {
                                    Some(c) => debug!("Selected cipher: {:?}", c),
                                    _ => warn!("Unknown cipher 0x{:x}", content.cipher),
                                };
                                let blah = parse_tls_extensions(content.ext);
                                debug!("extensions: {:?}", blah);
                            },
                            _ => (),
                        }
                    },
                    TlsMessage::Heartbeat(ref d) => {
                        if d.payload_len as usize > d.payload.len() {
                            warn!("Heartbeat message with incorrect length {}. Heartbleed attempt ?",d.payload.len());
                        }
                    },
                    _ => (),
                }
            }
            if rem.len() > 0 { warn!("** unparsed ** {:?}",rem); };
        },
        IResult::Error(e) => error!("TLS parser reported an error: {:?}", e),
        IResult::Incomplete(e) => error!("TLS parser reported incomplete input: {:?}", e),
    };

    this
}
<|endoftext|>


<commit_before>extern crate proxer;
extern crate pretty_env_logger;

use proxer::Client;
use proxer::PageableEndpoint;
use proxer::parameter;
use std::ops::Add;
use proxer::Endpoint;
use proxer::api;

fn main()
{
	pretty_env_logger::init().unwrap();

	get_comments();
	get_fullentry();
}

fn get_fullentry()
{
	let prxr = Client::with_env_key("PROXER_API_KEY").unwrap();

	let req = parameter::InfoGetFullEntry { id: 53 };

	let res = prxr.execute(req).unwrap();

	eprintln!("medium: {}", res.medium);
	eprintln!("count: {}", res.count);
}

fn get_comments()
{
	let prxr = Client::with_env_key("PROXER_API_KEY").unwrap();

	let req = parameter::InfoGetComments {
		id: 53,
		p: None,
		limit: Some(100),
		sort: None,
	};

	let pager = req.pager(prxr);

	let mut counter = 0;

	for comment in pager {
		counter = counter.add(1);
		let comment = comment.unwrap();

		println!("{:5}: {}", counter, comment.username);
	}
}
<commit_msg>make test program running<commit_after>extern crate proxer;
extern crate pretty_env_logger;

use proxer::Client;
use proxer::PageableEndpoint;
use std::ops::Add;
use proxer::Endpoint;
use proxer::api;

fn main()
{
	pretty_env_logger::init().unwrap();

	get_comments();
	get_fullentry();
}

fn get_fullentry()
{
	let prxr = Client::with_env_key("PROXER_API_KEY").unwrap();

	let req = api::info::GetFullEntry { id: 53 };

	let res = prxr.execute(req).unwrap();

	eprintln!("medium: {}", res.medium);;
}

fn get_comments()
{
	let prxr = Client::with_env_key("PROXER_API_KEY").unwrap();

	let req = api::info::GetComments {
		id: 53,
		p: None,
		limit: Some(100),
		sort: None,
	};

	let pager = req.pager(prxr);

	let mut counter = 0;

	for comment in pager {
		counter = counter.add(1);
		let comment = comment.unwrap();

		println!("{:5}: {}", counter, comment.username);
	}
}
<|endoftext|>


<commit_before>extern crate glium;
extern crate gltile;
extern crate looper;

use glium::DisplayBuild;

fn main() {
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(1536, 1024)
        .build_glium()
        .unwrap();

    let mut renderer = gltile::Renderer::new(&display, 16, "assets/tileset.png");

    let tile = {
        let mut tile = gltile::Tile::new();
        tile.fg = *gltile::colors::YELLOW;
        tile.pix = gltile::Pix::Dood;
        tile
    };

    renderer.set(gltile::ScreenTile2D::new(5, 5), tile);

    looper::Looper::new(60.0).run(|| {
        renderer.render();
        for ev in display.poll_events() {
            match ev {
                glium::glutin::Event::Closed => return looper::Action::Stop,
                _ => (),
            }
        }
        looper::Action::Continue
    })
}
<commit_msg>chore(examples): update dood example<commit_after>extern crate glium;
extern crate gltile;
extern crate looper;

use glium::DisplayBuild;

fn main() {
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(1536, 1024)
        .build_glium()
        .unwrap();

    let mut renderer = gltile::Renderer::new(&display, 16, "assets/tileset.png");

    let tile = {
        let mut tile = gltile::Tile::new();
        tile.fg = *gltile::colors::YELLOW;
        tile.pix = gltile::Pix::Dood;
        tile
    };

    renderer.set(gltile::units::ScreenTile2D::new(5, 5), tile);

    let render = || {
        renderer.render();
        looper::Action::Continue
    };

    let update = || {
        for ev in display.poll_events() {
            match ev {
                glium::glutin::Event::Closed => return looper::Action::Stop,
                _ => (),
            }
        }
        looper::Action::Continue
    };

    looper::Looper::new(60.0).run(render, update);
}
<|endoftext|>


<commit_before>extern crate mio;
extern crate nix;
extern crate coroutine;
extern crate mioco;

use mio::*;
use mio::tcp::*;
use mio::util::Slab;
use std::io;

use std::net::SocketAddr;
use std::str::FromStr;

const SERVER: Token = Token(0);
const CONN_TOKEN_START : Token = Token(1);
const CONNS_MAX : usize = 256;
const DEFAULT_LISTEN_ADDR : &'static str = "127.0.0.1:5555";

fn listend_addr() -> SocketAddr {
    FromStr::from_str(DEFAULT_LISTEN_ADDR).unwrap()
}

struct Server {
    sock: TcpListener,
    conns: Slab<mioco::Coroutine>,
}

impl Server {
    fn new(addr : SocketAddr) -> io::Result<(Server, EventLoop<Server>)> {

        let sock = try!(TcpSocket::v4());

        try!(sock.set_reuseaddr(true));
        try!(sock.bind(&addr));

        let sock = try!(sock.listen(1024));
        let config = EventLoopConfig {
            io_poll_timeout_ms: 1,
            notify_capacity: 4_096,
            messages_per_tick: 256,
            timer_tick_ms: 1,
            timer_wheel_size: 1_024,
            timer_capacity: 65_536,
        };
        let mut ev_loop : EventLoop<Server> = try!(EventLoop::configured(config));

        try!(ev_loop.register_opt(&sock, SERVER, Interest::readable(), PollOpt::edge()));

        Ok((Server {
            sock: sock,
            conns: Slab::new_starting_at(CONN_TOKEN_START, CONNS_MAX),
        }, ev_loop))
    }

    fn accept(&mut self, event_loop: &mut EventLoop<Server>) -> io::Result<()> {

        use std::os::unix::io::AsRawFd;
        use nix::sys::socket;
        loop {
            let sock = match try!(self.sock.accept()) {
                None => break,
                Some(sock) => sock,
            };

            // Don't buffer output in TCP - kills latency sensitive benchmarks
            try!(socket::setsockopt(
                    sock.as_raw_fd(), socket::SockLevel::Tcp, socket::sockopt::TcpNoDelay, &true
                    ).map_err(|e| io::Error::from_raw_os_error(e.errno() as i32)));

            let f = move |io : &mut mioco::IOHandle| {
                use std::io::{Read, Write};
                let mut buf = [0u8; 1024 * 16];
                loop {

                    let res = io.read(&mut buf);

                    match res {
                        Err(_) => return,
                        Ok(0) => /* EOF */ return,
                        Ok(size) => {
                            let mut write_i = 0;
                            loop {
                                if write_i == size {
                                    break;
                                }

                                match io.write(&mut buf[write_i..size]) {
                                    Ok(written) => write_i += written,
                                    Err(_) => return,
                                }
                            }
                        }
                    }
                }
            };
            let _tok = self.conns.create_and_insert(|token| {
                mioco::Coroutine::new(sock, event_loop, token, f)
            });
        }

        Ok(())
    }

    fn conn_handle_finished(&mut self, token : Token, finished : bool) {
        if finished {
            self.conns.remove(token);
        }
    }

    fn conn_readable(&mut self, event_loop: &mut EventLoop<Server>, tok: Token, hint: ReadHint) {
        let finished = {
            let conn = self.conn(tok);
            conn.readable(event_loop, tok, hint);
            conn.is_finished()
        };
        self.conn_handle_finished(tok, finished);
    }

    fn conn_writable(&mut self, event_loop: &mut EventLoop<Server>, tok: Token) {
        let finished = {
            let conn = self.conn(tok);
            conn.writable(event_loop, tok);
            conn.is_finished()
        };
        self.conn_handle_finished(tok, finished);
    }

    fn conn<'a>(&'a mut self, tok: Token) -> &'a mut mioco::Coroutine {
        &mut self.conns[tok]
    }
}

impl Handler for Server {
    type Timeout = usize;
    type Message = ();

    fn readable(&mut self, event_loop: &mut EventLoop<Server>, token: Token, hint: ReadHint) {
        match token {
            SERVER => self.accept(event_loop).ok().expect("accept(event_loop) failed"),
            i => self.conn_readable(event_loop, i, hint),
        };
    }

    fn writable(&mut self, event_loop: &mut EventLoop<Server>, token: Token) {
        match token {
            SERVER => panic!("received writable for token 0"),
            _ => self.conn_writable(event_loop, token),
        };
    }
}

pub fn main() {
    let addr = listend_addr();

    let (mut server, mut ev_loop) = Server::new(addr).ok().expect("Server::new(...) failed");

    // Start the event loop
    println!("Starting tcp echo server on {:?}", server.sock.local_addr().unwrap());
    ev_loop.run(&mut server).unwrap();
}
<commit_msg>Fixes example build<commit_after>extern crate mio;
extern crate nix;
extern crate coroutine;
extern crate mioco;

use mio::*;
use mio::tcp::*;
use mio::util::Slab;
use std::io;

use std::net::SocketAddr;
use std::str::FromStr;

const SERVER: Token = Token(0);
const CONN_TOKEN_START : Token = Token(1);
const CONNS_MAX : usize = 256;
const DEFAULT_LISTEN_ADDR : &'static str = "127.0.0.1:5555";

fn listend_addr() -> SocketAddr {
    FromStr::from_str(DEFAULT_LISTEN_ADDR).unwrap()
}

struct Server {
    sock: TcpListener,
    conns: Slab<mioco::Coroutine>,
}

impl Server {
    fn new(addr : SocketAddr) -> io::Result<(Server, EventLoop<Server>)> {

        let sock = try!(TcpSocket::v4());

        try!(sock.set_reuseaddr(true));
        try!(sock.bind(&addr));

        let sock = try!(sock.listen(1024));
        let config = EventLoopConfig {
            io_poll_timeout_ms: 1,
            notify_capacity: 4_096,
            messages_per_tick: 256,
            timer_tick_ms: 1,
            timer_wheel_size: 1_024,
            timer_capacity: 65_536,
        };
        let mut ev_loop : EventLoop<Server> = try!(EventLoop::configured(config));

        try!(ev_loop.register_opt(&sock, SERVER, Interest::readable(), PollOpt::edge()));

        Ok((Server {
            sock: sock,
            conns: Slab::new_starting_at(CONN_TOKEN_START, CONNS_MAX),
        }, ev_loop))
    }

    fn accept(&mut self, event_loop: &mut EventLoop<Server>) -> io::Result<()> {

        use std::os::unix::io::AsRawFd;
        use nix::sys::socket;
        loop {
            let sock = match try!(self.sock.accept()) {
                None => break,
                Some(sock) => sock,
            };

            // Don't buffer output in TCP - kills latency sensitive benchmarks
            try!(socket::setsockopt(
                    sock.as_raw_fd(), socket::SockLevel::Tcp, socket::sockopt::TcpNoDelay, &true
                    ).map_err(|e| io::Error::from_raw_os_error(e.errno() as i32)));

            let f = move |io : &mut mioco::IOHandle| {
                use std::io::{Read, Write};
                let mut buf = [0u8; 1024 * 16];
                loop {

                    let res = io.read(&mut buf);

                    match res {
                        Err(_) => return,
                        Ok(0) => /* EOF */ return,
                        Ok(size) => {
                            let mut write_i = 0;
                            loop {
                                if write_i == size {
                                    break;
                                }

                                match io.write(&mut buf[write_i..size]) {
                                    Ok(written) => write_i += written,
                                    Err(_) => return,
                                }
                            }
                        }
                    }
                }
            };
            let _tok = self.conns.insert_with(|token| {
                mioco::Coroutine::new(sock, event_loop, token, f)
            });
        }

        Ok(())
    }

    fn conn_handle_finished(&mut self, token : Token, finished : bool) {
        if finished {
            self.conns.remove(token);
        }
    }

    fn conn_readable(&mut self, event_loop: &mut EventLoop<Server>, tok: Token, hint: ReadHint) {
        let finished = {
            let conn = self.conn(tok);
            conn.readable(event_loop, tok, hint);
            conn.is_finished()
        };
        self.conn_handle_finished(tok, finished);
    }

    fn conn_writable(&mut self, event_loop: &mut EventLoop<Server>, tok: Token) {
        let finished = {
            let conn = self.conn(tok);
            conn.writable(event_loop, tok);
            conn.is_finished()
        };
        self.conn_handle_finished(tok, finished);
    }

    fn conn<'a>(&'a mut self, tok: Token) -> &'a mut mioco::Coroutine {
        &mut self.conns[tok]
    }
}

impl Handler for Server {
    type Timeout = usize;
    type Message = ();

    fn readable(&mut self, event_loop: &mut EventLoop<Server>, token: Token, hint: ReadHint) {
        match token {
            SERVER => self.accept(event_loop).ok().expect("accept(event_loop) failed"),
            i => self.conn_readable(event_loop, i, hint),
        };
    }

    fn writable(&mut self, event_loop: &mut EventLoop<Server>, token: Token) {
        match token {
            SERVER => panic!("received writable for token 0"),
            _ => self.conn_writable(event_loop, token),
        };
    }
}

pub fn main() {
    let addr = listend_addr();

    let (mut server, mut ev_loop) = Server::new(addr).ok().expect("Server::new(...) failed");

    // Start the event loop
    println!("Starting tcp echo server on {:?}", server.sock.local_addr().unwrap());
    ev_loop.run(&mut server).unwrap();
}
<|endoftext|>