<commit_before>use alloc::boxed::Box;
use collections::string::String;
use collections::vec::Vec;
use collections::btree_map::BTreeMap;

use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState};
use super::namespace::{AmlValue, ObjectReference};
use super::pkglength::parse_pkg_length;
use super::termlist::{parse_term_arg, parse_term_list};
use super::namestring::{parse_name_string, parse_super_name};

use time::monotonic;

pub fn parse_type1_opcode(data: &[u8],
                          ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_selector! {
        data, ctx,
        parse_def_break,
        parse_def_breakpoint,
        parse_def_continue,
        parse_def_noop,
        parse_def_fatal,
        parse_def_if_else,
        parse_def_load,
        parse_def_notify,
        parse_def_release,
        parse_def_reset,
        parse_def_signal,
        parse_def_sleep,
        parse_def_stall,
        parse_def_return,
        parse_def_unload,
        parse_def_while
    };

    Err(AmlError::AmlInvalidOpCode)
}

fn parse_def_break(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xA5);
    ctx.state = ExecutionState::BREAK;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_breakpoint(data: &[u8],
                        ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xCC);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_continue(data: &[u8],
                      ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0x9F);
    ctx.state = ExecutionState::CONTINUE;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_noop(data: &[u8],
                  ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xA3);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_fatal(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x32);

    let fatal_type = data[2];
    let fatal_code: u16 = (data[3] as u16) + ((data[4] as u16) << 8);
    let fatal_arg = parse_term_arg(&data[5..], ctx)?;

    Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val))
}

fn parse_def_load(data: &[u8],
                  ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    // TODO: Load in the table pointed to by `name`
    // TODO: Set DDB_Handle to the handle returned by loading in the table
    // TODO: Run the AML parser on the table, in a secondary namespace
    parser_opcode_extended!(data, 0x20);

    let name = parse_name_string(&data[2..], ctx)?;
    let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + name.len + ddb_handle_object.len
    })
}

fn parse_def_notify(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    // TODO: This requires significantly more infrastructure from the OS itself, see 5.6.6
    parser_opcode!(data, 0x86);

    let object = parse_super_name(&data[1..], ctx)?;
    let value = parse_term_arg(&data[1 + object.len..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + object.len + value.len
    })
}

fn parse_def_release(data: &[u8],
                     ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x27);

    let obj = parse_super_name(&data[2..], ctx)?;

    let mut namespace = ctx.prelock();
    let mutex = ctx.get(obj.val.clone());

    match mutex {
        AmlValue::Mutex((sync_level, owner)) => {
            if let Some(o) = owner {
                if o == ctx.ctx_id {
                    ctx.modify(obj.val.clone(), AmlValue::Mutex((sync_level, None)));
                } else {
                    return Err(AmlError::AmlHardFatal);
                }
            }
        },
        AmlValue::OperationRegion { region, offset, len, accessor, accessed_by } => {
            if let Some(o) = accessed_by {
                if o == ctx.ctx_id {
                    ctx.modify(obj.val.clone(), AmlValue::OperationRegion {
                        region,
                        offset,
                        len,
                        accessor,
                        accessed_by: None
                    });
                } else {
                    return Err(AmlError::AmlHardFatal);
                }
            }
        },
        _ => return Err(AmlError::AmlValueError)
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + obj.len
    })
}

fn parse_def_reset(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x26);

    let object = parse_super_name(&data[2..], ctx)?;
    let event = ctx.get(object.val.clone()).get_as_event()?;

    ctx.modify(object.val.clone(), AmlValue::Event(0));

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_signal(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x24);
    let object = parse_super_name(&data[2..], ctx)?;

    let namespace = ctx.prelock();
    let event = ctx.get(object.val.clone()).get_as_event()?;

    ctx.modify(object.val.clone(), AmlValue::Event(event + 1));

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_sleep(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    // TODO: Sleep the processor for the specified number of milliseconds (minimum)
    parser_opcode_extended!(data, 0x22);

    let time = parse_term_arg(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + time.len
    })
}

fn parse_def_stall(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x21);

    let time = parse_term_arg(&data[2..], ctx)?;
    let timeout = time.val.get_as_integer()?;

    let (seconds, nanoseconds) = monotonic();
    let starting_time_ns = nanoseconds + (seconds * 1000000000);

    loop {
        let (seconds, nanoseconds) = monotonic();
        let current_time_ns = nanoseconds + (seconds * 1000000000);

        if current_time_ns - starting_time_ns > timeout as u64 * 1000 {
            break;
        }
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + time.len
    })
}

fn parse_def_unload(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    // TODO: remove from namespace all values added when `object` was loaded
    // TODO: globally synchronous (how?)
    parser_opcode_extended!(data, 0x2A);

    let object = parse_super_name(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_if_else(data: &[u8],
                     ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xA0);

    let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;
    let if_condition = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?;

    let (else_length, else_length_len) = if data.len() > 1 + pkg_length && data[1 + pkg_length] == 0xA1 {
        parse_pkg_length(&data[2 + pkg_length..])?
    } else {
        (0 as usize, 0 as usize)
    };

    if if_condition.val.get_as_integer()? > 0 {
        parse_term_list(&data[1 + pkg_length_len + if_condition.len .. 1 + pkg_length], ctx)?;
    } else if else_length > 0 {
        parse_term_list(&data[2 + pkg_length + else_length_len .. 2 + pkg_length + else_length], ctx)?;
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + pkg_length + if else_length > 0 { 1 + else_length } else { 0 }
    })
}

fn parse_def_while(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xA2);

    let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;

    loop {
        let predicate = parse_term_arg(&data[1 + pkg_length_len..], ctx)?;
        if predicate.val.get_as_integer()? == 0 {
            break;
        }

        parse_term_list(&data[1 + pkg_length_len + predicate.len .. 1 + pkg_length], ctx)?;

        match ctx.state {
            ExecutionState::EXECUTING => (),
            ExecutionState::BREAK => {
                ctx.state = ExecutionState::EXECUTING;
                break;
            },
            ExecutionState::CONTINUE => ctx.state = ExecutionState::EXECUTING,
            _ => return Ok(AmlParseType {
                val: AmlValue::None,
                len: 0 as usize
            })
        }
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + pkg_length
    })
}

fn parse_def_return(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xA4);

    let arg_object = parse_term_arg(&data[1..], ctx)?;
    ctx.state = ExecutionState::RETURN(arg_object.val);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + arg_object.len
    })
}
<commit_msg>Implemented sleep<commit_after>use alloc::boxed::Box;
use collections::string::String;
use collections::vec::Vec;
use collections::btree_map::BTreeMap;

use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState};
use super::namespace::{AmlValue, ObjectReference};
use super::pkglength::parse_pkg_length;
use super::termlist::{parse_term_arg, parse_term_list};
use super::namestring::{parse_name_string, parse_super_name};

use time::monotonic;

pub fn parse_type1_opcode(data: &[u8],
                          ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_selector! {
        data, ctx,
        parse_def_break,
        parse_def_breakpoint,
        parse_def_continue,
        parse_def_noop,
        parse_def_fatal,
        parse_def_if_else,
        parse_def_load,
        parse_def_notify,
        parse_def_release,
        parse_def_reset,
        parse_def_signal,
        parse_def_sleep,
        parse_def_stall,
        parse_def_return,
        parse_def_unload,
        parse_def_while
    };

    Err(AmlError::AmlInvalidOpCode)
}

fn parse_def_break(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xA5);
    ctx.state = ExecutionState::BREAK;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_breakpoint(data: &[u8],
                        ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xCC);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_continue(data: &[u8],
                      ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0x9F);
    ctx.state = ExecutionState::CONTINUE;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_noop(data: &[u8],
                  ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xA3);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_fatal(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x32);

    let fatal_type = data[2];
    let fatal_code: u16 = (data[3] as u16) + ((data[4] as u16) << 8);
    let fatal_arg = parse_term_arg(&data[5..], ctx)?;

    Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val))
}

fn parse_def_load(data: &[u8],
                  ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    // TODO: Load in the table pointed to by `name`
    // TODO: Set DDB_Handle to the handle returned by loading in the table
    // TODO: Run the AML parser on the table, in a secondary namespace
    parser_opcode_extended!(data, 0x20);

    let name = parse_name_string(&data[2..], ctx)?;
    let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + name.len + ddb_handle_object.len
    })
}

