<commit_before>use std::io::{Write, Result};
use {Class, Function, Type, TypeKind, typescript};
use heck::MixedCase;
use std::collections::BTreeMap;

fn get_hl_type_with_null(ty: &Type) -> String {
    let mut formatted = get_hl_type_without_null(ty);
    if ty.is_nullable {
        formatted.push_str(" | null");
    }
    formatted
}

fn get_hl_type_without_null(ty: &Type) -> String {
    if ty.is_custom {
        match ty.kind {
            TypeKind::Ref => format!("{}Ref", ty.name),
            TypeKind::RefMut => format!("{}RefMut", ty.name),
            TypeKind::Value => ty.name.clone(),
        }
    } else {
        match (ty.kind, ty.name.as_str()) {
            (TypeKind::Ref, "c_char") => "string",
            (TypeKind::Ref, _) | (TypeKind::RefMut, _) => "Buffer",
            (_, t) if !ty.is_custom => {
                match t {
                    "i8" => "number",
                    "i16" => "number",
                    "i32" => "number",
                    "i64" => "number",
                    "u8" => "number",
                    "u16" => "number",
                    "u32" => "number",
                    "u64" => "number",
                    "usize" => "number",
                    "f32" => "number",
                    "f64" => "number",
                    "bool" => "boolean",
                    "()" => "void",
                    "c_char" => "string",
                    "Json" => "any",
                    x => x,
                }
            }
            _ => unreachable!(),
        }.to_string()
    }
}

fn get_ll_type(ty: &Type) -> &str {
    match (ty.kind, ty.name.as_str()) {
        (TypeKind::Ref, "c_char") | (_, "Json") => "'CString'",
        (TypeKind::Ref, _) | (TypeKind::RefMut, _) => "'pointer'",
        (_, t) if !ty.is_custom => {
            match t {
                "i8" => "'int8'",
                "i16" => "'int16'",
                "i32" => "'int32'",
                "i64" => "'int64'",
                "u8" => "'uint8'",
                "u16" => "'uint16'",
                "u32" => "'uint32'",
                "u64" => "'uint64'",
                "usize" => "'size_t'",
                "f32" => "'float'",
                "f64" => "'double'",
                "bool" => "'bool'",
                "()" => "'void'",
                "c_char" => "'char'",
                x => x,
            }
        }
        _ => "'pointer'",
    }
}