fn parse_def_notify(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    // TODO: This requires significantly more infrastructure from the OS itself, see 5.6.6
    parser_opcode!(data, 0x86);

    let object = parse_super_name(&data[1..], ctx)?;
    let value = parse_term_arg(&data[1 + object.len..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + object.len + value.len
    })
}

fn parse_def_release(data: &[u8],
                     ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x27);

    let obj = parse_super_name(&data[2..], ctx)?;

    let mut namespace = ctx.prelock();
    let mutex = ctx.get(obj.val.clone());

    match mutex {
        AmlValue::Mutex((sync_level, owner)) => {
            if let Some(o) = owner {
                if o == ctx.ctx_id {
                    ctx.modify(obj.val.clone(), AmlValue::Mutex((sync_level, None)));
                } else {
                    return Err(AmlError::AmlHardFatal);
                }
            }
        },
        AmlValue::OperationRegion { region, offset, len, accessor, accessed_by } => {
            if let Some(o) = accessed_by {
                if o == ctx.ctx_id {
                    ctx.modify(obj.val.clone(), AmlValue::OperationRegion {
                        region,
                        offset,
                        len,
                        accessor,
                        accessed_by: None
                    });
                } else {
                    return Err(AmlError::AmlHardFatal);
                }
            }
        },
        _ => return Err(AmlError::AmlValueError)
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + obj.len
    })
}

fn parse_def_reset(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x26);

    let object = parse_super_name(&data[2..], ctx)?;
    let event = ctx.get(object.val.clone()).get_as_event()?;

    ctx.modify(object.val.clone(), AmlValue::Event(0));

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_signal(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x24);
    let object = parse_super_name(&data[2..], ctx)?;

    let namespace = ctx.prelock();
    let event = ctx.get(object.val.clone()).get_as_event()?;

    ctx.modify(object.val.clone(), AmlValue::Event(event + 1));

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_sleep(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x22);

    let time = parse_term_arg(&data[2..], ctx)?;
    let timeout = time.val.get_as_integer()?;

    let (seconds, nanoseconds) = monotonic();
    let starting_time_ns = nanoseconds + (seconds * 1000000000);

    loop {
        let (seconds, nanoseconds) = monotonic();
        let current_time_ns = nanoseconds + (seconds * 1000000000);

        if current_time_ns - starting_time_ns > timeout as u64 * 1000000 {
            break;
        }
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + time.len
    })
}

fn parse_def_stall(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode_extended!(data, 0x21);

    let time = parse_term_arg(&data[2..], ctx)?;
    let timeout = time.val.get_as_integer()?;

    let (seconds, nanoseconds) = monotonic();
    let starting_time_ns = nanoseconds + (seconds * 1000000000);

    loop {
        let (seconds, nanoseconds) = monotonic();
        let current_time_ns = nanoseconds + (seconds * 1000000000);

        if current_time_ns - starting_time_ns > timeout as u64 * 1000 {
            break;
        }
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + time.len
    })
}

fn parse_def_unload(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    // TODO: remove from namespace all values added when `object` was loaded
    // TODO: globally synchronous (how?)
    parser_opcode_extended!(data, 0x2A);

    let object = parse_super_name(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_if_else(data: &[u8],
                     ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xA0);

    let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;
    let if_condition = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?;

    let (else_length, else_length_len) = if data.len() > 1 + pkg_length && data[1 + pkg_length] == 0xA1 {
        parse_pkg_length(&data[2 + pkg_length..])?
    } else {
        (0 as usize, 0 as usize)
    };

    if if_condition.val.get_as_integer()? > 0 {
        parse_term_list(&data[1 + pkg_length_len + if_condition.len .. 1 + pkg_length], ctx)?;
    } else if else_length > 0 {
        parse_term_list(&data[2 + pkg_length + else_length_len .. 2 + pkg_length + else_length], ctx)?;
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + pkg_length + if else_length > 0 { 1 + else_length } else { 0 }
    })
}

fn parse_def_while(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xA2);

    let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;

    loop {
        let predicate = parse_term_arg(&data[1 + pkg_length_len..], ctx)?;
        if predicate.val.get_as_integer()? == 0 {
            break;
        }

        parse_term_list(&data[1 + pkg_length_len + predicate.len .. 1 + pkg_length], ctx)?;

        match ctx.state {
            ExecutionState::EXECUTING => (),
            ExecutionState::BREAK => {
                ctx.state = ExecutionState::EXECUTING;
                break;
            },
            ExecutionState::CONTINUE => ctx.state = ExecutionState::EXECUTING,
            _ => return Ok(AmlParseType {
                val: AmlValue::None,
                len: 0 as usize
            })
        }
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + pkg_length
    })
}

fn parse_def_return(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    match ctx.state {
        ExecutionState::EXECUTING => (),
        _ => return Ok(AmlParseType {
            val: AmlValue::None,
            len: 0 as usize
        })
    }

    parser_opcode!(data, 0xA4);

    let arg_object = parse_term_arg(&data[1..], ctx)?;
    ctx.state = ExecutionState::RETURN(arg_object.val);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + arg_object.len
    })
}
<|endoftext|>


<commit_before>//! A thread pool for running blocking functions asynchronously.

use std::sync::atomic::{AtomicU64, Ordering};
use std::thread;
use std::time::Duration;

use crossbeam::channel::{bounded, Receiver, Sender};
use lazy_static::lazy_static;

use super::Promise;

const MAX_THREADS: u64 = 10_000;

static DYNAMIC_THREAD_COUNT: AtomicU64 = AtomicU64::new(0);

struct Pool {
    sender: Sender<Box<FnOnce() + Send + 'static>>,
    receiver: Receiver<Box<FnOnce() + Send + 'static>>,
}

lazy_static! {
    static ref POOL: Pool = {
        for _ in 0..2 {
            thread::Builder::new()
                .name("async-blocking-driver".to_string())
                .spawn(|| {
                    for task in &POOL.receiver {
                        (task)()
                    }
                })
                .expect("cannot start a thread driving blocking tasks");
        }

        // We want to use an unbuffered channel here to help
        // us drive our dynamic control. In effect, the
        // kernel's scheduler becomes the queue, reducing
        // the number of buffers that work must flow through
        // before being acted on by a core. This helps keep
        // latency snappy in the overall async system by
        // reducing bufferbloat.
        let (sender, receiver) = bounded(0);
        Pool { sender, receiver }
    };
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_create_another_blocking_thread() {
    // We use a `Relaxed` atomic operation because
    // it's just a heuristic, and would not lose correctness
    // even if it's random.
    let workers = DYNAMIC_THREAD_COUNT.load(Ordering::Relaxed);
    if workers >= MAX_THREADS {
        return;
    }

    thread::Builder::new()
        .name("async-blocking-driver-dynamic".to_string())
        .spawn(|| {
            let wait_limit = Duration::from_secs(1);

            DYNAMIC_THREAD_COUNT.fetch_add(1, Ordering::Relaxed);
            while let Ok(task) = POOL.receiver.recv_timeout(wait_limit) {
                (task)();
            }
            DYNAMIC_THREAD_COUNT.fetch_sub(1, Ordering::Relaxed);
        })
        .expect("cannot start a dynamic thread driving blocking tasks");
}

/// Spawns a blocking task.
///
/// The task will be spawned onto a thread pool specifically dedicated to blocking tasks.
pub fn spawn<F, R>(work: F) -> Promise<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = Promise::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };
    let first_try_result = POOL.sender.try_send(Box::new(task));
    match first_try_result {
        Ok(()) => {
            // NICEEEE
        }
        Err(crossbeam::channel::TrySendError::Full(task)) => {
            // We were not able to send to the channel without
            // blocking. Try to spin up another thread and then
            // retry sending while blocking.
            maybe_create_another_blocking_thread();
            POOL.sender.send(task).unwrap()
        }
        Err(crossbeam::channel::TrySendError::Disconnected(_)) => {
            panic!(
                "unable to send to blocking threadpool \
                 due to receiver disconnection"
            );
        }
    }
    promise
}
<commit_msg>add dyn keyword<commit_after>//! A thread pool for running blocking functions asynchronously.

use std::sync::atomic::{AtomicU64, Ordering};
use std::thread;
use std::time::Duration;

use crossbeam::channel::{bounded, Receiver, Sender};
use lazy_static::lazy_static;

use super::Promise;

const MAX_THREADS: u64 = 10_000;