fn write_fn<W: Write>(mut writer: W, function: &Function, type_script: bool) -> Result<()> {
    let is_static = function.is_static();
    let has_return_type = function.has_return_type();
    let return_type_with_null = get_hl_type_with_null(&function.output);
    let return_type_without_null = get_hl_type_without_null(&function.output);
    let method = function.method.to_mixed_case();
    let is_json = has_return_type && function.output.name == "Json";

    if !type_script {
        write!(
            writer,
            r#"
    /**"#
        )?;

        for &(ref name, ref ty) in function.inputs.iter().skip(if is_static { 0 } else { 1 }) {
            write!(
                writer,
                r#"
     * @param {{{}}} {}"#,
                get_hl_type_with_null(ty),
                name.to_mixed_case()
            )?;
        }

        if has_return_type {
            write!(
                writer,
                r#"
     * @return {{{}}}"#,
                return_type_with_null
            )?;
        }

        write!(
            writer,
            r#"
     */"#
        )?;
    }

    write!(
        writer,
        r#"
    {}{}("#,
        if is_static { "static " } else { "" },
        method
    )?;

    for (i, &(ref name, ref ty)) in function
        .inputs
        .iter()
        .skip(if is_static { 0 } else { 1 })
        .enumerate()
    {
        if i != 0 {
            write!(writer, ", ")?;
        }
        write!(writer, "{}", name.to_mixed_case())?;
        if type_script {
            write!(writer, ": {}", get_hl_type_with_null(ty))?;
        }
    }

    if type_script && has_return_type {
        write!(
            writer,
            r#"): {} {{
        "#,
            return_type_with_null
        )?;
    } else {
        write!(
            writer,
            r#") {{
        "#
        )?;
    }

    for &(ref name, ref typ) in function.inputs.iter() {
        if typ.is_custom {
            write!(
                writer,
                r#"if (ref.isNull({name}.ptr)) {{
            throw "{name} is disposed";
        }}
        "#,
                name = name.to_mixed_case()
            )?;
        }
    }

    if has_return_type {
        if function.output.is_custom {
            write!(writer, r#"var result = new {}("#, return_type_without_null)?;
        } else {
            write!(writer, "var result = ")?;
        }
    }

    write!(writer, r#"liveSplitCoreNative.{}("#, &function.name)?;

    for (i, &(ref name, ref typ)) in function.inputs.iter().enumerate() {
        if i != 0 {
            write!(writer, ", ")?;
        }
        write!(
            writer,
            "{}",
            if name == "this" {
                "this.ptr".to_string()
            } else if typ.name == "Json" {
                format!("JSON.stringify({})", name.to_mixed_case())
            } else if typ.is_custom {
                format!("{}.ptr", name.to_mixed_case())
            } else {
                name.to_mixed_case()
            }
        )?;
    }

    write!(writer, ")")?;

    if has_return_type && function.output.is_custom {
        write!(writer, r#")"#)?;
    }

    write!(writer, r#";"#)?;

    for &(ref name, ref typ) in function.inputs.iter() {
        if typ.is_custom && typ.kind == TypeKind::Value {
            write!(
                writer,
                r#"
        {}.ptr = ref.NULL;"#,
                name.to_mixed_case()
            )?;
        }
    }

    if has_return_type {
        if function.output.is_nullable && function.output.is_custom {
            write!(
                writer,
                r#"
        if (ref.isNull(result.ptr)) {{
            return null;
        }}"#
            )?;
        }
        if is_json {
            write!(
                writer,
                r#"
        return JSON.parse(result);"#
            )?;
        } else {
            write!(
                writer,
                r#"
        return result;"#
            )?;
        }
    }

    write!(
        writer,
        r#"
    }}"#
    )?;

    Ok(())
}

pub fn write<W: Write>(
    mut writer: W,
    classes: &BTreeMap<String, Class>,
    type_script: bool,
) -> Result<()> {
    if type_script {
        write!(
            writer,
            r#""use strict";
import ffi = require('ffi');
import fs = require('fs');
import ref = require('ref');

{}

var liveSplitCoreNative = ffi.Library('livesplit_core', {{"#,
            typescript::HEADER
        )?;
    } else {
        write!(
            writer,
            "{}",
            r#""use strict";
var ffi = require('ffi');
var fs = require('fs');
var ref = require('ref');

var liveSplitCoreNative = ffi.Library('livesplit_core', {"#
        )?;
    }

    for class in classes.values() {
        for function in class
            .static_fns
            .iter()
            .chain(class.own_fns.iter())
            .chain(class.shared_fns.iter())
            .chain(class.mut_fns.iter())
        {
            write!(
                writer,
                r#"
    '{}': [{}, ["#,
                function.name,
                get_ll_type(&function.output)
            )?;

            for (i, &(_, ref typ)) in function.inputs.iter().enumerate() {
                if i != 0 {
                    write!(writer, ", ")?;
                }
                write!(writer, "{}", get_ll_type(typ))?;
            }

            write!(writer, "]],")?;
        }
    }

    writeln!(
        writer,
        "{}",
        r#"
});"#
    )?;

    for (class_name, class) in classes {
        let class_name_ref = format!("{}Ref", class_name);
        let class_name_ref_mut = format!("{}RefMut", class_name);

        write!(
            writer,
            r#"
{export}class {class} {{"#,
            class = class_name_ref,
            export = if type_script { "export " } else { "" }
        )?;

        if type_script {
            write!(
                writer,
                r#"
    ptr: Buffer;"#
            )?;
        }

        for function in &class.shared_fns {
            write_fn(&mut writer, function, type_script)?;
        }

        if class_name == "SharedTimer" {
            if type_script {
                write!(
                    writer,
                    "{}",
                    r#"
    readWith(action: (timer: TimerRef) => void) {
        this.read().with(function (lock) {
            action(lock.timer());
        });
    }
    writeWith(action: (timer: TimerRefMut) => void) {
        this.write().with(function (lock) {
            action(lock.timer());
        });
    }"#
                )?;
            } else {
                write!(
                    writer,
                    "{}",
                    r#"
    /**
     * @param {function(TimerRef)} action
     */
    readWith(action) {
        this.read().with(function (lock) {
            action(lock.timer());
        });
    }
    /**
     * @param {function(TimerRefMut)} action
     */
    writeWith(action) {
        this.write().with(function (lock) {
            action(lock.timer());
        });
    }"#
                )?;
            }
        }

        if type_script {
            write!(
                writer,
                r#"
    constructor(ptr: Buffer) {{"#
            )?;
        } else {
            write!(
                writer,
                r#"
    /**
     * @param {{Buffer}} ptr
     */
    constructor(ptr) {{"#
            )?;
        }

        write!(
            writer,
            r#"
        this.ptr = ptr;
    }}
}}
{export}class {class} extends {base_class} {{"#,
            class = class_name_ref_mut,
            base_class = class_name_ref,
            export = if type_script {
                r#"
export "#.to_string()
            } else {
                format!(
                    r#"exports.{base_class} = {base_class};

"#,
                    base_class = class_name_ref
                )
            }
        )?;

        for function in &class.mut_fns {
            write_fn(&mut writer, function, type_script)?;
        }

        write!(
            writer,
            r#"
}}
{export}class {class} extends {base_class} {{"#,
            class = class_name,
            base_class = class_name_ref_mut,
            export = if type_script {
                r#"
export "#.to_string()
            } else {
                format!(
                    r#"exports.{base_class} = {base_class};

"#,
                    base_class = class_name_ref_mut
                )
            }
        )?;

        if type_script {
            write!(
                writer,
                r#"
    with(closure: (obj: {class}) => void) {{"#,
                class = class_name
            )?;
        } else {
            write!(
                writer,
                r#"
    /**
     * @param {{function({class})}} closure
     */
    with(closure) {{"#,
                class = class_name
            )?;
        }

        write!(
            writer,
            r#"
        try {{
            closure(this);
        }} finally {{
            this.dispose();
        }}
    }}
    dispose() {{
        if (!ref.isNull(this.ptr)) {{"#
        )?;

        if let Some(function) = class.own_fns.iter().find(|f| f.method == "drop") {
            write!(
                writer,
                r#"
            liveSplitCoreNative.{}(this.ptr);"#,
                function.name
            )?;
        }

        write!(
            writer,
            r#"
            this.ptr = ref.NULL;
        }}
    }}"#
        )?;

        for function in class.static_fns.iter().chain(class.own_fns.iter()) {
            if function.method != "drop" {
                write_fn(&mut writer, function, type_script)?;
            }
        }

        if class_name == "Run" {
            if type_script {
                write!(
                    writer,
                    "{}",
                    r#"
    static parseArray(data: Int8Array): Run {
        var buf = Buffer.from(data.buffer);
        if (data.byteLength !== data.buffer.byteLength) {
            buf = buf.slice(data.byteOffset, data.byteOffset + data.byteLength);
        }
        return Run.parse(buf, buf.byteLength);
    }
    static parseFile(file: any) {
        var data = fs.readFileSync(file);
        return Run.parse(data, data.byteLength);
    }
    static parseString(text: string): Run {
        let data = new Buffer(text);
        return Run.parse(data, data.byteLength);
    }"#
                )?;
            } else {
                write!(
                    writer,
                    "{}",
                    r#"
    /**
     * @param {Int8Array} data
     * @return {Run}
     */
    static parseArray(data) {
        var buf = Buffer.from(data.buffer);
        if (data.byteLength !== data.buffer.byteLength) {
            buf = buf.slice(data.byteOffset, data.byteOffset + data.byteLength);
        }
        return Run.parse(buf, buf.byteLength);
    }
    /**
     * @param {string | Buffer | number} file
     * @return {Run}
     */
    static parseFile(file: any) {
        var data = fs.readFileSync(file);
        return Run.parse(data, data.byteLength);
    }
    /**
     * @param {string} text
     * @return {Run}
     */
    static parseString(text: string): Run {
        let data = new Buffer(text);
        return Run.parse(data, data.byteLength);
    }"#
                )?;
            }
        }

        writeln!(
            writer,
            r#"
}}{export}"#,
            export = if type_script {
                "".to_string()
            } else {
                format!(
                    r#"
exports.{base_class} = {base_class};"#,
                    base_class = class_name
                )
            }
        )?;
    }

    Ok(())
}
<commit_msg>Fix Bugs in Node JavaScript Bindings<commit_after>use std::io::{Write, Result};
use {Class, Function, Type, TypeKind, typescript};
use heck::MixedCase;
use std::collections::BTreeMap;

fn get_hl_type_with_null(ty: &Type) -> String {
    let mut formatted = get_hl_type_without_null(ty);
    if ty.is_nullable {
        formatted.push_str(" | null");
    }
    formatted
}

fn get_hl_type_without_null(ty: &Type) -> String {
    if ty.is_custom {
        match ty.kind {
            TypeKind::Ref => format!("{}Ref", ty.name),
            TypeKind::RefMut => format!("{}RefMut", ty.name),
            TypeKind::Value => ty.name.clone(),
        }
    } else {
        match (ty.kind, ty.name.as_str()) {
            (TypeKind::Ref, "c_char") => "string",
            (TypeKind::Ref, _) | (TypeKind::RefMut, _) => "Buffer",
            (_, t) if !ty.is_custom => {
                match t {
                    "i8" => "number",
                    "i16" => "number",
                    "i32" => "number",
                    "i64" => "number",
                    "u8" => "number",
                    "u16" => "number",
                    "u32" => "number",
                    "u64" => "number",
                    "usize" => "number",
                    "f32" => "number",
                    "f64" => "number",
                    "bool" => "boolean",
                    "()" => "void",
                    "c_char" => "string",
                    "Json" => "any",
                    x => x,
                }
            }
            _ => unreachable!(),
        }.to_string()
    }
}

fn get_ll_type(ty: &Type) -> &str {
    match (ty.kind, ty.name.as_str()) {
        (TypeKind::Ref, "c_char") | (_, "Json") => "'CString'",
        (TypeKind::Ref, _) | (TypeKind::RefMut, _) => "'pointer'",
        (_, t) if !ty.is_custom => {
            match t {
                "i8" => "'int8'",
                "i16" => "'int16'",
                "i32" => "'int32'",
                "i64" => "'int64'",
                "u8" => "'uint8'",
                "u16" => "'uint16'",
                "u32" => "'uint32'",
                "u64" => "'uint64'",
                "usize" => "'size_t'",
                "f32" => "'float'",
                "f64" => "'double'",
                "bool" => "'bool'",
                "()" => "'void'",
                "c_char" => "'char'",
                x => x,
            }
        }
        _ => "'pointer'",
    }
}

fn write_fn<W: Write>(mut writer: W, function: &Function, type_script: bool) -> Result<()> {
    let is_static = function.is_static();
    let has_return_type = function.has_return_type();
    let return_type_with_null = get_hl_type_with_null(&function.output);
    let return_type_without_null = get_hl_type_without_null(&function.output);
    let method = function.method.to_mixed_case();
    let is_json = has_return_type && function.output.name == "Json";

    if !type_script {
        write!(
            writer,
            r#"
    /**"#
        )?;

        for &(ref name, ref ty) in function.inputs.iter().skip(if is_static { 0 } else { 1 }) {
            write!(
                writer,
                r#"
     * @param {{{}}} {}"#,
                get_hl_type_with_null(ty),
                name.to_mixed_case()
            )?;
        }

        if has_return_type {
            write!(
                writer,
                r#"
     * @return {{{}}}"#,
                return_type_with_null
            )?;
        }

        write!(
            writer,
            r#"
     */"#
        )?;
    }

    write!(
        writer,
        r#"
    {}{}("#,
        if is_static { "static " } else { "" },
        method
    )?;

    for (i, &(ref name, ref ty)) in function
        .inputs
        .iter()
        .skip(if is_static { 0 } else { 1 })
        .enumerate()
    {
        if i != 0 {
            write!(writer, ", ")?;
        }
        write!(writer, "{}", name.to_mixed_case())?;
        if type_script {
            write!(writer, ": {}", get_hl_type_with_null(ty))?;
        }
    }

    if type_script && has_return_type {
        write!(
            writer,
            r#"): {} {{
        "#,
            return_type_with_null
        )?;
    } else {
        write!(
            writer,
            r#") {{
        "#
        )?;
    }

    for &(ref name, ref typ) in function.inputs.iter() {
        if typ.is_custom {
            write!(
                writer,
                r#"if (ref.isNull({name}.ptr)) {{
            throw "{name} is disposed";
        }}
        "#,
                name = name.to_mixed_case()
            )?;
        }
    }

    if has_return_type {
        if function.output.is_custom {
            write!(writer, r#"var result = new {}("#, return_type_without_null)?;
        } else {
            write!(writer, "var result = ")?;
        }
    }

    write!(writer, r#"liveSplitCoreNative.{}("#, &function.name)?;

    for (i, &(ref name, ref typ)) in function.inputs.iter().enumerate() {
        if i != 0 {
            write!(writer, ", ")?;
        }
        write!(
            writer,
            "{}",
            if name == "this" {
                "this.ptr".to_string()
            } else if typ.name == "Json" {
                format!("JSON.stringify({})", name.to_mixed_case())
            } else if typ.is_custom {
                format!("{}.ptr", name.to_mixed_case())
            } else {
                name.to_mixed_case()
            }
        )?;
    }

    write!(writer, ")")?;

    if has_return_type && function.output.is_custom {
        write!(writer, r#")"#)?;
    }

    write!(writer, r#";"#)?;

    for &(ref name, ref typ) in function.inputs.iter() {
        if typ.is_custom && typ.kind == TypeKind::Value {
            write!(
                writer,
                r#"
        {}.ptr = ref.NULL;"#,
                name.to_mixed_case()
            )?;
        }
    }

    if has_return_type {
        if function.output.is_nullable && function.output.is_custom {
            write!(
                writer,
                r#"
        if (ref.isNull(result.ptr)) {{
            return null;
        }}"#
            )?;
        }
        if is_json {
            write!(
                writer,
                r#"
        return JSON.parse(result);"#
            )?;
        } else {
            write!(
                writer,
                r#"
        return result;"#
            )?;
        }
    }

    write!(
        writer,
        r#"
    }}"#
    )?;

    Ok(())
}

pub fn write<W: Write>(
    mut writer: W,
    classes: &BTreeMap<String, Class>,
    type_script: bool,
) -> Result<()> {
    if type_script {
        write!(
            writer,
            r#""use strict";
import ffi = require('ffi');
import fs = require('fs');
import ref = require('ref');

{}

var liveSplitCoreNative = ffi.Library('livesplit_core', {{"#,
            typescript::HEADER
        )?;
    } else {
        write!(
            writer,
            "{}",
            r#""use strict";
var ffi = require('ffi');
var fs = require('fs');
var ref = require('ref');

var liveSplitCoreNative = ffi.Library('livesplit_core', {"#
        )?;
    }

    for class in classes.values() {
        for function in class
            .static_fns
            .iter()
            .chain(class.own_fns.iter())
            .chain(class.shared_fns.iter())
            .chain(class.mut_fns.iter())
        {
            write!(
                writer,
                r#"
    '{}': [{}, ["#,
                function.name,
                get_ll_type(&function.output)
            )?;

            for (i, &(_, ref typ)) in function.inputs.iter().enumerate() {
                if i != 0 {
                    write!(writer, ", ")?;
                }
                write!(writer, "{}", get_ll_type(typ))?;
            }

            write!(writer, "]],")?;
        }
    }

    writeln!(
        writer,
        "{}",
        r#"
});"#
    )?;

    for (class_name, class) in classes {
        let class_name_ref = format!("{}Ref", class_name);
        let class_name_ref_mut = format!("{}RefMut", class_name);

        write!(
            writer,
            r#"
{export}class {class} {{"#,
            class = class_name_ref,
            export = if type_script { "export " } else { "" }
        )?;

        if type_script {
            write!(
                writer,
                r#"
    ptr: Buffer;"#
            )?;
        }

        for function in &class.shared_fns {
            write_fn(&mut writer, function, type_script)?;
        }

        if class_name == "SharedTimer" {
            if type_script {
                write!(
                    writer,
                    "{}",
                    r#"
    readWith(action: (timer: TimerRef) => void) {
        this.read().with(function (lock) {
            action(lock.timer());
        });
    }
    writeWith(action: (timer: TimerRefMut) => void) {
        this.write().with(function (lock) {
            action(lock.timer());
        });
    }"#
                )?;
            } else {
                write!(
                    writer,
                    "{}",
                    r#"
    /**
     * @param {function(TimerRef)} action
     */
    readWith(action) {
        this.read().with(function (lock) {
            action(lock.timer());
        });
    }
    /**
     * @param {function(TimerRefMut)} action
     */
    writeWith(action) {
        this.write().with(function (lock) {
            action(lock.timer());
        });
    }"#
                )?;
            }
        }

        if type_script {
            write!(
                writer,
                r#"
    constructor(ptr: Buffer) {{"#
            )?;
        } else {
            write!(
                writer,
                r#"
    /**
     * @param {{Buffer}} ptr
     */
    constructor(ptr) {{"#
            )?;
        }

        write!(
            writer,
            r#"
        this.ptr = ptr;
    }}
}}
{export}class {class} extends {base_class} {{"#,
            class = class_name_ref_mut,
            base_class = class_name_ref,
            export = if type_script {
                r#"
export "#.to_string()
            } else {
                format!(
                    r#"exports.{base_class} = {base_class};

"#,
                    base_class = class_name_ref
                )
            }
        )?;

        for function in &class.mut_fns {
            write_fn(&mut writer, function, type_script)?;
        }

        write!(
            writer,
            r#"
}}
{export}class {class} extends {base_class} {{"#,
            class = class_name,
            base_class = class_name_ref_mut,
            export = if type_script {
                r#"
export "#.to_string()
            } else {
                format!(
                    r#"exports.{base_class} = {base_class};

"#,
                    base_class = class_name_ref_mut
                )
            }
        )?;

        if type_script {
            write!(
                writer,
                r#"
    with(closure: (obj: {class}) => void) {{"#,
                class = class_name
            )?;
        } else {
            write!(
                writer,
                r#"
    /**
     * @param {{function({class})}} closure
     */
    with(closure) {{"#,
                class = class_name
            )?;
        }

        write!(
            writer,
            r#"
        try {{
            closure(this);
        }} finally {{
            this.dispose();
        }}
    }}
    dispose() {{
        if (!ref.isNull(this.ptr)) {{"#
        )?;

        if let Some(function) = class.own_fns.iter().find(|f| f.method == "drop") {
            write!(
                writer,
                r#"
            liveSplitCoreNative.{}(this.ptr);"#,
                function.name
            )?;
        }

        write!(
            writer,
            r#"
            this.ptr = ref.NULL;
        }}
    }}"#
        )?;

        for function in class.static_fns.iter().chain(class.own_fns.iter()) {
            if function.method != "drop" {
                write_fn(&mut writer, function, type_script)?;
            }
        }

        if class_name == "Run" {
            if type_script {
                write!(
                    writer,
                    "{}",
                    r#"
    static parseArray(data: Int8Array): Run {
        var buf = Buffer.from(data.buffer);
        if (data.byteLength !== data.buffer.byteLength) {
            buf = buf.slice(data.byteOffset, data.byteOffset + data.byteLength);
        }
        return Run.parse(buf, buf.byteLength);
    }
    static parseFile(file: any) {
        var data = fs.readFileSync(file);
        return Run.parse(data, data.byteLength);
    }
    static parseString(text: string): Run {
        let data = new Buffer(text);
        return Run.parse(data, data.byteLength);
    }"#
                )?;
            } else {
                write!(
                    writer,
                    "{}",
                    r#"
    /**
     * @param {Int8Array} data
     * @return {Run}
     */
    static parseArray(data) {
        var buf = Buffer.from(data.buffer);
        if (data.byteLength !== data.buffer.byteLength) {
            buf = buf.slice(data.byteOffset, data.byteOffset + data.byteLength);
        }
        return Run.parse(buf, buf.byteLength);
    }
    /**
     * @param {string | Buffer | number} file
     * @return {Run}
     */
    static parseFile(file) {
        var data = fs.readFileSync(file);
        return Run.parse(data, data.byteLength);
    }
    /**
     * @param {string} text
     * @return {Run}
     */
    static parseString(text) {
        let data = new Buffer(text);
        return Run.parse(data, data.byteLength);
    }"#
                )?;
            }
        }

        writeln!(
            writer,
            r#"
}}{export}"#,
            export = if type_script {
                "".to_string()
            } else {
                format!(
                    r#"
exports.{base_class} = {base_class};"#,
                    base_class = class_name
                )
            }
        )?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use io;
use message::*;
use serialize::*;

#[inline]
unsafe fn ptr_sub<T>(p1 : * T, p2 : * T) -> uint {
    let p1Addr : uint = std::cast::transmute(p1);
    let p2Addr : uint = std::cast::transmute(p2);
    return (p1Addr - p2Addr) / std::mem::size_of::<T>();
}

#[inline]
unsafe fn mut_ptr_sub <T>(p1 : *mut T, p2 : *mut T) -> uint {
    let p1Addr : uint = std::cast::transmute(p1);
    let p2Addr : uint = std::cast::transmute(p2);
    return (p1Addr - p2Addr) / std::mem::size_of::<T>();
}

pub struct PackedInputStream<'a, 'b,  R> {
    inner : &'a mut io::BufferedInputStream<'b, R>
}

macro_rules! refresh_buffer(
    ($inner:expr, $size:ident, $inPtr:ident, $inEnd:ident, $out:ident,
     $outBuf:ident, $bufferBegin:ident) => (
        {
            $inner.skip($size);
            let (b, e) = $inner.getReadBuffer();
            $inPtr = b;
            $inEnd = e;
            $size = ptr_sub($inEnd, $inPtr);
            $bufferBegin = b;
            assert!($size > 0);
        }
        );
    )

impl <'a, 'b, R : std::io::Reader> std::io::Reader for PackedInputStream<'a, 'b, R> {
    fn eof(&mut self) -> bool {
        self.inner.eof()
    }

    fn read(&mut self, outBuf: &mut [u8]) -> Option<uint> {
        let len = outBuf.len();

        if (len == 0) { return Some(0); }

        assert!(len % 8 == 0, "PackInputStream reads must be word-aligned");

        unsafe {
            let mut out = outBuf.unsafe_mut_ref(0);
            let outEnd = outBuf.unsafe_mut_ref(len);

            let (mut inPtr, mut inEnd) = self.inner.getReadBuffer();
            let mut bufferBegin = inPtr;
            let mut size = ptr_sub(inEnd, inPtr);
            if size == 0 {
                return Some(0);
            }

            loop {

                let mut tag : u8;

                assert!(mut_ptr_sub(out, outBuf.unsafe_mut_ref(0)) % 8 == 0,
                        "Output pointer should always be aligned here.");

                if ptr_sub(inEnd, inPtr) < 10 {
                    if out >= outEnd {
                        self.inner.skip(ptr_sub(inPtr, bufferBegin));
                        return Some(mut_ptr_sub(out, outBuf.unsafe_mut_ref(0)));
                    }

                    if ptr_sub(inEnd, inPtr) == 0 {
                        refresh_buffer!(self.inner, size, inPtr, inEnd, out, outBuf, bufferBegin);
                        continue;
                    }

                    //# We have at least 1, but not 10, bytes availabe. We need to read
                    //# slowly, doing a bounds check on each byte.

                    tag = *inPtr;
                    inPtr = inPtr.offset(1);

                    for i in range(0, 8) {
                        if (tag & (1u8 << i)) != 0 {
                            if ptr_sub(inEnd, inPtr) == 0 {
                                refresh_buffer!(self.inner, size, inPtr, inEnd,
                                                out, outBuf, bufferBegin);
                            }
                            *out = *inPtr;
                            out = out.offset(1);
                            inPtr = inPtr.offset(1);
                        } else {
                            *out = 0;
                            out = out.offset(1);
                        }
                    }

                    if ptr_sub(inEnd, inPtr) == 0 && (tag == 0 || tag == 0xff) {
                        refresh_buffer!(self.inner, size, inPtr, inEnd,
                                        out, outBuf, bufferBegin);
                    }
                } else {
                    tag = *inPtr;
                    inPtr = inPtr.offset(1);

                    for n in range(0, 8) {
                        let isNonzero = (tag & (1 as u8 << n)) != 0;
                        *out = (*inPtr) & ((-(isNonzero as i8)) as u8);
                        out = out.offset(1);
                        inPtr = inPtr.offset(isNonzero as int);
                    }
                }
                if (tag == 0) {
                    assert!(ptr_sub(inEnd, inPtr) > 0,
                            "Should always have non-empty buffer here");

                    let runLength : uint = (*inPtr) as uint * 8;
                    inPtr = inPtr.offset(1);

                    assert!(runLength <= mut_ptr_sub(outEnd, out),
                            "Packed input did not end cleanly on a segment boundary");

                    std::ptr::set_memory(out, 0, runLength);
                    out = out.offset(runLength as int);

                } else if (tag == 0xff) {
                    assert!(ptr_sub(inEnd, inPtr) > 0,
                            "Should always have non-empty buffer here");

                    let mut runLength : uint = (*inPtr) as uint * 8;
                    inPtr = inPtr.offset(1);

                    assert!(runLength <= mut_ptr_sub(outEnd, out),
                            "Packed input did not end cleanly on a segment boundary");

                    let inRemaining = ptr_sub(inEnd, inPtr);
                    if (inRemaining >= runLength) {
                        //# Fast path.
                        std::ptr::copy_nonoverlapping_memory(out, inPtr, runLength);
                        out = out.offset(runLength as int);
                        inPtr = inPtr.offset(runLength as int);
                    } else {
                        //# Copy over the first buffer, then do one big read for the rest.
                        std::ptr::copy_nonoverlapping_memory(out, inPtr, inRemaining);
                        out = out.offset(inRemaining as int);
                        runLength -= inRemaining;

                        self.inner.skip(size);
                        do std::vec::raw::mut_buf_as_slice::<u8,()>(out, runLength) |buf| {
                            self.inner.read(buf);
                        }
                        out = out.offset(runLength as int);

                        if (out == outEnd) {
                            return Some(len);
                        } else {
                            let (b, e) = self.inner.getReadBuffer();
                            inPtr = b;
                            inEnd = e;
                            size = ptr_sub(e, b);
                            bufferBegin = inPtr;
                            continue;
                        }
                    }
                }

                if (out == outEnd) {
                    self.inner.skip(ptr_sub(inPtr, bufferBegin));
                    return Some(len);
                }
            }
        }
    }
}

pub struct PackedOutputStream<'a, 'b, W> {
    inner : &'a mut io::BufferedOutputStream<'b, W>
}

impl <'a, 'b, W : std::io::Writer> std::io::Writer for PackedOutputStream<'a, 'b, W> {
    fn write(&mut self, inBuf : &[u8]) {
        unsafe {
            let (mut out, mut bufferEnd) = self.inner.getWriteBuffer();
            let mut bufferBegin = out;
            let mut slowBuffer : [u8,..20] = [0, ..20];

            let mut inPtr : *u8 = inBuf.unsafe_ref(0);
            let inEnd : *u8 = inBuf.unsafe_ref(inBuf.len());

            while (inPtr < inEnd) {

                if (mut_ptr_sub(bufferEnd, out) < 10) {
                    //# Oops, we're out of space. We need at least 10
                    //# bytes for the fast path, since we don't
                    //# bounds-check on every byte.
                    self.inner.write_ptr(bufferBegin, mut_ptr_sub(out, bufferBegin));

                    out = slowBuffer.unsafe_mut_ref(0);
                    bufferEnd = slowBuffer.unsafe_mut_ref(20);
                    bufferBegin = out;
                }

                let tagPos : *mut u8 = out;
                out = out.offset(1);

                let bit0 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit0 as int);
                inPtr = inPtr.offset(1);

                let bit1 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit1 as int);
                inPtr = inPtr.offset(1);

                let bit2 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit2 as int);
                inPtr = inPtr.offset(1);

                let bit3 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit3 as int);
                inPtr = inPtr.offset(1);

                let bit4 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit4 as int);
                inPtr = inPtr.offset(1);

                let bit5 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit5 as int);
                inPtr = inPtr.offset(1);

                let bit6 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit6 as int);
                inPtr = inPtr.offset(1);

                let bit7 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit7 as int);
                inPtr = inPtr.offset(1);

                let tag : u8 = (bit0 << 0) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
                    | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7);

                *tagPos = tag;

                if (tag == 0) {
                    //# An all-zero word is followed by a count of
                    //# consecutive zero words (not including the first
                    //# one).

                    let mut inWord : *u64 = std::cast::transmute(inPtr);
                    let mut limit : *u64 = std::cast::transmute(inEnd);
                    if (ptr_sub(limit, inWord) > 255) {
                        limit = inWord.offset(255);
                    }
                    while (inWord < limit && *inWord == 0) {
                        inWord = inWord.offset(1);
                    }
                    *out = ptr_sub(inWord, std::cast::transmute::<*u8, *u64>(inPtr)) as u8;

                    out = out.offset(1);
                    inPtr = std::cast::transmute::<*u64, *u8>(inWord);

                } else if (tag == 0xff) {
                    //# An all-nonzero word is followed by a count of
                    //# consecutive uncompressed words, followed by the
                    //# uncompressed words themselves.

                    //# Count the number of consecutive words in the input
                    //# which have no more than a single zero-byte. We look
                    //# for at least two zeros because that's the point
                    //# where our compression scheme becomes a net win.
                    let runStart = inPtr;
                    let mut limit = inEnd;
                    if (ptr_sub(limit, inPtr) > 255 * 8) {
                        limit = inPtr.offset(255 * 8);
                    }

                    while (inPtr < limit) {
                        let mut c = 0;

                        for _ in range(0,8) {
                            c += (*inPtr == 0) as u8;
                            inPtr = inPtr.offset(1);
                        }

                        if (c >= 2) {
                            //# Un-read the word with multiple zeros, since
                            //# we'll want to compress that one.
                            inPtr = inPtr.offset(-8);
                            break;
                        }
                    }
                    let count : uint = ptr_sub(inPtr, runStart);
                    *out = (count / 8) as u8;
                    out = out.offset(1);

                    if (count <= mut_ptr_sub(bufferEnd, out)) {
                        //# There's enough space to memcpy.

                        let src : *u8 = runStart;
                        std::ptr::copy_nonoverlapping_memory(out, src, count);

                        out = out.offset(count as int);
                    } else {
                        //# Input overruns the output buffer. We'll give it
                        //# to the output stream in one chunk and let it
                        //# decide what to do.
                        self.inner.write_ptr(bufferBegin, mut_ptr_sub(out, bufferBegin));

                        do std::vec::raw::buf_as_slice::<u8,()>(runStart, count) |buf| {
                            self.inner.write(buf);
                        }

                        let (out1, bufferEnd1) = self.inner.getWriteBuffer();
                        out = out1; bufferEnd = bufferEnd1;
                        bufferBegin = out;
                    }
                }
            }

            self.inner.write_ptr(bufferBegin, mut_ptr_sub(out, bufferBegin));
        }
    }

   fn flush(&mut self) { self.inner.flush(); }
}

pub trait WritePacked {
    fn writePackedMessage(&mut self, message : &MessageBuilder);
}

impl <'self, T : std::io::Writer> WritePacked for io::BufferedOutputStream<'self, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut packedOutputStream = PackedOutputStream {inner : self};
        writeMessage(&mut packedOutputStream, message);
    }
}

pub struct WritePackedWrapper<'a, T> {writer : &'a mut T }

impl <'a, T: std::io::Writer> WritePacked for WritePackedWrapper<'a, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut buffered = io::BufferedOutputStream::new(self.writer);
        buffered.writePackedMessage(message);
        buffered.flush();
    }
}
<commit_msg>only need one pointer subtraction function<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use io;
use message::*;
use serialize::*;

#[inline]
unsafe fn ptr_sub<T, U:std::ptr::RawPtr<T>>(p1 : U, p2 : U) -> uint {
    return (p1.to_uint() - p2.to_uint()) / std::mem::size_of::<T>();
}

pub struct PackedInputStream<'a, 'b,  R> {
    inner : &'a mut io::BufferedInputStream<'b, R>
}

macro_rules! refresh_buffer(
    ($inner:expr, $size:ident, $inPtr:ident, $inEnd:ident, $out:ident,
     $outBuf:ident, $bufferBegin:ident) => (
        {
            $inner.skip($size);
            let (b, e) = $inner.getReadBuffer();
            $inPtr = b;
            $inEnd = e;
            $size = ptr_sub($inEnd, $inPtr);
            $bufferBegin = b;
            assert!($size > 0);
        }
        );
    )

impl <'a, 'b, R : std::io::Reader> std::io::Reader for PackedInputStream<'a, 'b, R> {
    fn eof(&mut self) -> bool {
        self.inner.eof()
    }

    fn read(&mut self, outBuf: &mut [u8]) -> Option<uint> {
        let len = outBuf.len();

        if (len == 0) { return Some(0); }

        assert!(len % 8 == 0, "PackInputStream reads must be word-aligned");

        unsafe {
            let mut out = outBuf.unsafe_mut_ref(0);
            let outEnd = outBuf.unsafe_mut_ref(len);

            let (mut inPtr, mut inEnd) = self.inner.getReadBuffer();
            let mut bufferBegin = inPtr;
            let mut size = ptr_sub(inEnd, inPtr);
            if size == 0 {
                return Some(0);
            }

            loop {

                let mut tag : u8;

                assert!(ptr_sub(out, outBuf.unsafe_mut_ref(0)) % 8 == 0,
                        "Output pointer should always be aligned here.");

                if ptr_sub(inEnd, inPtr) < 10 {
                    if out >= outEnd {
                        self.inner.skip(ptr_sub(inPtr, bufferBegin));
                        return Some(ptr_sub(out, outBuf.unsafe_mut_ref(0)));
                    }

                    if ptr_sub(inEnd, inPtr) == 0 {
                        refresh_buffer!(self.inner, size, inPtr, inEnd, out, outBuf, bufferBegin);
                        continue;
                    }

                    //# We have at least 1, but not 10, bytes availabe. We need to read
                    //# slowly, doing a bounds check on each byte.

                    tag = *inPtr;
                    inPtr = inPtr.offset(1);

                    for i in range(0, 8) {
                        if (tag & (1u8 << i)) != 0 {
                            if ptr_sub(inEnd, inPtr) == 0 {
                                refresh_buffer!(self.inner, size, inPtr, inEnd,
                                                out, outBuf, bufferBegin);
                            }
                            *out = *inPtr;
                            out = out.offset(1);
                            inPtr = inPtr.offset(1);
                        } else {
                            *out = 0;
                            out = out.offset(1);
                        }
                    }

                    if ptr_sub(inEnd, inPtr) == 0 && (tag == 0 || tag == 0xff) {
                        refresh_buffer!(self.inner, size, inPtr, inEnd,
                                        out, outBuf, bufferBegin);
                    }
                } else {
                    tag = *inPtr;
                    inPtr = inPtr.offset(1);

                    for n in range(0, 8) {
                        let isNonzero = (tag & (1 as u8 << n)) != 0;
                        *out = (*inPtr) & ((-(isNonzero as i8)) as u8);
                        out = out.offset(1);
                        inPtr = inPtr.offset(isNonzero as int);
                    }
                }
                if (tag == 0) {
                    assert!(ptr_sub(inEnd, inPtr) > 0,
                            "Should always have non-empty buffer here");

                    let runLength : uint = (*inPtr) as uint * 8;
                    inPtr = inPtr.offset(1);

                    assert!(runLength <= ptr_sub(outEnd, out),
                            "Packed input did not end cleanly on a segment boundary");

                    std::ptr::set_memory(out, 0, runLength);
                    out = out.offset(runLength as int);

                } else if (tag == 0xff) {
                    assert!(ptr_sub(inEnd, inPtr) > 0,
                            "Should always have non-empty buffer here");

                    let mut runLength : uint = (*inPtr) as uint * 8;
                    inPtr = inPtr.offset(1);

                    assert!(runLength <= ptr_sub(outEnd, out),
                            "Packed input did not end cleanly on a segment boundary");

                    let inRemaining = ptr_sub(inEnd, inPtr);
                    if (inRemaining >= runLength) {
                        //# Fast path.
                        std::ptr::copy_nonoverlapping_memory(out, inPtr, runLength);
                        out = out.offset(runLength as int);
                        inPtr = inPtr.offset(runLength as int);
                    } else {
                        //# Copy over the first buffer, then do one big read for the rest.
                        std::ptr::copy_nonoverlapping_memory(out, inPtr, inRemaining);
                        out = out.offset(inRemaining as int);
                        runLength -= inRemaining;

                        self.inner.skip(size);
                        do std::vec::raw::mut_buf_as_slice::<u8,()>(out, runLength) |buf| {
                            self.inner.read(buf);
                        }
                        out = out.offset(runLength as int);

                        if (out == outEnd) {
                            return Some(len);
                        } else {
                            let (b, e) = self.inner.getReadBuffer();
                            inPtr = b;
                            inEnd = e;
                            size = ptr_sub(e, b);
                            bufferBegin = inPtr;
                            continue;
                        }
                    }
                }

                if (out == outEnd) {
                    self.inner.skip(ptr_sub(inPtr, bufferBegin));
                    return Some(len);
                }
            }
        }
    }
}

pub struct PackedOutputStream<'a, 'b, W> {
    inner : &'a mut io::BufferedOutputStream<'b, W>
}

impl <'a, 'b, W : std::io::Writer> std::io::Writer for PackedOutputStream<'a, 'b, W> {
    fn write(&mut self, inBuf : &[u8]) {
        unsafe {
            let (mut out, mut bufferEnd) = self.inner.getWriteBuffer();
            let mut bufferBegin = out;
            let mut slowBuffer : [u8,..20] = [0, ..20];

            let mut inPtr : *u8 = inBuf.unsafe_ref(0);
            let inEnd : *u8 = inBuf.unsafe_ref(inBuf.len());

            while (inPtr < inEnd) {

                if (ptr_sub(bufferEnd, out) < 10) {
                    //# Oops, we're out of space. We need at least 10
                    //# bytes for the fast path, since we don't
                    //# bounds-check on every byte.
                    self.inner.write_ptr(bufferBegin, ptr_sub(out, bufferBegin));

                    out = slowBuffer.unsafe_mut_ref(0);
                    bufferEnd = slowBuffer.unsafe_mut_ref(20);
                    bufferBegin = out;
                }

                let tagPos : *mut u8 = out;
                out = out.offset(1);

                let bit0 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit0 as int);
                inPtr = inPtr.offset(1);

                let bit1 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit1 as int);
                inPtr = inPtr.offset(1);

                let bit2 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit2 as int);
                inPtr = inPtr.offset(1);

                let bit3 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit3 as int);
                inPtr = inPtr.offset(1);

                let bit4 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit4 as int);
                inPtr = inPtr.offset(1);

                let bit5 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit5 as int);
                inPtr = inPtr.offset(1);

                let bit6 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit6 as int);
                inPtr = inPtr.offset(1);

                let bit7 = (*inPtr != 0) as u8;
                *out = *inPtr;
                out = out.offset(bit7 as int);
                inPtr = inPtr.offset(1);

                let tag : u8 = (bit0 << 0) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
                    | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7);

                *tagPos = tag;

                if (tag == 0) {
                    //# An all-zero word is followed by a count of
                    //# consecutive zero words (not including the first
                    //# one).

                    let mut inWord : *u64 = std::cast::transmute(inPtr);
                    let mut limit : *u64 = std::cast::transmute(inEnd);
                    if (ptr_sub(limit, inWord) > 255) {
                        limit = inWord.offset(255);
                    }
                    while (inWord < limit && *inWord == 0) {
                        inWord = inWord.offset(1);
                    }
                    *out = ptr_sub(inWord, std::cast::transmute::<*u8, *u64>(inPtr)) as u8;

                    out = out.offset(1);
                    inPtr = std::cast::transmute::<*u64, *u8>(inWord);

                } else if (tag == 0xff) {
                    //# An all-nonzero word is followed by a count of
                    //# consecutive uncompressed words, followed by the
                    //# uncompressed words themselves.

                    //# Count the number of consecutive words in the input
                    //# which have no more than a single zero-byte. We look
                    //# for at least two zeros because that's the point
                    //# where our compression scheme becomes a net win.
                    let runStart = inPtr;
                    let mut limit = inEnd;
                    if (ptr_sub(limit, inPtr) > 255 * 8) {
                        limit = inPtr.offset(255 * 8);
                    }

                    while (inPtr < limit) {
                        let mut c = 0;

                        for _ in range(0,8) {
                            c += (*inPtr == 0) as u8;
                            inPtr = inPtr.offset(1);
                        }

                        if (c >= 2) {
                            //# Un-read the word with multiple zeros, since
                            //# we'll want to compress that one.
                            inPtr = inPtr.offset(-8);
                            break;
                        }
                    }
                    let count : uint = ptr_sub(inPtr, runStart);
                    *out = (count / 8) as u8;
                    out = out.offset(1);

                    if (count <= ptr_sub(bufferEnd, out)) {
                        //# There's enough space to memcpy.

                        let src : *u8 = runStart;
                        std::ptr::copy_nonoverlapping_memory(out, src, count);

                        out = out.offset(count as int);
                    } else {
                        //# Input overruns the output buffer. We'll give it
                        //# to the output stream in one chunk and let it
                        //# decide what to do.
                        self.inner.write_ptr(bufferBegin, ptr_sub(out, bufferBegin));

                        do std::vec::raw::buf_as_slice::<u8,()>(runStart, count) |buf| {
                            self.inner.write(buf);
                        }

                        let (out1, bufferEnd1) = self.inner.getWriteBuffer();
                        out = out1; bufferEnd = bufferEnd1;
                        bufferBegin = out;
                    }
                }
            }

            self.inner.write_ptr(bufferBegin, ptr_sub(out, bufferBegin));
        }
    }

   fn flush(&mut self) { self.inner.flush(); }
}

pub trait WritePacked {
    fn writePackedMessage(&mut self, message : &MessageBuilder);
}

impl <'self, T : std::io::Writer> WritePacked for io::BufferedOutputStream<'self, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut packedOutputStream = PackedOutputStream {inner : self};
        writeMessage(&mut packedOutputStream, message);
    }
}

pub struct WritePackedWrapper<'a, T> {writer : &'a mut T }

impl <'a, T: std::io::Writer> WritePacked for WritePackedWrapper<'a, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut buffered = io::BufferedOutputStream::new(self.writer);
        buffered.writePackedMessage(message);
        buffered.flush();
    }
}
<|endoftext|>


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

#![stable(feature = "metadata_ext", since = "1.1.0")]

use libc;

use fs::Metadata;
use sys_common::AsInner;

#[allow(deprecated)]
use os::linux::raw;

/// OS-specific extension methods for `fs::Metadata`
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
    /// Gain a reference to the underlying `stat` structure which contains
    /// the raw information returned by the OS.
    ///
    /// The contents of the returned `stat` are **not** consistent across
    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
    /// cross-Unix abstractions contained within the raw stat.
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    #[rustc_deprecated(since = "1.8.0",
                       reason = "deprecated in favor of the accessor \
                                 methods of this trait")]
    #[allow(deprecated)]
    fn as_raw_stat(&self) -> &raw::stat;

    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_dev(&self) -> u64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ino(&self) -> u64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mode(&self) -> u32;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_nlink(&self) -> u64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_uid(&self) -> u32;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_gid(&self) -> u32;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_rdev(&self) -> u64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_size(&self) -> u64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_atime(&self) -> i64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_atime_nsec(&self) -> i64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mtime(&self) -> i64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mtime_nsec(&self) -> i64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ctime(&self) -> i64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ctime_nsec(&self) -> i64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_blksize(&self) -> u64;
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_blocks(&self) -> u64;
}