static DYNAMIC_THREAD_COUNT: AtomicU64 = AtomicU64::new(0);

struct Pool {
    sender: Sender<Box<dyn FnOnce() + Send + 'static>>,
    receiver: Receiver<Box<dyn FnOnce() + Send + 'static>>,
}

lazy_static! {
    static ref POOL: Pool = {
        for _ in 0..2 {
            thread::Builder::new()
                .name("async-blocking-driver".to_string())
                .spawn(|| {
                    for task in &POOL.receiver {
                        (task)()
                    }
                })
                .expect("cannot start a thread driving blocking tasks");
        }

        // We want to use an unbuffered channel here to help
        // us drive our dynamic control. In effect, the
        // kernel's scheduler becomes the queue, reducing
        // the number of buffers that work must flow through
        // before being acted on by a core. This helps keep
        // latency snappy in the overall async system by
        // reducing bufferbloat.
        let (sender, receiver) = bounded(0);
        Pool { sender, receiver }
    };
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_create_another_blocking_thread() {
    // We use a `Relaxed` atomic operation because
    // it's just a heuristic, and would not lose correctness
    // even if it's random.
    let workers = DYNAMIC_THREAD_COUNT.load(Ordering::Relaxed);
    if workers >= MAX_THREADS {
        return;
    }

    thread::Builder::new()
        .name("async-blocking-driver-dynamic".to_string())
        .spawn(|| {
            let wait_limit = Duration::from_secs(1);

            DYNAMIC_THREAD_COUNT.fetch_add(1, Ordering::Relaxed);
            while let Ok(task) = POOL.receiver.recv_timeout(wait_limit) {
                (task)();
            }
            DYNAMIC_THREAD_COUNT.fetch_sub(1, Ordering::Relaxed);
        })
        .expect("cannot start a dynamic thread driving blocking tasks");
}

/// Spawns a blocking task.
///
/// The task will be spawned onto a thread pool specifically dedicated to blocking tasks.
pub fn spawn<F, R>(work: F) -> Promise<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = Promise::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };
    let first_try_result = POOL.sender.try_send(Box::new(task));
    match first_try_result {
        Ok(()) => {
            // NICEEEE
        }
        Err(crossbeam::channel::TrySendError::Full(task)) => {
            // We were not able to send to the channel without
            // blocking. Try to spin up another thread and then
            // retry sending while blocking.
            maybe_create_another_blocking_thread();
            POOL.sender.send(task).unwrap()
        }
        Err(crossbeam::channel::TrySendError::Disconnected(_)) => {
            panic!(
                "unable to send to blocking threadpool \
                 due to receiver disconnection"
            );
        }
    }
    promise
}
<|endoftext|>


<commit_before>//
// base32n.rs - new base32 module
//
// The Base32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 A             9 J            18 S            27 3
//     1 B            10 K            19 T            28 4
//     2 C            11 L            20 U            29 5
//     3 D            12 M            21 V            30 6
//     4 E            13 N            22 W            31 7
//     5 F            14 O            23 X
//     6 G            15 P            24 Y         (pad) =
//     7 H            16 Q            25 Z
//     8 I            17 R            26 2
//
// The "Extended Hex" Base 32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 0             9 9            18 I            27 R
//     1 1            10 A            19 J            28 S
//     2 2            11 B            20 K            29 T
//     3 3            12 C            21 L            30 U
//     4 4            13 D            22 M            31 V
//     5 5            14 E            23 N
//     6 6            15 F            24 O         (pad) =
//     7 7            16 G            25 P
//     8 8            17 H            26 Q
//

// FIXME write
<commit_msg>base32n: wip<commit_after>//
// base32n.rs - new base32 module
//
// The Base32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 A             9 J            18 S            27 3
//     1 B            10 K            19 T            28 4
//     2 C            11 L            20 U            29 5
//     3 D            12 M            21 V            30 6
//     4 E            13 N            22 W            31 7
//     5 F            14 O            23 X
//     6 G            15 P            24 Y         (pad) =
//     7 H            16 Q            25 Z
//     8 I            17 R            26 2
//
// The "Extended Hex" Base 32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 0             9 9            18 I            27 R
//     1 1            10 A            19 J            28 S
//     2 2            11 B            20 K            29 T
//     3 3            12 C            21 L            30 U
//     4 4            13 D            22 M            31 V
//     5 5            14 E            23 N
//     6 6            15 F            24 O         (pad) =
//     7 7            16 G            25 P
//     8 8            17 H            26 Q
//

use std;

import vec::len;

const PAD: u8 = 61u8;

iface enc {
    fn encode(dst: [mutable u8], src: [u8]);
    fn encode_h(dst: [mutable u8], src: [u8]);
    fn encode_bytes(src: [u8]) -> [u8];
    fn encode_bytes_h(src: [u8]) -> [u8];
    fn decode(dst: [mutable u8], src: [u8]);
    fn decode_h(dst: [mutable u8], src: [u8]);
    fn decode_bytes(src: [u8]) -> [u8];
    fn decode_bytes_h(src: [u8]) -> [u8];
}

fn mk() -> enc {
    type _enc = {table: [u8], table_h: [u8],
                 decode_map: [u8], decode_map_h: [u8]};

    impl of enc for _enc {
        fn encode(dst: [mutable u8], src: [u8]) {
            b32encode(self.table, dst, src);
        }
        fn encode_h(dst: [mutable u8], src: [u8]) {
            b32encode(self.table_h, dst, src);
        }
        fn encode_bytes(src: [u8]) -> [u8] {
            []
        }
        fn encode_bytes_h(src: [u8]) -> [u8] {
            []
        }
        fn decode(dst: [mutable u8], src: [u8]) {
            b32decode(self.decode_map, dst, src);
        }
        fn decode_h(dst: [mutable u8], src: [u8]) {
            b32decode(self.decode_map_h, dst, src);
        }
        fn decode_bytes(src: [u8]) -> [u8] {
            []
        }
        fn decode_bytes_h(src: [u8]) -> [u8] {
            []
        }
    }

    {table: [],
     table_h: [],
     decode_map: [],
     decode_map_h: []} as enc
}

fn b32encode(table: [u8], dst: [mutable u8], src: [u8]) {
}

fn b32decode(decode_map: [u8], dst: [mutable u8], src: [u8]) {
}

#[cfg(test)]
mod tests {
}
<|endoftext|>


<commit_before>use headers::serialization_utils::{push_quoted_string, quoted_string, WriterUtil};
use std::rt::io::{Reader, Writer};

#[deriving(Clone, Eq)]
pub struct EntityTag {
    weak: bool,
    opaque_tag: ~str,
}

impl ToStr for EntityTag {
    fn to_str(&self) -> ~str {
        if self.weak {
            push_quoted_string(~"W/", self.opaque_tag)
        } else {
            quoted_string(self.opaque_tag)
        }
    }
}

impl super::HeaderConvertible for EntityTag {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>) -> Option<EntityTag> {
        let weak;
        let opaque_tag;
        match reader.next() {
            Some(b) if b == 'W' as u8 => match reader.next() {
                Some(b) if b == '/' as u8 => {
                    weak = true;
                    match reader.read_quoted_string(false) {
                        Some(tag) => opaque_tag = tag,
                        None => return None,
                    }
                },
                _ => return None,
            },
            Some(b) if b == '"' as u8 => {
                weak = false;
                match reader.read_quoted_string(true) {
                    Some(tag) => opaque_tag = tag,
                    None => return None,
                }
            },
            _ => {
                return None;
            }
        };
        Some(EntityTag {
            weak: weak,
            opaque_tag: opaque_tag,
        })
    }

    fn to_stream<W: Writer>(&self, writer: &mut W) {
        if self.weak {
            writer.write(bytes!("W/"));
        }
        writer.write_quoted_string(self.opaque_tag);
    }

    fn http_value(&self) -> ~str {
        self.to_str()
    }
}
<commit_msg>Add some ETag helper functions and tests.<commit_after>use headers::serialization_utils::{push_quoted_string, quoted_string, WriterUtil};
use std::rt::io::{Reader, Writer};

#[deriving(Clone, Eq)]
pub struct EntityTag {
    weak: bool,
    opaque_tag: ~str,
}

pub fn weak_etag<S: Str>(opaque_tag: S) -> EntityTag {
    EntityTag {
        weak: true,
        opaque_tag: opaque_tag.into_owned(),
    }
}