#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for Metadata {
    #[allow(deprecated)]
    fn as_raw_stat(&self) -> &raw::stat {
        unsafe {
            &*(self.as_inner().as_inner() as *const libc::stat64
                                          as *const raw::stat)
        }
    }
    fn st_dev(&self) -> u64 {
        self.as_inner().as_inner().st_dev as u64
    }
    fn st_ino(&self) -> u64 {
        self.as_inner().as_inner().st_ino as u64
    }
    fn st_mode(&self) -> u32 {
        self.as_inner().as_inner().st_mode as u32
    }
    fn st_nlink(&self) -> u64 {
        self.as_inner().as_inner().st_nlink as u64
    }
    fn st_uid(&self) -> u32 {
        self.as_inner().as_inner().st_uid as u32
    }
    fn st_gid(&self) -> u32 {
        self.as_inner().as_inner().st_gid as u32
    }
    fn st_rdev(&self) -> u64 {
        self.as_inner().as_inner().st_rdev as u64
    }
    fn st_size(&self) -> u64 {
        self.as_inner().as_inner().st_size as u64
    }
    fn st_atime(&self) -> i64 {
        self.as_inner().as_inner().st_atime as i64
    }
    fn st_atime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_atime_nsec as i64
    }
    fn st_mtime(&self) -> i64 {
        self.as_inner().as_inner().st_mtime as i64
    }
    fn st_mtime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_mtime_nsec as i64
    }
    fn st_ctime(&self) -> i64 {
        self.as_inner().as_inner().st_ctime as i64
    }
    fn st_ctime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_ctime_nsec as i64
    }
    fn st_blksize(&self) -> u64 {
        self.as_inner().as_inner().st_blksize as u64
    }
    fn st_blocks(&self) -> u64 {
        self.as_inner().as_inner().st_blocks as u64
    }
}
<commit_msg>Rollup merge of #40869 - ctjhoa:master, r=steveklabnik<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![stable(feature = "metadata_ext", since = "1.1.0")]

use libc;

use fs::Metadata;
use sys_common::AsInner;

#[allow(deprecated)]
use os::linux::raw;

/// OS-specific extension methods for `fs::Metadata`
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
    /// Gain a reference to the underlying `stat` structure which contains
    /// the raw information returned by the OS.
    ///
    /// The contents of the returned `stat` are **not** consistent across
    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
    /// cross-Unix abstractions contained within the raw stat.
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    #[rustc_deprecated(since = "1.8.0",
                       reason = "deprecated in favor of the accessor \
                                 methods of this trait")]
    #[allow(deprecated)]
    fn as_raw_stat(&self) -> &raw::stat;

    /// Returns the device ID on which this file resides.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_dev(&self) -> u64;
    /// Returns the inode number.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ino(&self) -> u64;
    /// Returns the file type and mode.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mode(&self) -> u32;
    /// Returns the number of hard links to file.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_nlink(&self) -> u64;
    /// Returns the user ID of the file owner.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_uid(&self) -> u32;
    /// Returns the group ID of the file owner.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_gid(&self) -> u32;
    /// Returns the device ID that this file represents. Only relevant for special file.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_rdev(&self) -> u64;
    /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
    ///
    /// The size of a symbolic link is the length of the pathname it contains,
    /// without a terminating null byte.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_size(&self) -> u64;
    /// Returns the last access time.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_atime(&self) -> i64;
    /// Returns the last access time, nano seconds part.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_atime_nsec(&self) -> i64;
    /// Returns the last modification time.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mtime(&self) -> i64;
    /// Returns the last modification time, nano seconds part.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mtime_nsec(&self) -> i64;
    /// Returns the last status change time.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ctime(&self) -> i64;
    /// Returns the last status change time, nano seconds part.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ctime_nsec(&self) -> i64;
    /// Returns the "preferred" blocksize for efficient filesystem I/O.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_blksize(&self) -> u64;
    /// Returns the number of blocks allocated to the file, 512-byte units.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_blocks(&self) -> u64;
}

#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for Metadata {
    #[allow(deprecated)]
    fn as_raw_stat(&self) -> &raw::stat {
        unsafe {
            &*(self.as_inner().as_inner() as *const libc::stat64
                                          as *const raw::stat)
        }
    }
    fn st_dev(&self) -> u64 {
        self.as_inner().as_inner().st_dev as u64
    }
    fn st_ino(&self) -> u64 {
        self.as_inner().as_inner().st_ino as u64
    }
    fn st_mode(&self) -> u32 {
        self.as_inner().as_inner().st_mode as u32
    }
    fn st_nlink(&self) -> u64 {
        self.as_inner().as_inner().st_nlink as u64
    }
    fn st_uid(&self) -> u32 {
        self.as_inner().as_inner().st_uid as u32
    }
    fn st_gid(&self) -> u32 {
        self.as_inner().as_inner().st_gid as u32
    }
    fn st_rdev(&self) -> u64 {
        self.as_inner().as_inner().st_rdev as u64
    }
    fn st_size(&self) -> u64 {
        self.as_inner().as_inner().st_size as u64
    }
    fn st_atime(&self) -> i64 {
        self.as_inner().as_inner().st_atime as i64
    }
    fn st_atime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_atime_nsec as i64
    }
    fn st_mtime(&self) -> i64 {
        self.as_inner().as_inner().st_mtime as i64
    }
    fn st_mtime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_mtime_nsec as i64
    }
    fn st_ctime(&self) -> i64 {
        self.as_inner().as_inner().st_ctime as i64
    }
    fn st_ctime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_ctime_nsec as i64
    }
    fn st_blksize(&self) -> u64 {
        self.as_inner().as_inner().st_blksize as u64
    }
    fn st_blocks(&self) -> u64 {
        self.as_inner().as_inner().st_blocks as u64
    }
}
<|endoftext|>


<commit_before>use std::f32;
use std::io;

fn f(x: f32) -> f32 {
    x.cos()
}