pub fn strong_etag<S: Str>(opaque_tag: S) -> EntityTag {
    EntityTag {
        weak: false,
        opaque_tag: opaque_tag.into_owned(),
    }
}

impl ToStr for EntityTag {
    fn to_str(&self) -> ~str {
        if self.weak {
            push_quoted_string(~"W/", self.opaque_tag)
        } else {
            quoted_string(self.opaque_tag)
        }
    }
}

impl super::HeaderConvertible for EntityTag {
    fn from_stream<R: Reader>(reader: &mut super::HeaderValueByteIterator<R>) -> Option<EntityTag> {
        reader.some_if_consumed(EntityTag {
            weak: match reader.next() {
                Some(b) if b == 'W' as u8 => {
                    if reader.next() != '/' as u8 || reader.next() != '"' {
                        return None;
                    }
                    true
                },
                Some(b) if b == '"' as u8 => {
                    false
                },
                _ => {
                    return None;
                }
            },
            opaque_tag: match reader.read_quoted_string(true) {
                Some(tag) => tag,
                None => return None,
            }
        })
    }

    fn to_stream<W: Writer>(&self, writer: &mut W) {
        if self.weak {
            writer.write(bytes!("W/"));
        }
        writer.write_quoted_string(self.opaque_tag);
    }

    fn http_value(&self) -> ~str {
        self.to_str()
    }
}

#[test]
fn test_etag() {
    use headers::test_utils::*;
    assert_conversion_correct("\"\"", strong_etag(""));
    assert_conversion_correct("\"fO0\"", strong_etag("fO0"));
    assert_conversion_correct("\"fO0 bar\"", strong_etag("fO0 bar"));
    assert_conversion_correct("\"fO0 \\\"bar\"", strong_etag("fO0 \"bar"));
    assert_conversion_correct("\"fO0 \\\"bar\\\"\"", strong_etag("fO0 \"bar\""));

    assert_conversion_correct("W/\"\"", weak_etag(""));
    assert_conversion_correct("W/\"fO0\"", weak_etag("fO0"));
    assert_conversion_correct("W/\"fO0 bar\"", weak_etag("fO0 bar"));
    assert_conversion_correct("W/\"fO0 \\\"bar\"", weak_etag("fO0 \"bar"));
    assert_conversion_correct("W/\"fO0 \\\"bar\\\"\"", weak_etag("fO0 \"bar\""));
    assert_interpretation_correct("w/\"fO0\"", weak_etag("fO0"));

    assert_invalid::<EntityTag>("");
    assert_invalid::<EntityTag>("fO0");
    assert_invalid::<EntityTag>("\"\\\"");
    assert_invalid::<EntityTag>("\"\"\"\"");
}
<|endoftext|>


<commit_before>#![feature(std_misc, old_io, old_path)]

extern crate graphics;
extern crate glium;
extern crate glutin;
extern crate glium_graphics;
extern crate image;

use std::old_io::timer::sleep;
use std::time::duration::Duration;
use glium::{ DisplayBuild, Surface, Texture2d };
use glium_graphics::{ Glium2d, GliumGraphics, DrawTexture, OpenGL };
use graphics::{ RelativeTransform, default_draw_state };

fn main() {
    let window = glutin::WindowBuilder::new()
        .with_dimensions(300, 300)
        .with_title(format!("Image test"))
        .build_glium().unwrap();

    let rust_logo = DrawTexture::new({
        let image = image::open(&Path::new("assets/rust.png")).unwrap();
        Texture2d::new(&window, image)
    });

    let mut g2d = Glium2d::new(OpenGL::_3_2, &window);

    let draw_state = default_draw_state();

    loop {
        let mut target = window.draw();
        {
            let mut g = GliumGraphics::new(&mut g2d, &mut target);
            let (w, h) = window.get_framebuffer_dimensions();
            let transform = graphics::abs_transform(w as f64, h as f64);

            graphics::clear([1.0; 4], &mut g);
            graphics::Rectangle::new([1.0, 0.0, 0.0, 1.0])
                .draw([0.0, 0.0, 100.0, 100.0],
                      &draw_state,
                      transform,
                      &mut g);
            graphics::Rectangle::new([0.0, 1.0, 0.0, 0.3])
                .draw([50.0, 50.0, 100.0, 100.0],
                      &draw_state,
                      transform,
                      &mut g);
            graphics::image(&rust_logo, transform.trans(100.0, 100.0), &mut g);
        }
        target.finish();

        for _ in window.poll_events() {}
        if window.is_closed() {
            break
        }
        sleep(Duration::milliseconds(15));
    }
}
<commit_msg>Update image_test example to latest rust<commit_after>#![feature(std_misc, thread_sleep, old_path)]

extern crate graphics;
extern crate glium;
extern crate glutin;
extern crate glium_graphics;
extern crate image;

use std::old_path::*;

use std::thread::sleep;
use std::time::duration::Duration;
use glium::{ DisplayBuild, Surface, Texture2d };
use glium_graphics::{ Glium2d, GliumGraphics, DrawTexture, OpenGL };
use graphics::{ RelativeTransform, default_draw_state };

fn main() {
    let window = glutin::WindowBuilder::new()
        .with_dimensions(300, 300)
        .with_title("glium_graphics: image_test".to_string())
        .build_glium().unwrap();

    let rust_logo = DrawTexture::new({
        let image = image::open(&Path::new("assets/rust.png")).unwrap();
        Texture2d::new(&window, image)
    });

    let mut g2d = Glium2d::new(OpenGL::_3_2, &window);

    let draw_state = default_draw_state();

    loop {
        let mut target = window.draw();
        {
            let mut g = GliumGraphics::new(&mut g2d, &mut target);
            let (w, h) = window.get_framebuffer_dimensions();
            let transform = graphics::abs_transform(w as f64, h as f64);

            graphics::clear([1.0; 4], &mut g);
            graphics::Rectangle::new([1.0, 0.0, 0.0, 1.0])
                .draw([0.0, 0.0, 100.0, 100.0],
                      &draw_state,
                      transform,
                      &mut g);
            graphics::Rectangle::new([0.0, 1.0, 0.0, 0.3])
                .draw([50.0, 50.0, 100.0, 100.0],
                      &draw_state,
                      transform,
                      &mut g);
            graphics::image(&rust_logo, transform.trans(100.0, 100.0), &mut g);
        }
        target.finish();

        window.poll_events().last();
        if window.is_closed() {
            break
        }
        sleep(Duration::milliseconds(15));
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;

use glium::Surface;
use glium::glutin;

mod support;

#[derive(Copy, Clone, Debug)]
struct PerInstance {
    pub id: u32,
    pub w_position: (f32, f32, f32),
    pub color: (f32, f32, f32),
}
implement_vertex!(PerInstance, id, w_position, color);

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
        .with_depth_buffer(24)
        .build_glium()
        .unwrap();

    // building the vertex and index buffers
    let vertex_buffer = support::load_wavefront(&display, include_bytes!("support/teapot.obj"));

    // the program
    let program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                out vec3 v_normal;
                out vec3 v_color;

                void main() {
                    v_normal = normal;
                    v_color = color;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                in vec3 v_normal;
                in vec3 v_color;
                out vec4 f_color;

                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * v_color;
                    f_color = vec4(color, 1.0);
                }
            ",
        },
    ).unwrap();

    // the picking program
    let picking_program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                flat out uint v_id;

                void main() {
                    v_id = id;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                flat in uint v_id;
                out uint f_id;

                void main() {
                    f_id = v_id;
                }
            ",
        },
    ).unwrap();

    let mut camera = support::camera::CameraState::new();
    camera.set_position((0.0, 0.0, 1.5));
    camera.set_direction((0.0, 0.0, 1.0));

    //id's must be unique and != 0
    let mut per_instance = vec![
        PerInstance { id: 1, w_position: (-1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 2, w_position: ( 0.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 3, w_position: ( 1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
    ];
    per_instance.sort_by(|a, b| a.id.cmp(&b.id));
    let original = per_instance.clone();

    let mut picking_attachments: Option<(glium::texture::UnsignedTexture2d, glium::framebuffer::DepthRenderBuffer)> = None;
    let picking_pbo: glium::texture::pixel_buffer::PixelBuffer<u32>
        = glium::texture::pixel_buffer::PixelBuffer::new_empty(&display, 1);

    let mut cursor_position: Option<(i32, i32)> = None;

    // the main loop
    support::start_loop(|| {
        camera.update();

        // determing which object has been picked at the previous frame
        let picked_object = {
            let data = picking_pbo.read().map(|d| d[0]).unwrap_or(0);
            if data != 0 {
                per_instance.binary_search_by(|x| x.id.cmp(&data)).ok()
            } else {
                None
            }
        };

        per_instance = original.clone();
        if let Some(index) = picked_object {
            per_instance[index as usize] = PerInstance {
                id: per_instance[index as usize].id,
                w_position: per_instance[index as usize].w_position,
                color: (0.0, 1.0, 0.0)
            };
        }

        // building the uniforms
        let uniforms = uniform! {
            persp_matrix: camera.get_perspective(),
            view_matrix: camera.get_view(),
        };

        // draw parameters
        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: glium::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        let per_instance_buffer = glium::vertex::VertexBuffer::new(&display, &per_instance).unwrap();

        // drawing a frame
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);

        //update picking texture
        if picking_attachments.is_none() || (
            picking_attachments.as_ref().unwrap().0.get_width(),
            picking_attachments.as_ref().unwrap().0.get_height().unwrap()
        ) != target.get_dimensions() {
            let (width, height) = target.get_dimensions();
            picking_attachments = Some((
                glium::texture::UnsignedTexture2d::empty_with_format(
                    &display,
                    glium::texture::UncompressedUintFormat::U32,
                    glium::texture::MipmapsOption::NoMipmap,
                    width, height,
                ).unwrap(),
                glium::framebuffer::DepthRenderBuffer::new(
                    &display,
                    glium::texture::DepthFormat::F32,
                    width, height,
                ).unwrap()
            ))
        }

        // drawing the models and pass the picking texture
        if let Some((ref picking_texture, ref depth_buffer)) = picking_attachments {
            //clearing the picking texture
            picking_texture.main_level().first_layer().into_image(None).unwrap().raw_clear_buffer([0u32, 0, 0, 0]);

            let mut picking_target = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display, picking_texture, depth_buffer).unwrap();
            picking_target.clear_depth(1.0);
            picking_target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                        &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                        &picking_program, &uniforms, &params).unwrap();
        }
        target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                    &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms, &params).unwrap();
        target.finish().unwrap();

        // committing into the picking pbo
        if let (Some(cursor), Some(&(ref picking_texture, _))) = (cursor_position, picking_attachments.as_ref()) {
            let read_target = glium::Rect {
                left: cursor.0 as u32 - 1,
                bottom: picking_texture.get_height().unwrap() - cursor.1 as u32,
                width: 1,
                height: 1,
            };

            if read_target.left < picking_texture.get_width()
            && read_target.bottom < picking_texture.get_height().unwrap() {
                picking_texture.main_level()
                    .first_layer()
                    .into_image(None).unwrap()
                    .raw_read_to_pixel_buffer(&read_target, &picking_pbo);
            } else {
                picking_pbo.write(&[0]);
            }
        } else {
            picking_pbo.write(&[0]);
        }

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return support::Action::Stop,
                glutin::Event::MouseMoved(m) => cursor_position = Some(m),
                ev => camera.process_input(&ev),
            }
        }

        support::Action::Continue
    });
}
<commit_msg>fixed off by one error for y-axis and overflow conditions<commit_after>#[macro_use]
extern crate glium;