fn main() {
    let mut x = String::new();

    println!("Input seed");

    io::stdin().read_line(&mut x)
        .ok()
        .expect("invalid!");

    let mut x: f32 = match x.trim().parse() {
        Ok(num) => num,
        Err(_) => { 1.1 },
    };

    while (f(x) - x).abs() > f32::EPSILON {
        x = f(x)
    }

    println!("Dottie: {}", x);
}
<commit_msg>[2015-08-24] Challenge #229 [Easy] The Dottie Number<commit_after>use std::f32;
use std::io;

fn fixed_point<F>(f: F, mut x: f32) -> f32
    where F : Fn(f32) -> f32 {

    let mut count = 0;
    loop {
        let old = x;
        x = f(x);
        count += 1;

        if (x - old).abs() <= f32::EPSILON || count > 10000 { break; }
    }
    x
}

fn main() {
    let mut x = String::new();

    println!("Input seed");

    io::stdin().read_line(&mut x)
        .ok()
        .expect("invalid!");

    let x: f32 = match x.trim().parse() {
        Ok(num) => num,
        Err(_) => { 1.1 },
    };

    // Dottie Number
    let dottie = fixed_point(|y| y.cos(), x);

    println!("Dottie: {}", dottie);

    // Challenge 1
    let ch1 = fixed_point(|y| y - y.tan(), x);

    println!("challenge 1: {}", ch1);

    // Challenge 2
    let ch2 = fixed_point(|y| 1.0 + (1.0 / y), x);

    println!("challenge 2: {}", ch2);

    // Challenge 3
    let ch3 = fixed_point(|y| 4.0 * y * (1.0 - y), x);

    println!("challenge 3: {}", ch3);
}
<|endoftext|>


<commit_before>/// `RouteGraph` defines a Directed Acyclic Graph of Effects.
/// The edges connecting each Effect have a source and destination slot.
/// Edges are also allowed to go to null, in which case they are treated as outputs.
/// Edges can also come from null, in which case they are treated as inputs.

use std::collections::hash_map::HashMap;
use std::collections::hash_map;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter};
use std::fmt;
use std::rc::Rc;

use resman::ResMan;
use super::adjlist::AdjList;
use super::effect;
use super::effect::Effect;
use super::nullable_int::NullableInt;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct EdgeWeight {
    from_slot: u32,
    to_slot: u32,
}

pub type NodeData = Rc<Effect>;

/// None represents the Dag's I/O
type PrimNodeHandle = NullableInt<u32>;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct NodeHandle {
    node_handle: PrimNodeHandle,
}

#[derive(Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct Edge {
    from: NodeHandle,
    to: NodeHandle,
    weight: EdgeWeight,
}

#[derive(Debug)]
pub enum Error {
    /// Raised when an attempt to modify the graph would create a dependency cycle.
    WouldCycle,
    /// Raised on attempt to delete a node when it still has edges.
    NodeInUse,
    /// Raised on attempt to create a node with an id that's already in use.
    NodeExists,
    /// Error inside some Effect:: method
    EffectError(effect::Error),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

#[derive(Default, Debug)]
pub struct RouteGraph {
    edges: HashMap<NodeHandle, EdgeSet>,
    node_data: HashMap<NodeHandle, NodeData>,
}

#[derive(Debug)]
struct EdgeSet {
    outbound: HashSet<Edge>,
    inbound: HashSet<Edge>,
}

impl RouteGraph {
    pub fn new() -> Self {
        Default::default()
    }
    pub fn iter_nodes<'a>(&'a self) -> impl Iterator<Item=(&NodeHandle, &NodeData)> + 'a {
        self.node_data.iter()
    }
    pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item=&Edge> + 'a {
        self.edges.values().flat_map(|v_set| v_set.outbound.iter())
    }
    pub fn get_data(&self, handle: &NodeHandle) -> Option<&NodeData> {
        self.node_data.get(handle)
    }
    /// Try to create a node with the given handle/data.
    /// Will error if the handle is already in use.
    pub fn add_node(&mut self, handle: NodeHandle, node_data: NodeData) -> ResultE<()> {
        // Create storage for the node's outgoing edges
        match self.edges.entry(handle) {
            hash_map::Entry::Occupied(_) => Err(Error::NodeExists),
            hash_map::Entry::Vacant(entry) => { entry.insert(EdgeSet::new()); Ok(()) },
        }?;
        // Store the node's data
        assert!(self.node_data.insert(handle, node_data.clone()).is_none());
        Ok(())
    }
    pub fn add_edge(&mut self, edge: Edge) -> ResultE<()> {
        // Algorithm:
        //   Assume we currently have a DAG.
        //   Given that, the only way this new edge could introduce a cycle is if it was a part of
        //     that cycle.
        //   Therefore, if no path exists from the edge to itself, then it is safe to add the edge.
        let is_reachable = self.is_edge_reachable(&edge, &edge);
        if is_reachable {
            Err(Error::WouldCycle)
        } else {
            self.add_edge_unchecked(edge);
            Ok(())
        }
    }
    fn add_edge_unchecked(&mut self, edge: Edge) {
        // associate the edge with its origin.
        self.edges.entry(edge.from_full()).or_insert_with(EdgeSet::new).outbound.insert(edge.clone());
        // associate the edge with its destination.
        self.edges.entry(edge.to_full()).or_insert_with(EdgeSet::new).inbound.insert(edge);
    }
    fn is_edge_reachable(&self, from: &Edge, target: &Edge) -> bool {
        // Algorithm:
        //   Try to reach `edge` from `edge`.
        //   If we reach the boundary of the DAG while doing so, consider all reachable outbound
        //     edges of the DAG
        //     For each such edge, try to reach this DAG (recursively), and then resume the search for `edge`.
        if let Some(_to) = from.to.node_handle.get() {
            // The edge points to a NODE inside a DAG.
            // Consider all (reachable) outgoing edges of the node:
            if let Some(node_data) = self.edges.get(&from.to_full()) {
                for candidate_edge in &node_data.outbound {
                    if self.are_edges_internally_connected(from, candidate_edge) &&
                      self.is_edge_reachable(candidate_edge, target) {
                        return true;
                    }
                }
            }
        }
        false
    }
    /// Assuming from.to() == to.from(), will return true if & only if
    /// from and to are internally connected within the node.
    fn are_edges_internally_connected(&self, from: &Edge, to: &Edge) -> bool {
        self.node_data[&from.to_full()]
            .are_slots_connected(from.weight.to_slot, to.weight.from_slot)
    }
    /// Returns true if there's a path from `in` to `out` at the toplevel DAG.
    pub fn are_slots_connected(&self, in_slot: u32, out_slot: u32) -> bool {
        // Consider all edges from None paired with all edges to None:
        let root_dag = NodeHandle::toplevel();
        let edges_from = self.edges[&root_dag].outbound.iter().filter(|&edge| {
            edge.weight.from_slot == in_slot
        });
        for edge_from in edges_from {
            let edges_to = self.edges[&root_dag].inbound.iter().filter(|&edge| {
                edge.weight.to_slot == out_slot
            });
            for edge_to in edges_to {
                if self.is_edge_reachable(edge_from, edge_to) {
                    return true;
                }
            }
        }
        false
    }
    pub fn del_node(&mut self, node: NodeHandle) -> ResultE<()> {
        let ok_to_delete = match self.edges.entry(node) {
            // Already deleted
            hash_map::Entry::Vacant(_) => Ok(()),
            hash_map::Entry::Occupied(entry) => {
                if entry.get().is_empty() {
                    entry.remove();
                    Ok(())
                } else {
                    // Node has edges
                    Err(Error::NodeInUse)
                }
            }
        };
        if ok_to_delete.is_ok() {
            // delete the data associated with this node
            self.node_data.remove(&node);
        }
        ok_to_delete
    }
    pub fn del_edge(&mut self, edge: Edge) {
        // TODO: garbage collect the edge sets.
        if let Some(edge_set) = self.edges.get_mut(&edge.from_full()) {
            edge_set.outbound.remove(&edge);
        }
        if let Some(edge_set) = self.edges.get_mut(&edge.to_full()) {
            edge_set.inbound.remove(&edge);
        }
    }

    pub fn to_adjlist(&self) -> AdjList {
        // Map Effect -> EffectId
        let nodes = self.node_data.iter().map(|(handle, data)| {
            (*handle, data.id().clone())
        }).collect();
        // Doubly-linked edges -> singly-linked
        let edges = self.edges.iter().flat_map(|(_key, edgeset)| {
            edgeset.outbound.clone().into_iter()
        }).collect();

        AdjList {
            nodes: nodes,
            edges: edges,
        }
    }
    pub fn from_adjlist(adj: AdjList, res: &ResMan) -> ResultE<Self> {
        // Unwrap struct fields to local variables
        let (nodes, edges) = (adj.nodes, adj.edges);

        // Map EffectId -> Effect
        let nodes: ResultE<HashMap<NodeHandle, NodeData>> = nodes.into_iter().map(|(handle, id)| {
            let decoded_data = Effect::from_id(id, res)?;
            Ok((handle, decoded_data))
        }).collect();
        // Type deduction isn't smart enough to unwrap nodes in above statement.
        let nodes = nodes?;

        // Build self with only nodes and no edges
        let mut me = Self {
            edges: HashMap::new(),
            node_data: nodes,
        };

        // Add the edges one at a time, enforcing zero cycles
        for edge in &edges {
            me.add_edge(edge.clone())?
        }
        Ok(me)
    }
}

impl NodeHandle {
    pub fn toplevel() -> Self {
        NodeHandle::new(None)
    }
    pub fn new<T>(node_handle: T) -> Self
        where T: Into<PrimNodeHandle>
    {
        Self{ node_handle: node_handle.into() }
    }
    pub fn node_handle(&self) -> &PrimNodeHandle {
        &self.node_handle
    }
}
impl Display for NodeHandle {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.node_handle.fmt(f)
    }
}

impl Edge {
    /// Create an edge from `from` to null (i.e. an output)
    pub fn new_to_null(from: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from,
            to: NodeHandle::toplevel(),
            weight,
        }
    }
    pub fn new_from_null(to: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from: NodeHandle::toplevel(),
            to,
            weight
        }
    }
    /// Create an edge between the two nodes.
    pub fn new(from: NodeHandle, to: NodeHandle, weight: EdgeWeight) -> Self {
        Self{ from, to, weight }
    }
    // TODO: rename to 'from' and 'to' or 'from_hnd', 'to_hnd'?
    pub fn from_full(&self) -> NodeHandle {
        self.from
    }
    pub fn to_full(&self) -> NodeHandle {
        self.to
    }
    pub fn to_slot(&self) -> u32 {
        self.weight.to_slot
    }
    pub fn from_slot(&self) -> u32 {
        self.weight.from_slot
    }
}

impl EdgeWeight {
    pub fn new(from_slot: u32, to_slot: u32) -> Self {
        Self{ from_slot, to_slot }
    }
}

impl EdgeSet {
    fn new() -> Self {
        EdgeSet {
            outbound: HashSet::new(),
            inbound: HashSet::new(),
        }
    }
    fn is_empty(&self) -> bool {
        self.outbound.is_empty() && self.inbound.is_empty()
    }
}

/// Conversion from `effect::Error` for use with the `?` operator
impl From<effect::Error> for Error {
    fn from(e: effect::Error) -> Self {
        Error::EffectError(e)
    }
}
<commit_msg>impl `Deref` for NodeHandle<commit_after>/// `RouteGraph` defines a Directed Acyclic Graph of Effects.
/// The edges connecting each Effect have a source and destination slot.
/// Edges are also allowed to go to null, in which case they are treated as outputs.
/// Edges can also come from null, in which case they are treated as inputs.

use std::collections::hash_map::HashMap;
use std::collections::hash_map;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter};
use std::fmt;
use std::ops::Deref;
use std::rc::Rc;

use resman::ResMan;
use super::adjlist::AdjList;
use super::effect;
use super::effect::Effect;
use super::nullable_int::NullableInt;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct EdgeWeight {
    from_slot: u32,
    to_slot: u32,
}

pub type NodeData = Rc<Effect>;

/// None represents the Dag's I/O
type PrimNodeHandle = NullableInt<u32>;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct NodeHandle {
    node_handle: PrimNodeHandle,
}

#[derive(Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct Edge {
    from: NodeHandle,
    to: NodeHandle,
    weight: EdgeWeight,
}

#[derive(Debug)]
pub enum Error {
    /// Raised when an attempt to modify the graph would create a dependency cycle.
    WouldCycle,
    /// Raised on attempt to delete a node when it still has edges.
    NodeInUse,
    /// Raised on attempt to create a node with an id that's already in use.
    NodeExists,
    /// Error inside some Effect:: method
    EffectError(effect::Error),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

#[derive(Default, Debug)]
pub struct RouteGraph {
    edges: HashMap<NodeHandle, EdgeSet>,
    node_data: HashMap<NodeHandle, NodeData>,
}

#[derive(Debug)]
struct EdgeSet {
    outbound: HashSet<Edge>,
    inbound: HashSet<Edge>,
}

impl RouteGraph {
    pub fn new() -> Self {
        Default::default()
    }
    pub fn iter_nodes<'a>(&'a self) -> impl Iterator<Item=(&NodeHandle, &NodeData)> + 'a {
        self.node_data.iter()
    }
    pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item=&Edge> + 'a {
        self.edges.values().flat_map(|v_set| v_set.outbound.iter())
    }
    pub fn get_data(&self, handle: &NodeHandle) -> Option<&NodeData> {
        self.node_data.get(handle)
    }
    /// Try to create a node with the given handle/data.
    /// Will error if the handle is already in use.
    pub fn add_node(&mut self, handle: NodeHandle, node_data: NodeData) -> ResultE<()> {
        // Create storage for the node's outgoing edges
        match self.edges.entry(handle) {
            hash_map::Entry::Occupied(_) => Err(Error::NodeExists),
            hash_map::Entry::Vacant(entry) => { entry.insert(EdgeSet::new()); Ok(()) },
        }?;
        // Store the node's data
        assert!(self.node_data.insert(handle, node_data.clone()).is_none());
        Ok(())
    }
    pub fn add_edge(&mut self, edge: Edge) -> ResultE<()> {
        // Algorithm:
        //   Assume we currently have a DAG.
        //   Given that, the only way this new edge could introduce a cycle is if it was a part of
        //     that cycle.
        //   Therefore, if no path exists from the edge to itself, then it is safe to add the edge.
        let is_reachable = self.is_edge_reachable(&edge, &edge);
        if is_reachable {
            Err(Error::WouldCycle)
        } else {
            self.add_edge_unchecked(edge);
            Ok(())
        }
    }
    fn add_edge_unchecked(&mut self, edge: Edge) {
        // associate the edge with its origin.
        self.edges.entry(edge.from_full()).or_insert_with(EdgeSet::new).outbound.insert(edge.clone());
        // associate the edge with its destination.
        self.edges.entry(edge.to_full()).or_insert_with(EdgeSet::new).inbound.insert(edge);
    }
    fn is_edge_reachable(&self, from: &Edge, target: &Edge) -> bool {
        // Algorithm:
        //   Try to reach `edge` from `edge`.
        //   If we reach the boundary of the DAG while doing so, consider all reachable outbound
        //     edges of the DAG
        //     For each such edge, try to reach this DAG (recursively), and then resume the search for `edge`.
        if let Some(_to) = from.to.node_handle.get() {
            // The edge points to a NODE inside a DAG.
            // Consider all (reachable) outgoing edges of the node:
            if let Some(node_data) = self.edges.get(&from.to_full()) {
                for candidate_edge in &node_data.outbound {
                    if self.are_edges_internally_connected(from, candidate_edge) &&
                      self.is_edge_reachable(candidate_edge, target) {
                        return true;
                    }
                }
            }
        }
        false
    }
    /// Assuming from.to() == to.from(), will return true if & only if
    /// from and to are internally connected within the node.
    fn are_edges_internally_connected(&self, from: &Edge, to: &Edge) -> bool {
        self.node_data[&from.to_full()]
            .are_slots_connected(from.weight.to_slot, to.weight.from_slot)
    }
    /// Returns true if there's a path from `in` to `out` at the toplevel DAG.
    pub fn are_slots_connected(&self, in_slot: u32, out_slot: u32) -> bool {
        // Consider all edges from None paired with all edges to None:
        let root_dag = NodeHandle::toplevel();
        let edges_from = self.edges[&root_dag].outbound.iter().filter(|&edge| {
            edge.weight.from_slot == in_slot
        });
        for edge_from in edges_from {
            let edges_to = self.edges[&root_dag].inbound.iter().filter(|&edge| {
                edge.weight.to_slot == out_slot
            });
            for edge_to in edges_to {
                if self.is_edge_reachable(edge_from, edge_to) {
                    return true;
                }
            }
        }
        false
    }
    pub fn del_node(&mut self, node: NodeHandle) -> ResultE<()> {
        let ok_to_delete = match self.edges.entry(node) {
            // Already deleted
            hash_map::Entry::Vacant(_) => Ok(()),
            hash_map::Entry::Occupied(entry) => {
                if entry.get().is_empty() {
                    entry.remove();
                    Ok(())
                } else {
                    // Node has edges
                    Err(Error::NodeInUse)
                }
            }
        };
        if ok_to_delete.is_ok() {
            // delete the data associated with this node
            self.node_data.remove(&node);
        }
        ok_to_delete
    }
    pub fn del_edge(&mut self, edge: Edge) {
        // TODO: garbage collect the edge sets.
        if let Some(edge_set) = self.edges.get_mut(&edge.from_full()) {
            edge_set.outbound.remove(&edge);
        }
        if let Some(edge_set) = self.edges.get_mut(&edge.to_full()) {
            edge_set.inbound.remove(&edge);
        }
    }

    pub fn to_adjlist(&self) -> AdjList {
        // Map Effect -> EffectId
        let nodes = self.node_data.iter().map(|(handle, data)| {
            (*handle, data.id().clone())
        }).collect();
        // Doubly-linked edges -> singly-linked
        let edges = self.edges.iter().flat_map(|(_key, edgeset)| {
            edgeset.outbound.clone().into_iter()
        }).collect();

        AdjList {
            nodes: nodes,
            edges: edges,
        }
    }
    pub fn from_adjlist(adj: AdjList, res: &ResMan) -> ResultE<Self> {
        // Unwrap struct fields to local variables
        let (nodes, edges) = (adj.nodes, adj.edges);

        // Map EffectId -> Effect
        let nodes: ResultE<HashMap<NodeHandle, NodeData>> = nodes.into_iter().map(|(handle, id)| {
            let decoded_data = Effect::from_id(id, res)?;
            Ok((handle, decoded_data))
        }).collect();
        // Type deduction isn't smart enough to unwrap nodes in above statement.
        let nodes = nodes?;

        // Build self with only nodes and no edges
        let mut me = Self {
            edges: HashMap::new(),
            node_data: nodes,
        };

        // Add the edges one at a time, enforcing zero cycles
        for edge in &edges {
            me.add_edge(edge.clone())?
        }
        Ok(me)
    }
}

impl NodeHandle {
    pub fn toplevel() -> Self {
        NodeHandle::new(None)
    }
    pub fn new<T>(node_handle: T) -> Self
        where T: Into<PrimNodeHandle>
    {
        Self{ node_handle: node_handle.into() }
    }
    pub fn node_handle(&self) -> &PrimNodeHandle {
        &self.node_handle
    }
}
impl Display for NodeHandle {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.node_handle.fmt(f)
    }
}
impl Deref for NodeHandle {
    type Target = PrimNodeHandle;
    fn deref(&self) -> &Self::Target {
        &self.node_handle
    }
}

impl Edge {
    /// Create an edge from `from` to null (i.e. an output)
    pub fn new_to_null(from: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from,
            to: NodeHandle::toplevel(),
            weight,
        }
    }
    pub fn new_from_null(to: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from: NodeHandle::toplevel(),
            to,
            weight
        }
    }
    /// Create an edge between the two nodes.
    pub fn new(from: NodeHandle, to: NodeHandle, weight: EdgeWeight) -> Self {
        Self{ from, to, weight }
    }
    // TODO: rename to 'from' and 'to' or 'from_hnd', 'to_hnd'?
    pub fn from_full(&self) -> NodeHandle {
        self.from
    }
    pub fn to_full(&self) -> NodeHandle {
        self.to
    }
    pub fn to_slot(&self) -> u32 {
        self.weight.to_slot
    }
    pub fn from_slot(&self) -> u32 {
        self.weight.from_slot
    }
}

impl EdgeWeight {
    pub fn new(from_slot: u32, to_slot: u32) -> Self {
        Self{ from_slot, to_slot }
    }
}

impl EdgeSet {
    fn new() -> Self {
        EdgeSet {
            outbound: HashSet::new(),
            inbound: HashSet::new(),
        }
    }
    fn is_empty(&self) -> bool {
        self.outbound.is_empty() && self.inbound.is_empty()
    }
}

/// Conversion from `effect::Error` for use with the `?` operator
impl From<effect::Error> for Error {
    fn from(e: effect::Error) -> Self {
        Error::EffectError(e)
    }
}
<|endoftext|>


<commit_before>use crate::bytes_deque::buf_vec_deque::BufVecDeque;
use crate::codec::zeroes::Zeroes;
use crate::solicit::frame::FrameHeaderBuffer;
use bytes::Buf;
use bytes::Bytes;
use std::io::Cursor;
use std::io::IoSlice;
use std::mem;

enum Item {
    Vec(Cursor<Vec<u8>>),
    Bytes(Bytes),
    FrameHeaderBuffer(Cursor<FrameHeaderBuffer>),
    Zeroes(Zeroes),
}

impl Buf for Item {
    fn remaining(&self) -> usize {
        match self {
            Item::Vec(v) => v.remaining(),
            Item::Bytes(b) => b.remaining(),
            Item::FrameHeaderBuffer(c) => c.remaining(),
            Item::Zeroes(z) => z.remaining(),
        }
    }