use glium::Surface;
use glium::glutin;

mod support;

#[derive(Copy, Clone, Debug)]
struct PerInstance {
    pub id: u32,
    pub w_position: (f32, f32, f32),
    pub color: (f32, f32, f32),
}
implement_vertex!(PerInstance, id, w_position, color);

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
        .with_depth_buffer(24)
        .build_glium()
        .unwrap();

    // building the vertex and index buffers
    let vertex_buffer = support::load_wavefront(&display, include_bytes!("support/teapot.obj"));

    // the program
    let program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                out vec3 v_normal;
                out vec3 v_color;

                void main() {
                    v_normal = normal;
                    v_color = color;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                in vec3 v_normal;
                in vec3 v_color;
                out vec4 f_color;

                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * v_color;
                    f_color = vec4(color, 1.0);
                }
            ",
        },
    ).unwrap();

    // the picking program
    let picking_program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                flat out uint v_id;

                void main() {
                    v_id = id;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                flat in uint v_id;
                out uint f_id;

                void main() {
                    f_id = v_id;
                }
            ",
        },
    ).unwrap();

    let mut camera = support::camera::CameraState::new();
    camera.set_position((0.0, 0.0, 1.5));
    camera.set_direction((0.0, 0.0, 1.0));

    //id's must be unique and != 0
    let mut per_instance = vec![
        PerInstance { id: 1, w_position: (-1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 2, w_position: ( 0.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 3, w_position: ( 1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
    ];
    per_instance.sort_by(|a, b| a.id.cmp(&b.id));
    let original = per_instance.clone();

    let mut picking_attachments: Option<(glium::texture::UnsignedTexture2d, glium::framebuffer::DepthRenderBuffer)> = None;
    let picking_pbo: glium::texture::pixel_buffer::PixelBuffer<u32>
        = glium::texture::pixel_buffer::PixelBuffer::new_empty(&display, 1);

    let mut cursor_position: Option<(i32, i32)> = None;

    // the main loop
    support::start_loop(|| {
        camera.update();

        // determing which object has been picked at the previous frame
        let picked_object = {
            let data = picking_pbo.read().map(|d| d[0]).unwrap_or(0);
            if data != 0 {
                per_instance.binary_search_by(|x| x.id.cmp(&data)).ok()
            } else {
                None
            }
        };

        per_instance = original.clone();
        if let Some(index) = picked_object {
            per_instance[index as usize] = PerInstance {
                id: per_instance[index as usize].id,
                w_position: per_instance[index as usize].w_position,
                color: (0.0, 1.0, 0.0)
            };
        }

        // building the uniforms
        let uniforms = uniform! {
            persp_matrix: camera.get_perspective(),
            view_matrix: camera.get_view(),
        };

        // draw parameters
        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: glium::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        let per_instance_buffer = glium::vertex::VertexBuffer::new(&display, &per_instance).unwrap();

        // drawing a frame
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);

        //update picking texture
        if picking_attachments.is_none() || (
            picking_attachments.as_ref().unwrap().0.get_width(),
            picking_attachments.as_ref().unwrap().0.get_height().unwrap()
        ) != target.get_dimensions() {
            let (width, height) = target.get_dimensions();
            picking_attachments = Some((
                glium::texture::UnsignedTexture2d::empty_with_format(
                    &display,
                    glium::texture::UncompressedUintFormat::U32,
                    glium::texture::MipmapsOption::NoMipmap,
                    width, height,
                ).unwrap(),
                glium::framebuffer::DepthRenderBuffer::new(
                    &display,
                    glium::texture::DepthFormat::F32,
                    width, height,
                ).unwrap()
            ))
        }

        // drawing the models and pass the picking texture
        if let Some((ref picking_texture, ref depth_buffer)) = picking_attachments {
            //clearing the picking texture
            picking_texture.main_level().first_layer().into_image(None).unwrap().raw_clear_buffer([0u32, 0, 0, 0]);

            let mut picking_target = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display, picking_texture, depth_buffer).unwrap();
            picking_target.clear_depth(1.0);
            picking_target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                        &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                        &picking_program, &uniforms, &params).unwrap();
        }
        target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                    &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms, &params).unwrap();
        target.finish().unwrap();

        // committing into the picking pbo
        if let (Some(cursor), Some(&(ref picking_texture, _))) = (cursor_position, picking_attachments.as_ref()) {
            let read_target = glium::Rect {
                left: (cursor.0 - 1) as u32,
                bottom: picking_texture.get_height().unwrap() - std::cmp::max(cursor.1 - 1, 0) as u32,
                width: 1,
                height: 1,
            };

            if read_target.left < picking_texture.get_width()
            && read_target.bottom < picking_texture.get_height().unwrap() {
                picking_texture.main_level()
                    .first_layer()
                    .into_image(None).unwrap()
                    .raw_read_to_pixel_buffer(&read_target, &picking_pbo);
            } else {
                picking_pbo.write(&[0]);
            }
        } else {
            picking_pbo.write(&[0]);
        }

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return support::Action::Stop,
                glutin::Event::MouseMoved(m) => cursor_position = Some(m),
                ev => camera.process_input(&ev),
            }
        }

        support::Action::Continue
    });
}
<|endoftext|>


<commit_before>// Copyright 2013-2015 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.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
mod imp {
    use self::OsRngInner::*;

    use fs::File;
    use io;
    use libc;
    use mem;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use sys::os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc",
                  target_arch = "powerpc64")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;
        #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
        const NR_GETRANDOM: libc::c_long = 359;
        #[cfg(target_arch = "aarch64")]
        const NR_GETRANDOM: libc::c_long = 278;

        const GRND_NONBLOCK: libc::c_uint = 0x0001;

        unsafe {
            libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc",
                      target_arch = "powerpc64"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::EAGAIN {
                    // if getrandom() returns EAGAIN it would have blocked
                    // because the non-blocking pool (urandom) has not
                    // initialized in the kernel yet due to a lack of entropy
                    // the fallback we do here is to avoid blocking applications
                    // which could depend on this call without ever knowing
                    // they do and don't have a work around. The PRNG of
                    // /dev/urandom will still be used but not over a completely
                    // full entropy pool
                    let reader = File::open("/dev/urandom").expect("Unable to open /dev/urandom");
                    let mut reader_rng = ReaderRng::new(reader);
                    reader_rng.fill_bytes(& mut v[read..]);
                    read += v.len() as usize;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc",
                  target_arch = "powerpc64")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, Ordering};
        use sync::Once;

        static CHECKER: Once = Once::new();
        static AVAILABLE: AtomicBool = AtomicBool::new(false);

        CHECKER.call_once(|| {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = io::Error::last_os_error().raw_os_error();
                err != Some(libc::ENOSYS)
            } else {
                true
            };
            AVAILABLE.store(available, Ordering::Relaxed);
        });

        AVAILABLE.load(Ordering::Relaxed)
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc",
                      target_arch = "powerpc64"))))]
    fn is_getrandom_available() -> bool { false }

    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = File::open("/dev/urandom")?;
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use io;
    use libc;
    use mem;
    use sys::os::errno;
    use rand::Rng;

    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside
        // of this module
        _dummy: (),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            // getentropy(2) permits a maximum buffer size of 256 bytes
            for s in v.chunks_mut(256) {
                let ret = unsafe {
                    libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
                };
                if ret == -1 {
                    panic!("unexpected getentropy error: {}", errno());
                }
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    use io;
    use mem;
    use ptr;
    use rand::Rng;
    use libc::{c_int, size_t};

    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside
        // of this module
        _dummy: (),
    }

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    #[link(name = "Security", kind = "framework")]
    #[cfg(not(cargobuild))]
    extern {}

    extern {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t,
                                   v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}",
                       io::Error::last_os_error());
            }
        }
    }
}
<commit_msg>Auto merge of #35884 - habnabit:freebsd-arc4rand, r=alexcrichton<commit_after>// Copyright 2013-2015 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.

pub use self::imp::OsRng;

use mem;

fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 {
    let mut buf: [u8; 4] = [0; 4];
    fill_buf(&mut buf);
    unsafe { mem::transmute::<[u8; 4], u32>(buf) }
}

fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 {
    let mut buf: [u8; 8] = [0; 8];
    fill_buf(&mut buf);
    unsafe { mem::transmute::<[u8; 8], u64>(buf) }
}

#[cfg(all(unix,
          not(target_os = "ios"),
          not(target_os = "openbsd"),
          not(target_os = "freebsd")))]
mod imp {
    use self::OsRngInner::*;
    use super::{next_u32, next_u64};

    use fs::File;
    use io;
    use libc;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use sys::os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc",
                  target_arch = "powerpc64")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;
        #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
        const NR_GETRANDOM: libc::c_long = 359;
        #[cfg(target_arch = "aarch64")]
        const NR_GETRANDOM: libc::c_long = 278;

        const GRND_NONBLOCK: libc::c_uint = 0x0001;

        unsafe {
            libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc",
                      target_arch = "powerpc64"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::EAGAIN {
                    // if getrandom() returns EAGAIN it would have blocked
                    // because the non-blocking pool (urandom) has not
                    // initialized in the kernel yet due to a lack of entropy
                    // the fallback we do here is to avoid blocking applications
                    // which could depend on this call without ever knowing
                    // they do and don't have a work around. The PRNG of
                    // /dev/urandom will still be used but not over a completely
                    // full entropy pool
                    let reader = File::open("/dev/urandom").expect("Unable to open /dev/urandom");
                    let mut reader_rng = ReaderRng::new(reader);
                    reader_rng.fill_bytes(& mut v[read..]);
                    read += v.len() as usize;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc",
                  target_arch = "powerpc64")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, Ordering};
        use sync::Once;

        static CHECKER: Once = Once::new();
        static AVAILABLE: AtomicBool = AtomicBool::new(false);

        CHECKER.call_once(|| {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = io::Error::last_os_error().raw_os_error();
                err != Some(libc::ENOSYS)
            } else {
                true
            };
            AVAILABLE.store(available, Ordering::Relaxed);
        });

        AVAILABLE.load(Ordering::Relaxed)
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc",
                      target_arch = "powerpc64"))))]
    fn is_getrandom_available() -> bool { false }

    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = File::open("/dev/urandom")?;
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => next_u32(&mut getrandom_fill_bytes),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => next_u64(&mut getrandom_fill_bytes),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use super::{next_u32, next_u64};

    use io;
    use libc;
    use sys::os::errno;
    use rand::Rng;

    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside
        // of this module
        _dummy: (),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            next_u32(&mut |v| self.fill_bytes(v))
        }
        fn next_u64(&mut self) -> u64 {
            next_u64(&mut |v| self.fill_bytes(v))
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            // getentropy(2) permits a maximum buffer size of 256 bytes
            for s in v.chunks_mut(256) {
                let ret = unsafe {
                    libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
                };
                if ret == -1 {
                    panic!("unexpected getentropy error: {}", errno());
                }
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    use super::{next_u32, next_u64};

    use io;
    use ptr;
    use rand::Rng;
    use libc::{c_int, size_t};

    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside
        // of this module
        _dummy: (),
    }

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    #[link(name = "Security", kind = "framework")]
    #[cfg(not(cargobuild))]
    extern {}

    extern {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            next_u32(&mut |v| self.fill_bytes(v))
        }
        fn next_u64(&mut self) -> u64 {
            next_u64(&mut |v| self.fill_bytes(v))
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t,
                                   v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}",
                       io::Error::last_os_error());
            }
        }
    }
}

#[cfg(target_os = "freebsd")]
mod imp {
    use super::{next_u32, next_u64};