    fn bytes(&self) -> &[u8] {
        match self {
            Item::Vec(v) => v.bytes(),
            Item::Bytes(b) => b.bytes(),
            Item::FrameHeaderBuffer(c) => c.bytes(),
            Item::Zeroes(z) => z.bytes(),
        }
    }

    fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
        match self {
            Item::Vec(v) => v.bytes_vectored(dst),
            Item::Bytes(b) => b.bytes_vectored(dst),
            Item::FrameHeaderBuffer(c) => c.bytes_vectored(dst),
            Item::Zeroes(z) => z.bytes_vectored(dst),
        }
    }

    fn advance(&mut self, cnt: usize) {
        match self {
            Item::Vec(v) => v.advance(cnt),
            Item::Bytes(b) => b.advance(cnt),
            Item::FrameHeaderBuffer(v) => v.advance(cnt),
            Item::Zeroes(z) => z.advance(cnt),
        }
    }
}

#[derive(Default)]
pub struct WriteBuffer {
    deque: BufVecDeque<Item>,
}

impl Buf for WriteBuffer {
    /// Size of data in the buffer
    fn remaining(&self) -> usize {
        self.deque.remaining()
    }

    fn bytes(&self) -> &[u8] {
        self.deque.bytes()
    }

    fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
        self.deque.bytes_vectored(dst)
    }

    fn advance(&mut self, cnt: usize) {
        self.deque.advance(cnt)
    }
}

impl WriteBuffer {
    pub fn new() -> WriteBuffer {
        Default::default()
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        self.tail_vec().extend_from_slice(data);
    }

    pub fn extend_from_bytes(&mut self, data: Bytes) {
        if data.is_empty() {
            return;
        }
        self.deque.push_back(Item::Bytes(data));
    }

    pub fn extend_frame_header_buffer(&mut self, buffer: FrameHeaderBuffer) {
        self.deque
            .push_back(Item::FrameHeaderBuffer(Cursor::new(buffer)));
    }

    pub fn extend_with_zeroes(&mut self, zeroes: usize) {
        if zeroes == 0 {
            return;
        }
        self.deque.push_back(Item::Zeroes(Zeroes(zeroes)));
    }

    pub fn tail_vec(&mut self) -> WriteBufferTailVec {
        match self.deque.pop_back() {
            Some(Item::Vec(cursor)) => WriteBufferTailVec {
                write_buffer: self,
                position: cursor.position() as usize,
                data: cursor.into_inner(),
            },
            o => {
                if let Some(v) = o {
                    self.deque.push_back(v);
                }
                WriteBufferTailVec {
                    write_buffer: self,
                    data: Vec::new(),
                    position: 0,
                }
            }
        }
    }
}

impl Into<Vec<u8>> for WriteBuffer {
    fn into(mut self) -> Vec<u8> {
        let mut v = Vec::with_capacity(self.remaining());
        while self.has_remaining() {
            let bytes = self.bytes();
            v.extend_from_slice(bytes);
            self.advance(bytes.len());
        }
        v
    }
}

impl Into<Bytes> for WriteBuffer {
    fn into(self) -> Bytes {
        Bytes::from(Into::<Vec<u8>>::into(self))
    }
}

pub struct WriteBufferTailVec<'a> {
    write_buffer: &'a mut WriteBuffer,
    data: Vec<u8>,
    position: usize,
}

impl<'a> Drop for WriteBufferTailVec<'a> {
    fn drop(&mut self) {
        let mut cursor = Cursor::new(mem::take(&mut self.data));
        cursor.set_position(self.position as u64);
        self.write_buffer.deque.push_back(Item::Vec(cursor))
    }
}

impl<'a> WriteBufferTailVec<'a> {
    /// Size of data in the buffer
    pub fn remaining(&self) -> usize {
        debug_assert!(self.position <= self.data.len());
        self.data.len() - self.position
    }

    /// Pos is relative to "data"
    pub fn patch_buf(&mut self, pos: usize, data: &[u8]) {
        let patch_pos = self.position + pos;
        (&mut self.data[patch_pos..patch_pos + data.len()]).copy_from_slice(data);
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        // Could do something smarter
        self.reserve(data.len());
        self.data.extend_from_slice(data);
    }

    pub fn reserve(&mut self, additional: usize) {
        if self.remaining() >= additional {
            return;
        }
        self.compact();
        self.data.reserve(additional);
    }

    pub fn compact(&mut self) {
        self.data.drain(..self.position);
        self.position = 0;
    }
}

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

    #[test]
    fn remaining() {
        let mut buf = WriteBuffer::new();
        buf.extend_from_slice(b"abcd");
        assert_eq!(4, buf.remaining());

        assert_eq!(b'a', buf.get_u8());
        assert_eq!(b'b', buf.get_u8());
        assert_eq!(2, buf.remaining());

        buf.extend_from_slice(b"ef");
        assert_eq!(b'c', buf.get_u8());
        assert_eq!(b'd', buf.get_u8());
        assert_eq!(b'e', buf.get_u8());
        assert_eq!(b'f', buf.get_u8());
        assert_eq!(0, buf.remaining());
    }
}
<commit_msg>Mute warning<commit_after>use crate::bytes_deque::buf_vec_deque::BufVecDeque;
use crate::codec::zeroes::Zeroes;
use crate::solicit::frame::FrameHeaderBuffer;
use bytes::Buf;
use bytes::Bytes;
use std::io::Cursor;
use std::io::IoSlice;
use std::mem;

enum Item {
    Vec(Cursor<Vec<u8>>),
    Bytes(Bytes),
    FrameHeaderBuffer(Cursor<FrameHeaderBuffer>),
    Zeroes(Zeroes),
}

impl Buf for Item {
    fn remaining(&self) -> usize {
        match self {
            Item::Vec(v) => v.remaining(),
            Item::Bytes(b) => b.remaining(),
            Item::FrameHeaderBuffer(c) => c.remaining(),
            Item::Zeroes(z) => z.remaining(),
        }
    }

    fn bytes(&self) -> &[u8] {
        match self {
            Item::Vec(v) => v.bytes(),
            Item::Bytes(b) => b.bytes(),
            Item::FrameHeaderBuffer(c) => c.bytes(),
            Item::Zeroes(z) => z.bytes(),
        }
    }

    fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
        match self {
            Item::Vec(v) => v.bytes_vectored(dst),
            Item::Bytes(b) => b.bytes_vectored(dst),
            Item::FrameHeaderBuffer(c) => c.bytes_vectored(dst),
            Item::Zeroes(z) => z.bytes_vectored(dst),
        }
    }

    fn advance(&mut self, cnt: usize) {
        match self {
            Item::Vec(v) => v.advance(cnt),
            Item::Bytes(b) => b.advance(cnt),
            Item::FrameHeaderBuffer(v) => v.advance(cnt),
            Item::Zeroes(z) => z.advance(cnt),
        }
    }
}

#[derive(Default)]
pub struct WriteBuffer {
    deque: BufVecDeque<Item>,
}

impl Buf for WriteBuffer {
    /// Size of data in the buffer
    fn remaining(&self) -> usize {
        self.deque.remaining()
    }

    fn bytes(&self) -> &[u8] {
        self.deque.bytes()
    }

    fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
        self.deque.bytes_vectored(dst)
    }

    fn advance(&mut self, cnt: usize) {
        self.deque.advance(cnt)
    }
}

impl WriteBuffer {
    pub fn new() -> WriteBuffer {
        Default::default()
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        self.tail_vec().extend_from_slice(data);
    }

    pub fn extend_from_bytes(&mut self, data: Bytes) {
        if data.is_empty() {
            return;
        }
        self.deque.push_back(Item::Bytes(data));
    }

    pub fn extend_frame_header_buffer(&mut self, buffer: FrameHeaderBuffer) {
        self.deque
            .push_back(Item::FrameHeaderBuffer(Cursor::new(buffer)));
    }

    pub fn extend_with_zeroes(&mut self, zeroes: usize) {
        if zeroes == 0 {
            return;
        }
        self.deque.push_back(Item::Zeroes(Zeroes(zeroes)));
    }

    pub fn tail_vec(&mut self) -> WriteBufferTailVec {
        match self.deque.pop_back() {
            Some(Item::Vec(cursor)) => WriteBufferTailVec {
                write_buffer: self,
                position: cursor.position() as usize,
                data: cursor.into_inner(),
            },
            o => {
                if let Some(v) = o {
                    self.deque.push_back(v);
                }
                WriteBufferTailVec {
                    write_buffer: self,
                    data: Vec::new(),
                    position: 0,
                }
            }
        }
    }
}

impl Into<Vec<u8>> for WriteBuffer {
    fn into(mut self) -> Vec<u8> {
        let mut v = Vec::with_capacity(self.remaining());
        while self.has_remaining() {
            let bytes = self.bytes();
            v.extend_from_slice(bytes);
            let len = bytes.len();
            self.advance(len);
        }
        v
    }
}

impl Into<Bytes> for WriteBuffer {
    fn into(self) -> Bytes {
        Bytes::from(Into::<Vec<u8>>::into(self))
    }
}

pub struct WriteBufferTailVec<'a> {
    write_buffer: &'a mut WriteBuffer,
    data: Vec<u8>,
    position: usize,
}

impl<'a> Drop for WriteBufferTailVec<'a> {
    fn drop(&mut self) {
        let mut cursor = Cursor::new(mem::take(&mut self.data));
        cursor.set_position(self.position as u64);
        self.write_buffer.deque.push_back(Item::Vec(cursor))
    }
}

impl<'a> WriteBufferTailVec<'a> {
    /// Size of data in the buffer
    pub fn remaining(&self) -> usize {
        debug_assert!(self.position <= self.data.len());
        self.data.len() - self.position
    }

    /// Pos is relative to "data"
    pub fn patch_buf(&mut self, pos: usize, data: &[u8]) {
        let patch_pos = self.position + pos;
        (&mut self.data[patch_pos..patch_pos + data.len()]).copy_from_slice(data);
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        // Could do something smarter
        self.reserve(data.len());
        self.data.extend_from_slice(data);
    }

    pub fn reserve(&mut self, additional: usize) {
        if self.remaining() >= additional {
            return;
        }
        self.compact();
        self.data.reserve(additional);
    }

    pub fn compact(&mut self) {
        self.data.drain(..self.position);
        self.position = 0;
    }
}

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

    #[test]
    fn remaining() {
        let mut buf = WriteBuffer::new();
        buf.extend_from_slice(b"abcd");
        assert_eq!(4, buf.remaining());

        assert_eq!(b'a', buf.get_u8());
        assert_eq!(b'b', buf.get_u8());
        assert_eq!(2, buf.remaining());

        buf.extend_from_slice(b"ef");
        assert_eq!(b'c', buf.get_u8());
        assert_eq!(b'd', buf.get_u8());
        assert_eq!(b'e', buf.get_u8());
        assert_eq!(b'f', buf.get_u8());
        assert_eq!(0, buf.remaining());
    }
}
<|endoftext|>