    use io;
    use libc;
    use rand::Rng;
    use ptr;

    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside
        // of this module
        _dummy: (),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            next_u32(&mut |v| self.fill_bytes(v))
        }
        fn next_u64(&mut self) -> u64 {
            next_u64(&mut |v| self.fill_bytes(v))
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let mib = [libc::CTL_KERN, libc::KERN_ARND];
            // kern.arandom permits a maximum buffer size of 256 bytes
            for s in v.chunks_mut(256) {
                let mut s_len = s.len();
                let ret = unsafe {
                    libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
                                 s.as_mut_ptr() as *mut _, &mut s_len,
                                 ptr::null(), 0)
                };
                if ret == -1 || s_len != s.len() {
                    panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                           ret, s.len(), s_len);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

use cast;
use libc;
use option::*;
use task;
use task::atomically;
use unstable::finally::Finally;
use unstable::intrinsics;
use ops::Drop;
use clone::Clone;
use kinds::Send;

/// An atomically reference counted pointer.
///
/// Enforces no shared-memory safety.
pub struct UnsafeAtomicRcBox<T> {
    data: *mut libc::c_void,
}

struct AtomicRcBoxData<T> {
    count: int,
    data: Option<T>,
}

impl<T: Send> UnsafeAtomicRcBox<T> {
    pub fn new(data: T) -> UnsafeAtomicRcBox<T> {
        unsafe {
            let data = ~AtomicRcBoxData { count: 1, data: Some(data) };
            let ptr = cast::transmute(data);
            return UnsafeAtomicRcBox { data: ptr };
        }
    }

    #[inline]
    pub unsafe fn get(&self) -> *mut T
    {
        let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
        assert!(data.count > 0);
        let r: *mut T = data.data.get_mut_ref();
        cast::forget(data);
        return r;
    }

    #[inline]
    pub unsafe fn get_immut(&self) -> *T
    {
        let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
        assert!(data.count > 0);
        let r: *T = cast::transmute_immut(data.data.get_mut_ref());
        cast::forget(data);
        return r;
    }
}

impl<T: Send> Clone for UnsafeAtomicRcBox<T> {
    fn clone(&self) -> UnsafeAtomicRcBox<T> {
        unsafe {
            let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
            let new_count = intrinsics::atomic_xadd(&mut data.count, 1) + 1;
            assert!(new_count >= 2);
            cast::forget(data);
            return UnsafeAtomicRcBox { data: self.data };
        }
    }
}

#[unsafe_destructor]
impl<T> Drop for UnsafeAtomicRcBox<T>{
    fn drop(&self) {
        unsafe {
            do task::unkillable {
                let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
                let new_count = intrinsics::atomic_xsub(&mut data.count, 1) - 1;
                assert!(new_count >= 0);
                if new_count == 0 {
                    // drop glue takes over.
                } else {
                    cast::forget(data);
                }
            }
        }
    }
}

/****************************************************************************/

#[allow(non_camel_case_types)] // runtime type
pub type rust_little_lock = *libc::c_void;

struct LittleLock {
    l: rust_little_lock,
}

impl Drop for LittleLock {
    fn drop(&self) {
        unsafe {
            rust_destroy_little_lock(self.l);
        }
    }
}

fn LittleLock() -> LittleLock {
    unsafe {
        LittleLock {
            l: rust_create_little_lock()
        }
    }
}

impl LittleLock {
    #[inline]
    pub unsafe fn lock<T>(&self, f: &fn() -> T) -> T {
        do atomically {
            rust_lock_little_lock(self.l);
            do (|| {
                f()
            }).finally {
                rust_unlock_little_lock(self.l);
            }
        }
    }
}

struct ExData<T> {
    lock: LittleLock,
    failed: bool,
    data: T,
}

/**
 * An arc over mutable data that is protected by a lock. For library use only.
 */
pub struct Exclusive<T> {
    x: UnsafeAtomicRcBox<ExData<T>>
}

pub fn exclusive<T:Send>(user_data: T) -> Exclusive<T> {
    let data = ExData {
        lock: LittleLock(),
        failed: false,
        data: user_data
    };
    Exclusive {
        x: UnsafeAtomicRcBox::new(data)
    }
}

impl<T:Send> Clone for Exclusive<T> {
    // Duplicate an exclusive ARC, as std::arc::clone.
    fn clone(&self) -> Exclusive<T> {
        Exclusive { x: self.x.clone() }
    }
}

impl<T:Send> Exclusive<T> {
    // Exactly like std::arc::mutex_arc,access(), but with the little_lock
    // instead of a proper mutex. Same reason for being unsafe.
    //
    // Currently, scheduling operations (i.e., yielding, receiving on a pipe,
    // accessing the provided condition variable) are prohibited while inside
    // the exclusive. Supporting that is a work in progress.
    #[inline]
    pub unsafe fn with<U>(&self, f: &fn(x: &mut T) -> U) -> U {
        let rec = self.x.get();
        do (*rec).lock.lock {
            if (*rec).failed {
                fail!("Poisoned exclusive - another task failed inside!");
            }
            (*rec).failed = true;
            let result = f(&mut (*rec).data);
            (*rec).failed = false;
            result
        }
    }

    #[inline]
    pub unsafe fn with_imm<U>(&self, f: &fn(x: &T) -> U) -> U {
        do self.with |x| {
            f(cast::transmute_immut(x))
        }
    }
}

fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool {
    unsafe {
        let old = intrinsics::atomic_cxchg(address, oldval, newval);
        old == oldval
    }
}

extern {
    fn rust_create_little_lock() -> rust_little_lock;
    fn rust_destroy_little_lock(lock: rust_little_lock);
    fn rust_lock_little_lock(lock: rust_little_lock);
    fn rust_unlock_little_lock(lock: rust_little_lock);
}

/* *********************************************************************/

//FIXME: #5042 This should be replaced by proper atomic type
pub struct AtomicUint {
    priv inner: uint
}

impl AtomicUint {
    pub fn new(val: uint) -> AtomicUint { AtomicUint { inner: val } }
    pub fn load(&self) -> uint {
        unsafe { intrinsics::atomic_load(cast::transmute(self)) as uint }
    }
    pub fn store(&mut self, val: uint) {
        unsafe { intrinsics::atomic_store(cast::transmute(self), val as int); }
    }
    pub fn add(&mut self, val: int) -> uint {
        unsafe { intrinsics::atomic_xadd(cast::transmute(self), val as int) as uint }
    }
    pub fn cas(&mut self, old:uint, new: uint) -> uint {
        unsafe { intrinsics::atomic_cxchg(cast::transmute(self), old as int, new as int) as uint }
    }
}

pub struct AtomicInt {
    priv inner: int
}

impl AtomicInt {
    pub fn new(val: int) -> AtomicInt { AtomicInt { inner: val } }
    pub fn load(&self) -> int {
        unsafe { intrinsics::atomic_load(&self.inner) }
    }
    pub fn store(&mut self, val: int) {
        unsafe { intrinsics::atomic_store(&mut self.inner, val); }
    }
    pub fn add(&mut self, val: int) -> int {
        unsafe { intrinsics::atomic_xadd(&mut self.inner, val) }
    }
    pub fn cas(&mut self, old: int, new: int) -> int {
        unsafe { intrinsics::atomic_cxchg(&mut self.inner, old, new) }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use comm;
    use super::exclusive;
    use task;
    use uint;

    #[test]
    fn exclusive_arc() {
        unsafe {
            let mut futures = ~[];

            let num_tasks = 10;
            let count = 10;

            let total = exclusive(~0);

            for uint::range(0, num_tasks) |_i| {
                let total = total.clone();
                let (port, chan) = comm::stream();
                futures.push(port);

                do task::spawn || {
                    for uint::range(0, count) |_i| {
                        do total.with |count| {
                            **count += 1;
                        }
                    }
                    chan.send(());
                }
            };

            for futures.iter().advance |f| { f.recv() }

            do total.with |total| {
                assert!(**total == num_tasks * count)
            };
        }
    }

    #[test] #[should_fail] #[ignore(cfg(windows))]
    fn exclusive_poison() {
        unsafe {
            // Tests that if one task fails inside of an exclusive, subsequent
            // accesses will also fail.
            let x = exclusive(1);
            let x2 = x.clone();
            do task::try || {
                do x2.with |one| {
                    assert_eq!(*one, 2);
                }
            };
            do x.with |one| {
                assert_eq!(*one, 1);
            }
        }
    }

    #[test]
    fn atomic_int_smoke_test() {
        let mut i = AtomicInt::new(0);
        i.store(10);
        assert!(i.load() == 10);
        assert!(i.add(1) == 10);
        assert!(i.load() == 11);
        assert!(i.cas(11, 12) == 11);
        assert!(i.cas(11, 13) == 12);
        assert!(i.load() == 12);
    }

    #[test]
    fn atomic_uint_smoke_test() {
        let mut i = AtomicUint::new(0);
        i.store(10);
        assert!(i.load() == 10);
        assert!(i.add(1) == 10);
        assert!(i.load() == 11);
        assert!(i.cas(11, 12) == 11);
        assert!(i.cas(11, 13) == 12);
        assert!(i.load() == 12);
    }
}
<commit_msg>Remove redundant Atomic{Ui,I}nt types from unstable::sync<commit_after>// Copyright 2013 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.

use cast;
use libc;
use option::*;
use task;
use task::atomically;
use unstable::finally::Finally;
use unstable::intrinsics;
use ops::Drop;
use clone::Clone;
use kinds::Send;

/// An atomically reference counted pointer.
///
/// Enforces no shared-memory safety.
pub struct UnsafeAtomicRcBox<T> {
    data: *mut libc::c_void,
}

struct AtomicRcBoxData<T> {
    count: int,
    data: Option<T>,
}

impl<T: Send> UnsafeAtomicRcBox<T> {
    pub fn new(data: T) -> UnsafeAtomicRcBox<T> {
        unsafe {
            let data = ~AtomicRcBoxData { count: 1, data: Some(data) };
            let ptr = cast::transmute(data);
            return UnsafeAtomicRcBox { data: ptr };
        }
    }

    #[inline]
    pub unsafe fn get(&self) -> *mut T
    {
        let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
        assert!(data.count > 0);
        let r: *mut T = data.data.get_mut_ref();
        cast::forget(data);
        return r;
    }

    #[inline]
    pub unsafe fn get_immut(&self) -> *T
    {
        let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
        assert!(data.count > 0);
        let r: *T = cast::transmute_immut(data.data.get_mut_ref());
        cast::forget(data);
        return r;
    }
}

impl<T: Send> Clone for UnsafeAtomicRcBox<T> {
    fn clone(&self) -> UnsafeAtomicRcBox<T> {
        unsafe {
            let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
            let new_count = intrinsics::atomic_xadd(&mut data.count, 1) + 1;
            assert!(new_count >= 2);
            cast::forget(data);
            return UnsafeAtomicRcBox { data: self.data };
        }
    }
}

#[unsafe_destructor]
impl<T> Drop for UnsafeAtomicRcBox<T>{
    fn drop(&self) {
        unsafe {
            do task::unkillable {
                let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
                let new_count = intrinsics::atomic_xsub(&mut data.count, 1) - 1;
                assert!(new_count >= 0);
                if new_count == 0 {
                    // drop glue takes over.
                } else {
                    cast::forget(data);
                }
            }
        }
    }
}

/****************************************************************************/

#[allow(non_camel_case_types)] // runtime type
pub type rust_little_lock = *libc::c_void;

struct LittleLock {
    l: rust_little_lock,
}

impl Drop for LittleLock {
    fn drop(&self) {
        unsafe {
            rust_destroy_little_lock(self.l);
        }
    }
}

fn LittleLock() -> LittleLock {
    unsafe {
        LittleLock {
            l: rust_create_little_lock()
        }
    }
}

impl LittleLock {
    #[inline]
    pub unsafe fn lock<T>(&self, f: &fn() -> T) -> T {
        do atomically {
            rust_lock_little_lock(self.l);
            do (|| {
                f()
            }).finally {
                rust_unlock_little_lock(self.l);
            }
        }
    }
}

struct ExData<T> {
    lock: LittleLock,
    failed: bool,
    data: T,
}

/**
 * An arc over mutable data that is protected by a lock. For library use only.
 */
pub struct Exclusive<T> {
    x: UnsafeAtomicRcBox<ExData<T>>
}

pub fn exclusive<T:Send>(user_data: T) -> Exclusive<T> {
    let data = ExData {
        lock: LittleLock(),
        failed: false,
        data: user_data
    };
    Exclusive {
        x: UnsafeAtomicRcBox::new(data)
    }
}

impl<T:Send> Clone for Exclusive<T> {
    // Duplicate an exclusive ARC, as std::arc::clone.
    fn clone(&self) -> Exclusive<T> {
        Exclusive { x: self.x.clone() }
    }
}

impl<T:Send> Exclusive<T> {
    // Exactly like std::arc::mutex_arc,access(), but with the little_lock
    // instead of a proper mutex. Same reason for being unsafe.
    //
    // Currently, scheduling operations (i.e., yielding, receiving on a pipe,
    // accessing the provided condition variable) are prohibited while inside
    // the exclusive. Supporting that is a work in progress.
    #[inline]
    pub unsafe fn with<U>(&self, f: &fn(x: &mut T) -> U) -> U {
        let rec = self.x.get();
        do (*rec).lock.lock {
            if (*rec).failed {
                fail!("Poisoned exclusive - another task failed inside!");
            }
            (*rec).failed = true;
            let result = f(&mut (*rec).data);
            (*rec).failed = false;
            result
        }
    }

    #[inline]
    pub unsafe fn with_imm<U>(&self, f: &fn(x: &T) -> U) -> U {
        do self.with |x| {
            f(cast::transmute_immut(x))
        }
    }
}

fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool {
    unsafe {
        let old = intrinsics::atomic_cxchg(address, oldval, newval);
        old == oldval
    }
}

extern {
    fn rust_create_little_lock() -> rust_little_lock;
    fn rust_destroy_little_lock(lock: rust_little_lock);
    fn rust_lock_little_lock(lock: rust_little_lock);
    fn rust_unlock_little_lock(lock: rust_little_lock);
}

#[cfg(test)]
mod tests {
    use super::*;
    use comm;
    use super::exclusive;
    use task;
    use uint;

    #[test]
    fn exclusive_arc() {
        unsafe {
            let mut futures = ~[];

            let num_tasks = 10;
            let count = 10;

            let total = exclusive(~0);

            for uint::range(0, num_tasks) |_i| {
                let total = total.clone();
                let (port, chan) = comm::stream();
                futures.push(port);

                do task::spawn || {
                    for uint::range(0, count) |_i| {
                        do total.with |count| {
                            **count += 1;
                        }
                    }
                    chan.send(());
                }
            };

            for futures.iter().advance |f| { f.recv() }

            do total.with |total| {
                assert!(**total == num_tasks * count)
            };
        }
    }

    #[test] #[should_fail] #[ignore(cfg(windows))]
    fn exclusive_poison() {
        unsafe {
            // Tests that if one task fails inside of an exclusive, subsequent
            // accesses will also fail.
            let x = exclusive(1);
            let x2 = x.clone();
            do task::try || {
                do x2.with |one| {
                    assert_eq!(*one, 2);
                }
            };
            do x.with |one| {
                assert_eq!(*one, 1);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! [GET /_matrix/federation/v1/state/{roomId}](https://matrix.org/docs/spec/server_server/r0.1.4#get-matrix-federation-v1-state-roomid)

use ruma_api::ruma_api;
use ruma_events::pdu::Pdu;
use ruma_identifiers::{EventId, RoomId};

ruma_api! {
    metadata: {
        description: "Retrieves a snapshot of a room's state at a given event.",
        method: GET,
        name: "get_room_state",
        path: "/_matrix/federation/v1/state/:room_id",
        rate_limited: false,
        authentication: ServerSignatures,
    }

    request: {
        /// The room ID to get state for.
        #[ruma_api(path)]
        pub room_id: &'a RoomId,

        /// An event ID in the room to retrieve the state at.
        #[ruma_api(query)]
        pub event_id: &'a EventId,
    }

    response: {
        /// The full set of authorization events that make up the state of the
        /// room, and their authorization events, recursively.
        pub auth_chain: Vec<Pdu>,

        /// The fully resolved state of the room at the given event.
        pub pdus: Vec<Pdu>,
    }
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given event ID and room ID.
    pub fn new(event_id: &'a EventId, room_id: &'a RoomId) -> Self {
        Self { event_id, room_id }
    }
}

impl Response {
    /// Creates a new `Response` with the given auth chain and room state.
    pub fn new(auth_chain: Vec<Pdu>, pdus: Vec<Pdu>) -> Self {
        Self { auth_chain, pdus }
    }
}
<commit_msg>Add Raw wrapper to get_room_state endpoint<commit_after>//! [GET /_matrix/federation/v1/state/{roomId}](https://matrix.org/docs/spec/server_server/r0.1.4#get-matrix-federation-v1-state-roomid)

use ruma_api::ruma_api;
use ruma_common::Raw;
use ruma_events::pdu::Pdu;
use ruma_identifiers::{EventId, RoomId};

ruma_api! {
    metadata: {
        description: "Retrieves a snapshot of a room's state at a given event.",
        method: GET,
        name: "get_room_state",
        path: "/_matrix/federation/v1/state/:room_id",
        rate_limited: false,
        authentication: ServerSignatures,
    }

    request: {
        /// The room ID to get state for.
        #[ruma_api(path)]
        pub room_id: &'a RoomId,

        /// An event ID in the room to retrieve the state at.
        #[ruma_api(query)]
        pub event_id: &'a EventId,
    }

    response: {
        /// The full set of authorization events that make up the state of the
        /// room, and their authorization events, recursively.
        pub auth_chain: Vec<Raw<Pdu>>,

        /// The fully resolved state of the room at the given event.
        pub pdus: Vec<Raw<Pdu>>,
    }
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given event ID and room ID.
    pub fn new(event_id: &'a EventId, room_id: &'a RoomId) -> Self {
        Self { event_id, room_id }
    }
}

impl Response {
    /// Creates a new `Response` with the given auth chain and room state.
    pub fn new(auth_chain: Vec<Raw<Pdu>>, pdus: Vec<Raw<Pdu>>) -> Self {
        Self { auth_chain, pdus }
    }
}
<|endoftext|>