<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! This module implements the virtio video encoder and decoder devices.
//! The current implementation uses [v3 RFC] of the virtio-video protocol.
//!
//! [v3 RFC]: https://markmail.org/thread/wxdne5re7aaugbjg

use std::thread;

#[cfg(feature = "video-encoder")]
use base::info;
use base::{error, AsRawDescriptor, Error as SysError, Event, RawDescriptor, Tube};
use data_model::{DataInit, Le32};
use remain::sorted;
use thiserror::Error;
use vm_memory::GuestMemory;

use crate::virtio::virtio_device::VirtioDevice;
use crate::virtio::{self, copy_config, DescriptorError, DeviceType, Interrupt};

#[macro_use]
mod macros;
mod async_cmd_desc_map;
mod command;
mod control;
#[cfg(feature = "video-decoder")]
mod decoder;
mod device;
#[cfg(feature = "video-encoder")]
mod encoder;
mod error;
mod event;
mod format;
mod params;
mod protocol;
mod resource;
mod response;
mod worker;

#[cfg(all(feature = "video-decoder", not(feature = "libvda")))]
compile_error!("The \"video-decoder\" feature requires \"libvda\" to also be enabled.");

#[cfg(all(feature = "video-encoder", not(feature = "libvda")))]
compile_error!("The \"video-encoder\" feature requires \"libvda\" to also be enabled.");

#[cfg(feature = "libvda")]
mod vda;

use command::ReadCmdError;
use device::Device;
use worker::Worker;

const QUEUE_SIZE: u16 = 256;
const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE, QUEUE_SIZE];

/// An error indicating something went wrong in virtio-video's worker.
#[sorted]
#[derive(Error, Debug)]
pub enum Error {
    /// No available descriptor in which an event is written to.
    #[error("no available descriptor in which an event is written to")]
    DescriptorNotAvailable,
    /// A DescriptorChain contains invalid data.
    #[error("DescriptorChain contains invalid data: {0}")]
    InvalidDescriptorChain(DescriptorError),
    /// Failed to read a virtio-video command.
    #[error("failed to read a command from the guest: {0}")]
    ReadFailure(ReadCmdError),
    /// Creating WaitContext failed.
    #[error("failed to create WaitContext: {0}")]
    WaitContextCreationFailed(SysError),
    /// Error while polling for events.
    #[error("failed to wait for events: {0}")]
    WaitError(SysError),
    /// Failed to write an event into the event queue.
    #[error("failed to write an event {event:?} into event queue: {error}")]
    WriteEventFailure {
        event: event::VideoEvt,
        error: std::io::Error,
    },
}

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub enum VideoDeviceType {
    #[cfg(feature = "video-decoder")]
    Decoder,
    #[cfg(feature = "video-encoder")]
    Encoder,
}

pub struct VideoDevice {
    device_type: VideoDeviceType,
    backend: VideoBackendType,
    kill_evt: Option<Event>,
    resource_bridge: Option<Tube>,
    base_features: u64,
}

impl VideoDevice {
    pub fn new(
        base_features: u64,
        device_type: VideoDeviceType,
        backend: VideoBackendType,
        resource_bridge: Option<Tube>,
    ) -> VideoDevice {
        VideoDevice {
            device_type,
            backend,
            kill_evt: None,
            resource_bridge,
            base_features,
        }
    }
}

impl Drop for VideoDevice {
    fn drop(&mut self) {
        if let Some(kill_evt) = self.kill_evt.take() {
            // Ignore the result because there is nothing we can do about it.
            let _ = kill_evt.write(1);
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum VideoBackendType {
    #[cfg(feature = "libvda")]
    Libvda,
    #[cfg(feature = "libvda")]
    LibvdaVd,
}

impl VirtioDevice for VideoDevice {
    fn keep_rds(&self) -> Vec<RawDescriptor> {
        let mut keep_rds = Vec::new();
        if let Some(resource_bridge) = &self.resource_bridge {
            keep_rds.push(resource_bridge.as_raw_descriptor());
        }
        keep_rds
    }

    fn device_type(&self) -> DeviceType {
        match &self.device_type {
            #[cfg(feature = "video-decoder")]
            VideoDeviceType::Decoder => DeviceType::VideoDec,
            #[cfg(feature = "video-encoder")]
            VideoDeviceType::Encoder => DeviceType::VideoEnc,
        }
    }

    fn queue_max_sizes(&self) -> &[u16] {
        QUEUE_SIZES
    }

    fn features(&self) -> u64 {
        // We specify the type to avoid an extra compilation error in case no backend is enabled
        // and this match statement becomes empty.
        let backend_features: u64 = match self.backend {
            #[cfg(feature = "libvda")]
            VideoBackendType::Libvda | VideoBackendType::LibvdaVd => {
                vda::supported_virtio_features()
            }
        };

        self.base_features | backend_features
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        let mut device_name = [0u8; 32];
        match self.backend {
            #[cfg(feature = "libvda")]
            VideoBackendType::Libvda => {
                (&mut device_name[0..6]).copy_from_slice("libvda".as_bytes())
            }
            #[cfg(feature = "libvda")]
            VideoBackendType::LibvdaVd => {
                (&mut device_name[0..8]).copy_from_slice("libvdavd".as_bytes())
            }
        };
        let mut cfg = protocol::virtio_video_config {
            version: Le32::from(0),
            max_caps_length: Le32::from(1024), // Set a big number
            max_resp_length: Le32::from(1024), // Set a big number
            device_name,
        };
        copy_config(data, 0, cfg.as_mut_slice(), offset);
    }

    fn activate(
        &mut self,
        mem: GuestMemory,
        interrupt: Interrupt,
        mut queues: Vec<virtio::queue::Queue>,
        mut queue_evts: Vec<Event>,
    ) {
        if queues.len() != QUEUE_SIZES.len() {
            error!(
                "wrong number of queues are passed: expected {}, actual {}",
                queues.len(),
                QUEUE_SIZES.len()
            );
            return;
        }
        if queue_evts.len() != QUEUE_SIZES.len() {
            error!(
                "wrong number of events are passed: expected {}, actual {}",
                queue_evts.len(),
                QUEUE_SIZES.len()
            );
        }

        let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
            Ok(v) => v,
            Err(e) => {
                error!("failed to create kill Event pair: {:?}", e);
                return;
            }
        };
        self.kill_evt = Some(self_kill_evt);

        let cmd_queue = queues.remove(0);
        let cmd_evt = queue_evts.remove(0);
        let event_queue = queues.remove(0);
        let event_evt = queue_evts.remove(0);
        let backend = self.backend;
        let resource_bridge = match self.resource_bridge.take() {
            Some(r) => r,
            None => {
                error!("no resource bridge is passed");
                return;
            }
        };
        let mut worker = Worker::new(
            interrupt,
            mem.clone(),
            cmd_queue,
            cmd_evt,
            event_queue,
            event_evt,
            kill_evt,
        );
        let worker_result = match &self.device_type {
            #[cfg(feature = "video-decoder")]
            VideoDeviceType::Decoder => thread::Builder::new()
                .name("virtio video decoder".to_owned())
                .spawn(move || {
                    let device: Box<dyn Device> = match backend {
                        #[cfg(feature = "libvda")]
                        VideoBackendType::Libvda => {
                            let vda = match decoder::backend::vda::LibvdaDecoder::new(
                                libvda::decode::VdaImplType::Gavda,
                            ) {
                                Ok(vda) => vda,
                                Err(e) => {
                                    error!("Failed to initialize VDA for decoder: {}", e);
                                    return;
                                }
                            };
                            Box::new(decoder::Decoder::new(vda, resource_bridge, mem))
                        }
                        #[cfg(feature = "libvda")]
                        VideoBackendType::LibvdaVd => {
                            let vda = match decoder::backend::vda::LibvdaDecoder::new(
                                libvda::decode::VdaImplType::Gavd,
                            ) {
                                Ok(vda) => vda,
                                Err(e) => {
                                    error!("Failed to initialize VD for decoder: {}", e);
                                    return;
                                }
                            };
                            Box::new(decoder::Decoder::new(vda, resource_bridge, mem))
                        }
                    };

                    if let Err(e) = worker.run(device) {
                        error!("Failed to start decoder worker: {}", e);
                    };
                    // Don't return any information since the return value is never checked.
                }),
            #[cfg(feature = "video-encoder")]
            VideoDeviceType::Encoder => thread::Builder::new()
                .name("virtio video encoder".to_owned())
                .spawn(move || {
                    let device: Box<dyn Device> = match backend {
                        #[cfg(feature = "libvda")]
                        VideoBackendType::Libvda => {
                            let vda = match encoder::backend::vda::LibvdaEncoder::new() {
                                Ok(vda) => vda,
                                Err(e) => {
                                    error!("Failed to initialize VDA for encoder: {}", e);
                                    return;
                                }
                            };

                            match encoder::EncoderDevice::new(vda, resource_bridge, mem) {
                                Ok(encoder) => Box::new(encoder),
                                Err(e) => {
                                    error!("Failed to create encoder device: {}", e);
                                    return;
                                }
                            }
                        }
                        #[cfg(feature = "libvda")]
                        VideoBackendType::LibvdaVd => {
                            error!("Invalid backend for encoder");
                            return;
                        }
                    };

                    if let Err(e) = worker.run(device) {
                        error!("Failed to start encoder worker: {}", e);
                    }
                }),
        };
        if let Err(e) = worker_result {
            error!(
                "failed to spawn virtio_video worker for {:?}: {}",
                &self.device_type, e
            );
            return;
        }
    }
}

/// Manages the zero-length, EOS-marked buffer signaling the end of a stream.
///
/// Both the decoder and encoder need to signal end-of-stream events using a zero-sized buffer
/// marked with the `VIRTIO_VIDEO_BUFFER_FLAG_EOS` flag. This struct allows to keep a buffer aside
/// for that purpose.
///
/// TODO(b/149725148): Remove this when libvda supports buffer flags.
#[cfg(feature = "video-encoder")]
struct EosBufferManager {
    stream_id: u32,
    eos_buffer: Option<u32>,
    client_awaits_eos: bool,
    responses: Vec<device::VideoEvtResponseType>,
}

#[cfg(feature = "video-encoder")]
impl EosBufferManager {
    /// Create a new EOS manager for stream `stream_id`.
    fn new(stream_id: u32) -> Self {
        Self {
            stream_id,
            eos_buffer: None,
            client_awaits_eos: false,
            responses: Default::default(),
        }
    }

    /// Attempt to reserve buffer `buffer_id` for use as EOS buffer.
    ///
    /// This method should be called by the output buffer queueing code of the device. It returns
    /// `true` if the buffer has been kept aside for EOS, `false` otherwise (which means another
    /// buffer is already kept aside for EOS). If `true` is returned, the client must not use the
    /// buffer for any other purpose.
    fn try_reserve_eos_buffer(&mut self, buffer_id: u32) -> bool {
        let is_none = self.eos_buffer.is_none();

        if is_none {
            info!(
                "stream {}: keeping buffer {} aside to signal EOS.",
                self.stream_id, buffer_id
            );
            self.eos_buffer = Some(buffer_id);
        }

        is_none
    }

    /// Attempt to complete an EOS event using the previously reserved buffer, if available.
    ///
    /// `responses` is a vector of responses to be sent to the driver along with the EOS buffer. If
    /// an EOS buffer has been made available using the `try_reserve_eos_buffer` method, then this
    /// method returns the `responses` vector with the EOS buffer dequeue appended in first
    /// position.
    ///
    /// If no EOS buffer is available, then the contents of `responses` is put aside, and will be
    /// returned the next time this method is called with an EOS buffer available. When this
    /// happens, `client_awaits_eos` will be set to true, and the client can check this member and
    /// call this method again right after queuing the next buffer to obtain the EOS response as
    /// soon as is possible.
    fn try_complete_eos(
        &mut self,
        responses: Vec<device::VideoEvtResponseType>,
    ) -> Option<Vec<device::VideoEvtResponseType>> {
        let eos_buffer_id = self.eos_buffer.take().or_else(|| {
            info!("stream {}: no EOS resource available on successful flush response, waiting for next buffer to be queued.", self.stream_id);
            self.client_awaits_eos = true;
            if !self.responses.is_empty() {
                error!("stream {}: EOS requested while one is already in progress. This is a bug!", self.stream_id);
            }
            self.responses = responses;
            None
        })?;

        let eos_tag = device::AsyncCmdTag::Queue {
            stream_id: self.stream_id,
            queue_type: command::QueueType::Output,
            resource_id: eos_buffer_id,
        };

        let eos_response = response::CmdResponse::ResourceQueue {
            timestamp: 0,
            flags: protocol::VIRTIO_VIDEO_BUFFER_FLAG_EOS,
            size: 0,
        };

        self.client_awaits_eos = false;

        info!(
            "stream {}: signaling EOS using buffer {}.",
            self.stream_id, eos_buffer_id
        );

        let mut responses = std::mem::take(&mut self.responses);
        responses.insert(
            0,
            device::VideoEvtResponseType::AsyncCmd(device::AsyncCmdResponse::from_response(
                eos_tag,
                eos_response,
            )),
        );

        Some(responses)
    }

    /// Reset the state of the manager, for use during e.g. stream resets.
    fn reset(&mut self) {
        self.eos_buffer = None;
        self.client_awaits_eos = false;
        self.responses.clear();
    }
}
<commit_msg>virtio: video: Increase command queue size<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! This module implements the virtio video encoder and decoder devices.
//! The current implementation uses [v3 RFC] of the virtio-video protocol.
//!
//! [v3 RFC]: https://markmail.org/thread/wxdne5re7aaugbjg

use std::thread;

#[cfg(feature = "video-encoder")]
use base::info;
use base::{error, AsRawDescriptor, Error as SysError, Event, RawDescriptor, Tube};
use data_model::{DataInit, Le32};
use remain::sorted;
use thiserror::Error;
use vm_memory::GuestMemory;

use crate::virtio::virtio_device::VirtioDevice;
use crate::virtio::{self, copy_config, DescriptorError, DeviceType, Interrupt};

#[macro_use]
mod macros;
mod async_cmd_desc_map;
mod command;
mod control;
#[cfg(feature = "video-decoder")]
mod decoder;
mod device;
#[cfg(feature = "video-encoder")]
mod encoder;
mod error;
mod event;
mod format;
mod params;
mod protocol;
mod resource;
mod response;
mod worker;

#[cfg(all(feature = "video-decoder", not(feature = "libvda")))]
compile_error!("The \"video-decoder\" feature requires \"libvda\" to also be enabled.");

#[cfg(all(feature = "video-encoder", not(feature = "libvda")))]
compile_error!("The \"video-encoder\" feature requires \"libvda\" to also be enabled.");

#[cfg(feature = "libvda")]
mod vda;

use command::ReadCmdError;
use device::Device;
use worker::Worker;

// CMD_QUEUE_SIZE = max number of command descriptors for input and output queues
// Experimentally, it appears a stream allocates 16 input and 26 output buffers = 42 total
// For 8 simultaneous streams, 2 descs per buffer * 42 buffers * 8 streams = 672 descs
// Allocate 1024 to give some headroom in case of extra streams/buffers
//
// TODO(b/204055006): Make cmd queue size dependent of
// (max buf cnt for input + max buf cnt for output) * max descs per buffer * max nb of streams
const CMD_QUEUE_SIZE: u16 = 1024;
// EVENT_QUEUE_SIZE = max number of event descriptors for stream events like resolution changes
const EVENT_QUEUE_SIZE: u16 = 256;
const QUEUE_SIZES: &[u16] = &[CMD_QUEUE_SIZE, EVENT_QUEUE_SIZE];

/// An error indicating something went wrong in virtio-video's worker.
#[sorted]
#[derive(Error, Debug)]
pub enum Error {
    /// No available descriptor in which an event is written to.
    #[error("no available descriptor in which an event is written to")]
    DescriptorNotAvailable,
    /// A DescriptorChain contains invalid data.
    #[error("DescriptorChain contains invalid data: {0}")]
    InvalidDescriptorChain(DescriptorError),
    /// Failed to read a virtio-video command.
    #[error("failed to read a command from the guest: {0}")]
    ReadFailure(ReadCmdError),
    /// Creating WaitContext failed.
    #[error("failed to create WaitContext: {0}")]
    WaitContextCreationFailed(SysError),
    /// Error while polling for events.
    #[error("failed to wait for events: {0}")]
    WaitError(SysError),
    /// Failed to write an event into the event queue.
    #[error("failed to write an event {event:?} into event queue: {error}")]
    WriteEventFailure {
        event: event::VideoEvt,
        error: std::io::Error,
    },
}

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub enum VideoDeviceType {
    #[cfg(feature = "video-decoder")]
    Decoder,
    #[cfg(feature = "video-encoder")]
    Encoder,
}

pub struct VideoDevice {
    device_type: VideoDeviceType,
    backend: VideoBackendType,
    kill_evt: Option<Event>,
    resource_bridge: Option<Tube>,
    base_features: u64,
}

impl VideoDevice {
    pub fn new(
        base_features: u64,
        device_type: VideoDeviceType,
        backend: VideoBackendType,
        resource_bridge: Option<Tube>,
    ) -> VideoDevice {
        VideoDevice {
            device_type,
            backend,
            kill_evt: None,
            resource_bridge,
            base_features,
        }
    }
}

impl Drop for VideoDevice {
    fn drop(&mut self) {
        if let Some(kill_evt) = self.kill_evt.take() {
            // Ignore the result because there is nothing we can do about it.
            let _ = kill_evt.write(1);
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum VideoBackendType {
    #[cfg(feature = "libvda")]
    Libvda,
    #[cfg(feature = "libvda")]
    LibvdaVd,
}

impl VirtioDevice for VideoDevice {
    fn keep_rds(&self) -> Vec<RawDescriptor> {
        let mut keep_rds = Vec::new();
        if let Some(resource_bridge) = &self.resource_bridge {
            keep_rds.push(resource_bridge.as_raw_descriptor());
        }
        keep_rds
    }

    fn device_type(&self) -> DeviceType {
        match &self.device_type {
            #[cfg(feature = "video-decoder")]
            VideoDeviceType::Decoder => DeviceType::VideoDec,
            #[cfg(feature = "video-encoder")]
            VideoDeviceType::Encoder => DeviceType::VideoEnc,
        }
    }

    fn queue_max_sizes(&self) -> &[u16] {
        QUEUE_SIZES
    }

    fn features(&self) -> u64 {
        // We specify the type to avoid an extra compilation error in case no backend is enabled
        // and this match statement becomes empty.
        let backend_features: u64 = match self.backend {
            #[cfg(feature = "libvda")]
            VideoBackendType::Libvda | VideoBackendType::LibvdaVd => {
                vda::supported_virtio_features()
            }
        };

        self.base_features | backend_features
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        let mut device_name = [0u8; 32];
        match self.backend {
            #[cfg(feature = "libvda")]
            VideoBackendType::Libvda => {
                (&mut device_name[0..6]).copy_from_slice("libvda".as_bytes())
            }
            #[cfg(feature = "libvda")]
            VideoBackendType::LibvdaVd => {
                (&mut device_name[0..8]).copy_from_slice("libvdavd".as_bytes())
            }
        };
        let mut cfg = protocol::virtio_video_config {
            version: Le32::from(0),
            max_caps_length: Le32::from(1024), // Set a big number
            max_resp_length: Le32::from(1024), // Set a big number
            device_name,
        };
        copy_config(data, 0, cfg.as_mut_slice(), offset);
    }

    fn activate(
        &mut self,
        mem: GuestMemory,
        interrupt: Interrupt,
        mut queues: Vec<virtio::queue::Queue>,
        mut queue_evts: Vec<Event>,
    ) {
        if queues.len() != QUEUE_SIZES.len() {
            error!(
                "wrong number of queues are passed: expected {}, actual {}",
                queues.len(),
                QUEUE_SIZES.len()
            );
            return;
        }
        if queue_evts.len() != QUEUE_SIZES.len() {
            error!(
                "wrong number of events are passed: expected {}, actual {}",
                queue_evts.len(),
                QUEUE_SIZES.len()
            );
        }

        let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
            Ok(v) => v,
            Err(e) => {
                error!("failed to create kill Event pair: {:?}", e);
                return;
            }
        };
        self.kill_evt = Some(self_kill_evt);

        let cmd_queue = queues.remove(0);
        let cmd_evt = queue_evts.remove(0);
        let event_queue = queues.remove(0);
        let event_evt = queue_evts.remove(0);
        let backend = self.backend;
        let resource_bridge = match self.resource_bridge.take() {
            Some(r) => r,
            None => {
                error!("no resource bridge is passed");
                return;
            }
        };
        let mut worker = Worker::new(
            interrupt,
            mem.clone(),
            cmd_queue,
            cmd_evt,
            event_queue,
            event_evt,
            kill_evt,
        );
        let worker_result = match &self.device_type {
            #[cfg(feature = "video-decoder")]
            VideoDeviceType::Decoder => thread::Builder::new()
                .name("virtio video decoder".to_owned())
                .spawn(move || {
                    let device: Box<dyn Device> = match backend {
                        #[cfg(feature = "libvda")]
                        VideoBackendType::Libvda => {
                            let vda = match decoder::backend::vda::LibvdaDecoder::new(
                                libvda::decode::VdaImplType::Gavda,
                            ) {
                                Ok(vda) => vda,
                                Err(e) => {
                                    error!("Failed to initialize VDA for decoder: {}", e);
                                    return;
                                }
                            };
                            Box::new(decoder::Decoder::new(vda, resource_bridge, mem))
                        }
                        #[cfg(feature = "libvda")]
                        VideoBackendType::LibvdaVd => {
                            let vda = match decoder::backend::vda::LibvdaDecoder::new(
                                libvda::decode::VdaImplType::Gavd,
                            ) {
                                Ok(vda) => vda,
                                Err(e) => {
                                    error!("Failed to initialize VD for decoder: {}", e);
                                    return;
                                }
                            };
                            Box::new(decoder::Decoder::new(vda, resource_bridge, mem))
                        }
                    };

                    if let Err(e) = worker.run(device) {
                        error!("Failed to start decoder worker: {}", e);
                    };
                    // Don't return any information since the return value is never checked.
                }),
            #[cfg(feature = "video-encoder")]
            VideoDeviceType::Encoder => thread::Builder::new()
                .name("virtio video encoder".to_owned())
                .spawn(move || {
                    let device: Box<dyn Device> = match backend {
                        #[cfg(feature = "libvda")]
                        VideoBackendType::Libvda => {
                            let vda = match encoder::backend::vda::LibvdaEncoder::new() {
                                Ok(vda) => vda,
                                Err(e) => {
                                    error!("Failed to initialize VDA for encoder: {}", e);
                                    return;
                                }
                            };

                            match encoder::EncoderDevice::new(vda, resource_bridge, mem) {
                                Ok(encoder) => Box::new(encoder),
                                Err(e) => {
                                    error!("Failed to create encoder device: {}", e);
                                    return;
                                }
                            }
                        }
                        #[cfg(feature = "libvda")]
                        VideoBackendType::LibvdaVd => {
                            error!("Invalid backend for encoder");
                            return;
                        }
                    };

                    if let Err(e) = worker.run(device) {
                        error!("Failed to start encoder worker: {}", e);
                    }
                }),
        };
        if let Err(e) = worker_result {
            error!(
                "failed to spawn virtio_video worker for {:?}: {}",
                &self.device_type, e
            );
            return;
        }
    }
}

/// Manages the zero-length, EOS-marked buffer signaling the end of a stream.
///
/// Both the decoder and encoder need to signal end-of-stream events using a zero-sized buffer
/// marked with the `VIRTIO_VIDEO_BUFFER_FLAG_EOS` flag. This struct allows to keep a buffer aside
/// for that purpose.
///
/// TODO(b/149725148): Remove this when libvda supports buffer flags.
#[cfg(feature = "video-encoder")]
struct EosBufferManager {
    stream_id: u32,
    eos_buffer: Option<u32>,
    client_awaits_eos: bool,
    responses: Vec<device::VideoEvtResponseType>,
}

#[cfg(feature = "video-encoder")]
impl EosBufferManager {
    /// Create a new EOS manager for stream `stream_id`.
    fn new(stream_id: u32) -> Self {
        Self {
            stream_id,
            eos_buffer: None,
            client_awaits_eos: false,
            responses: Default::default(),
        }
    }

    /// Attempt to reserve buffer `buffer_id` for use as EOS buffer.
    ///
    /// This method should be called by the output buffer queueing code of the device. It returns
    /// `true` if the buffer has been kept aside for EOS, `false` otherwise (which means another
    /// buffer is already kept aside for EOS). If `true` is returned, the client must not use the
    /// buffer for any other purpose.
    fn try_reserve_eos_buffer(&mut self, buffer_id: u32) -> bool {
        let is_none = self.eos_buffer.is_none();

        if is_none {
            info!(
                "stream {}: keeping buffer {} aside to signal EOS.",
                self.stream_id, buffer_id
            );
            self.eos_buffer = Some(buffer_id);
        }

        is_none
    }

    /// Attempt to complete an EOS event using the previously reserved buffer, if available.
    ///
    /// `responses` is a vector of responses to be sent to the driver along with the EOS buffer. If
    /// an EOS buffer has been made available using the `try_reserve_eos_buffer` method, then this
    /// method returns the `responses` vector with the EOS buffer dequeue appended in first
    /// position.
    ///
    /// If no EOS buffer is available, then the contents of `responses` is put aside, and will be
    /// returned the next time this method is called with an EOS buffer available. When this
    /// happens, `client_awaits_eos` will be set to true, and the client can check this member and
    /// call this method again right after queuing the next buffer to obtain the EOS response as
    /// soon as is possible.
    fn try_complete_eos(
        &mut self,
        responses: Vec<device::VideoEvtResponseType>,
    ) -> Option<Vec<device::VideoEvtResponseType>> {
        let eos_buffer_id = self.eos_buffer.take().or_else(|| {
            info!("stream {}: no EOS resource available on successful flush response, waiting for next buffer to be queued.", self.stream_id);
            self.client_awaits_eos = true;
            if !self.responses.is_empty() {
                error!("stream {}: EOS requested while one is already in progress. This is a bug!", self.stream_id);
            }
            self.responses = responses;
            None
        })?;

        let eos_tag = device::AsyncCmdTag::Queue {
            stream_id: self.stream_id,
            queue_type: command::QueueType::Output,
            resource_id: eos_buffer_id,
        };

        let eos_response = response::CmdResponse::ResourceQueue {
            timestamp: 0,
            flags: protocol::VIRTIO_VIDEO_BUFFER_FLAG_EOS,
            size: 0,
        };

        self.client_awaits_eos = false;

        info!(
            "stream {}: signaling EOS using buffer {}.",
            self.stream_id, eos_buffer_id
        );

        let mut responses = std::mem::take(&mut self.responses);
        responses.insert(
            0,
            device::VideoEvtResponseType::AsyncCmd(device::AsyncCmdResponse::from_response(
                eos_tag,
                eos_response,
            )),
        );

        Some(responses)
    }

    /// Reset the state of the manager, for use during e.g. stream resets.
    fn reset(&mut self) {
        self.eos_buffer = None;
        self.client_awaits_eos = false;
        self.responses.clear();
    }
}
<|endoftext|>


<commit_before>pub use self::param::*;
pub use self::reg::*;

use baseline::fct::ExHandler;
use ctxt::{Context, FctId};
use execstate::ExecState;
use object::{Handle, Obj};
use stacktrace::StackFrameInfo;

pub mod asm;
pub mod param;
pub mod reg;
pub mod trap;

pub fn sfi_from_execution_state(es: &ExecState) -> StackFrameInfo {
    unimplemented!();
}

pub fn resume_with_handler(es: &mut ExecState,
                           handler: &ExHandler,
                           fp: usize,
                           exception: Handle<Obj>,
                           stacksize: usize) {
    unimplemented!();
}

pub fn fp_from_execstate(es: &ExecState) -> usize {
    unimplemented!();
}

pub fn get_exception_object(es: &ExecState) -> Handle<Obj> {
    unimplemented!();
}

pub fn patch_fct_call(es: &mut ExecState, fct_ptr: *const u8) {
    unimplemented!();
}

pub fn patch_vtable_call(ctxt: &Context, es: &mut ExecState, fid: FctId, fct_ptr: *const u8) {
    unimplemented!();
}
<commit_msg>arm64: implemented more functions<commit_after>pub use self::param::*;
pub use self::reg::*;

use baseline::fct::ExHandler;
use ctxt::{Context, FctId};
use execstate::ExecState;
use object::{Handle, Obj};
use stacktrace::StackFrameInfo;

pub mod asm;
pub mod param;
pub mod reg;
pub mod trap;

pub fn sfi_from_execution_state(es: &ExecState) -> StackFrameInfo {
    let ra = es.regs[REG_LR.asm() as usize];

    StackFrameInfo {
        last: ptr::null(),
        fp: es.regs[REG_FP.asm() as usize],
        sp: es.sp,
        ra: ra,
        xpc: ra - 1,
    }
}

pub fn resume_with_handler(es: &mut ExecState,
                           handler: &ExHandler,
                           fp: usize,
                           exception: Handle<Obj>,
                           stacksize: usize) {
    unimplemented!();
}

pub fn fp_from_execstate(es: &ExecState) -> usize {
    es.regs[REG_FP.asm() as usize]
}

pub fn get_exception_object(es: &ExecState) -> Handle<Obj> {
    let obj: Handle<Obj> = es.regs[REG_RESULT.int() as usize].into();

    obj
}

pub fn patch_fct_call(es: &mut ExecState, fct_ptr: *const u8) {
    unimplemented!();
}

pub fn patch_vtable_call(ctxt: &Context, es: &mut ExecState, fid: FctId, fct_ptr: *const u8) {
    unimplemented!();
}
<|endoftext|>


<commit_before>use num::bigint::ToBigUint;
use num::Integer;

static BASE58_ALPHABET: &'static str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

pub fn to_base58(data: &[u8]) -> ~str
{
    let mut n = 0u.to_biguint().unwrap();
    for (i, c) in data.iter().rev().enumerate() {
        let c = c.to_biguint().unwrap();

        n =n + (c << (i * 8));
    }

    let mut result = StrBuf::new();
    let limit = 58u.to_biguint().unwrap();
    while n >= limit {
        let (d, r) = n.div_rem(&limit);
        let r = r.to_uint().unwrap();

        n = d;
        result.push_char(BASE58_ALPHABET[r] as char);
    }
    let r = n.to_uint().unwrap();

    if r > 0 {
        result.push_char(BASE58_ALPHABET[r] as char);
    }

    for c in data.iter() {
        if *c == 0 {
            result.push_char(BASE58_ALPHABET[0] as char);
        } else {
            break;
        }
    }

    result.as_slice().chars().rev().collect()
}

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

    #[test]
    fn test_simple()
    {
        let tests = ~[
            ("hello world".as_bytes(), "StV1DL6CwTryKyV"),
            ("Hello World".as_bytes(), "JxF12TrwUP45BMd"),
        ];

        for &(s, n) in tests.iter() {
            let r = to_base58(s);

            assert_eq!(r.as_slice(), n);
        }
    }
}

#[cfg(test)]
mod bench
{
    use super::to_base58;
    use test::test::Bencher;

    #[bench]
    fn bench_simple(bh: &mut Bencher)
    {
        let s = "hello world";

        bh.iter(|| {
            to_base58(s.as_bytes());
        });
        bh.bytes = s.len() as u64;
    }
}
<commit_msg>Update to latest Rust nightly.<commit_after>use num::bigint::ToBigUint;
use num::Integer;

static BASE58_ALPHABET: &'static str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

pub fn to_base58(data: &[u8]) -> StrBuf
{
    let mut n = 0u.to_biguint().unwrap();
    for (i, c) in data.iter().rev().enumerate() {
        let c = c.to_biguint().unwrap();

        n =n + (c << (i * 8));
    }

    let mut result = StrBuf::new();
    let limit = 58u.to_biguint().unwrap();
    while n >= limit {
        let (d, r) = n.div_rem(&limit);
        let r = r.to_uint().unwrap();

        n = d;
        result.push_char(BASE58_ALPHABET[r] as char);
    }
    let r = n.to_uint().unwrap();

    if r > 0 {
        result.push_char(BASE58_ALPHABET[r] as char);
    }

    for c in data.iter() {
        if *c == 0 {
            result.push_char(BASE58_ALPHABET[0] as char);
        } else {
            break;
        }
    }

    result.as_slice().chars().rev().collect()
}

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

    #[test]
    fn test_simple()
    {
        let tests = [
            ("hello world".as_bytes(), "StV1DL6CwTryKyV"),
            ("Hello World".as_bytes(), "JxF12TrwUP45BMd"),
        ];

        for &(s, n) in tests.iter() {
            let r = to_base58(s);

            assert_eq!(r.as_slice(), n);
        }
    }
}

#[cfg(test)]
mod bench
{
    use super::to_base58;
    use test::test::Bencher;

    #[bench]
    fn bench_simple(bh: &mut Bencher)
    {
        let s = "hello world";

        bh.iter(|| {
            to_base58(s.as_bytes());
        });
        bh.bytes = s.len() as u64;
    }
}
<|endoftext|>


<commit_before>#[feature(globs)];

extern mod native;
extern mod extra;
extern mod glfw;
extern mod gl;
extern mod cgmath;
extern mod noise;

use std::cast;
use std::ptr;
use std::str;
use std::vec;
use std::libc;
use std::io::Timer;

use gl::types::*;

use cgmath::matrix::Matrix;
use cgmath::matrix::Mat3;
use cgmath::matrix::Mat4;
use cgmath::matrix::ToMat4;
use cgmath::vector::Vector;
use cgmath::vector::Vec3;
use cgmath::vector::Vec4;
use cgmath::angle::rad;

#[link(name="GLU")]
extern {}

mod chunk;

static vertex_shader_src : &'static str = r"
#version 110

uniform mat4 modelview;
uniform mat4 projection;

attribute vec3 position;
attribute vec3 normal;

varying vec4 frag_color;

const vec4 obj_diffuse = vec4(0.2, 0.6, 0.2, 1.0);
const vec3 light_direction = vec3(0.408248, -0.816497, 0.408248);
const vec4 light_diffuse = vec4(0.8, 0.8, 0.8, 0.0);
const vec4 light_ambient = vec4(0.2, 0.2, 0.2, 1.0);

void main() {
    gl_Position = projection * modelview * vec4(position, 1.0);

    vec4 diffuse_factor
        = max(-dot(normal, light_direction), 0.0) * light_diffuse;
    vec4 ambient_diffuse_factor = diffuse_factor + light_ambient;

    frag_color = ambient_diffuse_factor * obj_diffuse;
}
";

static fragment_shader_src : &'static str = r"
#version 110

varying vec4 frag_color;

void main() {
    gl_FragColor = frag_color;
}
";

pub static WORLD_SIZE: uint = 4;
pub static CHUNK_SIZE: uint = 64;
pub static WORLD_SEED: u32 = 42;

static FRAME_TIME_TARGET_MS : u64 = 16;

struct GraphicsResources {
    program: GLuint,
    uniform_modelview: GLint,
    uniform_projection: GLint,
}

#[start]
fn start(argc: int, argv: **u8) -> int {
    do native::start(argc, argv) {
        main();
    }
}

fn main() {
   glfw::set_error_callback(~ErrorContext);

    do glfw::start {
        let mut window_width = 800;
        let mut window_height = 600;

        let window = glfw::Window::create(window_width, window_height, "Hello, I am a window.", glfw::Windowed)
            .expect("Failed to create GLFW window.");

        window.set_cursor_mode(glfw::CursorDisabled);
        window.make_context_current();

        gl::load_with(glfw::get_proc_address);

        gl::Enable(gl::DEPTH_TEST);
        gl::Enable(gl::CULL_FACE);

        glfw::set_swap_interval(1);

        let graphics_resources = load_graphics_resources();

        gl::UseProgram(graphics_resources.program);

        let mut chunk_loader = chunk::ChunkLoader::new(WORLD_SEED, &graphics_resources);

        window.set_key_callback(~KeyContext);

        let (fb_size_port, fb_size_chan): (Port<(u32,u32)>, Chan<(u32,u32)>) = std::comm::Chan::new();
        window.set_framebuffer_size_callback(~FramebufferSizeContext { chan: fb_size_chan });

        let start_time = extra::time::precise_time_ns();
        let mut last_frame_time = start_time;
        let mut num_frames = 0;

        let mut camera_position = Vec3::<f32>::new(0.0f32, 20.0f32, 40.0f32);

        //let mut timer = Timer::new().unwrap();

        while !window.should_close() {
            let frame_start_time = extra::time::precise_time_ns();

            glfw::poll_events();

            loop {
                match fb_size_port.try_recv() {
                    Some((w,h)) => {
                        window_width = w;
                        window_height = h;
                    }
                    None => break
                }
            }

            let (cursor_x, cursor_y) = window.get_cursor_pos();
            let camera_angle_y = ((cursor_x * 0.0005) % 1.0) * std::f64::consts::PI * 2.0;
            let camera_angle_x = ((cursor_y * 0.0005) % 1.0) * std::f64::consts::PI * 2.0;

            let mut camera_velocity = Vec3::<f32>::new(0.0f32, 0.0f32, 0.0f32);

            match window.get_key(glfw::KeySpace) {
                glfw::Press => { camera_velocity.y += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyLeftControl) {
                glfw::Press => { camera_velocity.y += -1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyS) {
                glfw::Press => { camera_velocity.z += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyW) {
                glfw::Press => { camera_velocity.z += -1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyD) {
                glfw::Press => { camera_velocity.x += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyA) {
                glfw::Press => { camera_velocity.x += -1.0f32 }
                _ => {}
            }

            gl::Viewport(0,0, window_width as GLint, window_height as GLint);

            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

            let projection = cgmath::projection::perspective(
                rad(1.57f32),
                window_width as f32 / window_height as f32,
                0.1f32, 1000.0f32);

            unsafe {
                gl::UniformMatrix4fv(graphics_resources.uniform_projection, 1, gl::FALSE, cast::transmute(&projection));
            }

            let camera_translation = Mat4::<f32>::from_cols(
                Vec4::<f32>::unit_x(),
                Vec4::<f32>::unit_y(),
                Vec4::<f32>::unit_z(),
                camera_position.mul_s(-1.0f32).extend(1.0f32));
            let camera_rotation_x = Mat3::<f32>::from_angle_x(rad(camera_angle_x as f32)).to_mat4();
            let camera_rotation_y = Mat3::<f32>::from_angle_y(rad(camera_angle_y as f32)).to_mat4();
            let camera = camera_rotation_x.mul_m(&camera_rotation_y).mul_m(&camera_translation);

            let inv_camera_rotation = Mat3::<f32>::from_euler(rad(-camera_angle_x as f32), rad(-camera_angle_y as f32), rad(0.0f32));
            let absolute_camera_velocity = inv_camera_rotation.mul_v(&camera_velocity).mul_s(0.5f32);
            camera_position.add_self_v(&absolute_camera_velocity);

            for (_, chunk) in chunk_loader.cache.iter() {
                let chunk_translation = Mat4::<f32>::from_cols(
                    Vec4::<f32>::unit_x(),
                    Vec4::<f32>::unit_y(),
                    Vec4::<f32>::unit_z(),
                    Vec4::<f32>::new(chunk.x as f32, 0.0f32, chunk.z as f32, 1.0f32));

                let modelview = camera.mul_m(&chunk_translation);

                gl::BindVertexArray(chunk.vao);

                unsafe {
                    gl::UniformMatrix4fv(graphics_resources.uniform_modelview, 1, gl::FALSE, cast::transmute(&modelview));
                    gl::DrawElements(gl::TRIANGLES, chunk.num_elements as i32, gl::UNSIGNED_INT, ptr::null());
                }

                gl::BindVertexArray(0);
            }

            window.swap_buffers();

            check_gl("main loop");

            chunk_loader.update(camera_position.x as i64, camera_position.z as i64);

            let cur_time = extra::time::precise_time_ns();
            num_frames += 1;
            if (cur_time - last_frame_time) > (1000*1000*1000) {
                println!("{} frames per second", num_frames);
                num_frames = 0;
                last_frame_time = cur_time;
            }

            let frame_end_time = extra::time::precise_time_ns();
            let frame_time_ms = (frame_end_time - frame_start_time)/(1000*1000);
            if (frame_time_ms < FRAME_TIME_TARGET_MS) {
                //timer.sleep(FRAME_TIME_TARGET_MS - frame_time_ms);
            }
        }
    }
}

fn load_graphics_resources() -> GraphicsResources {
    let vs = compile_shader(vertex_shader_src.as_bytes(), gl::VERTEX_SHADER);
    let fs = compile_shader(fragment_shader_src.as_bytes(), gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

    let uniform_modelview = unsafe { "modelview".with_c_str(|ptr| gl::GetUniformLocation(program, ptr)) };
    let uniform_projection = unsafe { "projection".with_c_str(|ptr| gl::GetUniformLocation(program, ptr)) };

    return GraphicsResources {
        program: program,
        uniform_modelview: uniform_modelview,
        uniform_projection: uniform_projection,
    };

}

extern "C" {
    fn gluErrorString(error: GLenum) -> *GLubyte;
}

fn check_gl(message : &str) {
    let err = gl::GetError();
    if (err != gl::NO_ERROR) {
        unsafe {
            let err = std::str::raw::from_c_str(gluErrorString(err) as *i8);
            fail!("GL error {} at {}", err, message);
        }
    }
}

fn compile_shader(src: &[u8], ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        //transmute is used here because `as` causes ICE
        //wait a sec, is `src` null-terminated properly?
        gl::ShaderSource(shader, 1, std::cast::transmute(std::ptr::to_unsafe_ptr(&src.as_ptr())), ptr::null());
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!(str::raw::from_utf8(buf).to_owned());
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);
    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!(str::raw::from_utf8(buf).to_owned());
        }
    }
    program
}

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
    fn call(&self, _: glfw::Error, description: ~str) {
        fail!("GLFW Error: {:s}", description);
    }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
    fn call(&self, window: &glfw::Window, key: glfw::Key, _: libc::c_int, action: glfw::Action, _: glfw::Modifiers) {
        match (action, key) {
            (glfw::Press, glfw::KeyEscape) => window.set_should_close(true),
            _ => {}
        }
    }
}

struct FramebufferSizeContext {
    chan: Chan<(u32,u32)>
}
impl glfw::FramebufferSizeCallback for FramebufferSizeContext {
    fn call(&self, _: &glfw::Window, width: i32, height: i32) {
        self.chan.send((width as u32,height as u32));
    }
}
<commit_msg>curve the planet<commit_after>#[feature(globs)];

extern mod native;
extern mod extra;
extern mod glfw;
extern mod gl;
extern mod cgmath;
extern mod noise;

use std::cast;
use std::ptr;
use std::str;
use std::vec;
use std::libc;
use std::io::Timer;

use gl::types::*;

use cgmath::matrix::Matrix;
use cgmath::matrix::Mat3;
use cgmath::matrix::Mat4;
use cgmath::matrix::ToMat4;
use cgmath::vector::Vector;
use cgmath::vector::Vec3;
use cgmath::vector::Vec4;
use cgmath::angle::rad;

#[link(name="GLU")]
extern {}

mod chunk;

static vertex_shader_src : &'static str = r"
#version 110

uniform mat4 modelview;
uniform mat4 projection;

attribute vec3 position;
attribute vec3 normal;

varying vec4 frag_color;

const vec4 obj_diffuse = vec4(0.2, 0.6, 0.2, 1.0);
const vec3 light_direction = vec3(0.408248, -0.816497, 0.408248);
const vec4 light_diffuse = vec4(0.8, 0.8, 0.8, 0.0);
const vec4 light_ambient = vec4(0.2, 0.2, 0.2, 1.0);

const float planet_radius = 6371000.0 / 10000.0;

void main() {
    vec4 eye_position = modelview * vec4(position, 1.0);

    /* Curvature of the planet */
    float distance_squared = pow(eye_position.x, 2) + pow(eye_position.z, 2);
    eye_position.y -= planet_radius - sqrt(pow(planet_radius, 2) - distance_squared);

    gl_Position = projection * eye_position;

    vec4 diffuse_factor
        = max(-dot(normal, light_direction), 0.0) * light_diffuse;
    vec4 ambient_diffuse_factor = diffuse_factor + light_ambient;

    frag_color = ambient_diffuse_factor * obj_diffuse;
}
";

static fragment_shader_src : &'static str = r"
#version 110

varying vec4 frag_color;

void main() {
    gl_FragColor = frag_color;
}
";

pub static WORLD_SIZE: uint = 4;
pub static CHUNK_SIZE: uint = 64;
pub static WORLD_SEED: u32 = 42;

static FRAME_TIME_TARGET_MS : u64 = 16;

struct GraphicsResources {
    program: GLuint,
    uniform_modelview: GLint,
    uniform_projection: GLint,
}

#[start]
fn start(argc: int, argv: **u8) -> int {
    do native::start(argc, argv) {
        main();
    }
}

fn main() {
   glfw::set_error_callback(~ErrorContext);

    do glfw::start {
        let mut window_width = 800;
        let mut window_height = 600;

        let window = glfw::Window::create(window_width, window_height, "Hello, I am a window.", glfw::Windowed)
            .expect("Failed to create GLFW window.");

        window.set_cursor_mode(glfw::CursorDisabled);
        window.make_context_current();

        gl::load_with(glfw::get_proc_address);

        gl::Enable(gl::DEPTH_TEST);
        gl::Enable(gl::CULL_FACE);

        glfw::set_swap_interval(1);

        let graphics_resources = load_graphics_resources();

        gl::UseProgram(graphics_resources.program);

        let mut chunk_loader = chunk::ChunkLoader::new(WORLD_SEED, &graphics_resources);

        window.set_key_callback(~KeyContext);

        let (fb_size_port, fb_size_chan): (Port<(u32,u32)>, Chan<(u32,u32)>) = std::comm::Chan::new();
        window.set_framebuffer_size_callback(~FramebufferSizeContext { chan: fb_size_chan });

        let start_time = extra::time::precise_time_ns();
        let mut last_frame_time = start_time;
        let mut num_frames = 0;

        let mut camera_position = Vec3::<f32>::new(0.0f32, 20.0f32, 40.0f32);

        //let mut timer = Timer::new().unwrap();

        while !window.should_close() {
            let frame_start_time = extra::time::precise_time_ns();

            glfw::poll_events();

            loop {
                match fb_size_port.try_recv() {
                    Some((w,h)) => {
                        window_width = w;
                        window_height = h;
                    }
                    None => break
                }
            }

            let (cursor_x, cursor_y) = window.get_cursor_pos();
            let camera_angle_y = ((cursor_x * 0.0005) % 1.0) * std::f64::consts::PI * 2.0;
            let camera_angle_x = ((cursor_y * 0.0005) % 1.0) * std::f64::consts::PI * 2.0;

            let mut camera_velocity = Vec3::<f32>::new(0.0f32, 0.0f32, 0.0f32);

            match window.get_key(glfw::KeySpace) {
                glfw::Press => { camera_velocity.y += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyLeftControl) {
                glfw::Press => { camera_velocity.y += -1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyS) {
                glfw::Press => { camera_velocity.z += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyW) {
                glfw::Press => { camera_velocity.z += -1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyD) {
                glfw::Press => { camera_velocity.x += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyA) {
                glfw::Press => { camera_velocity.x += -1.0f32 }
                _ => {}
            }

            gl::Viewport(0,0, window_width as GLint, window_height as GLint);

            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

            let projection = cgmath::projection::perspective(
                rad(1.57f32),
                window_width as f32 / window_height as f32,
                0.1f32, 1000.0f32);

            unsafe {
                gl::UniformMatrix4fv(graphics_resources.uniform_projection, 1, gl::FALSE, cast::transmute(&projection));
            }

            let camera_translation = Mat4::<f32>::from_cols(
                Vec4::<f32>::unit_x(),
                Vec4::<f32>::unit_y(),
                Vec4::<f32>::unit_z(),
                camera_position.mul_s(-1.0f32).extend(1.0f32));
            let camera_rotation_x = Mat3::<f32>::from_angle_x(rad(camera_angle_x as f32)).to_mat4();
            let camera_rotation_y = Mat3::<f32>::from_angle_y(rad(camera_angle_y as f32)).to_mat4();
            let camera = camera_rotation_x.mul_m(&camera_rotation_y).mul_m(&camera_translation);

            let inv_camera_rotation = Mat3::<f32>::from_euler(rad(-camera_angle_x as f32), rad(-camera_angle_y as f32), rad(0.0f32));
            let absolute_camera_velocity = inv_camera_rotation.mul_v(&camera_velocity).mul_s(0.5f32);
            camera_position.add_self_v(&absolute_camera_velocity);

            for (_, chunk) in chunk_loader.cache.iter() {
                let chunk_translation = Mat4::<f32>::from_cols(
                    Vec4::<f32>::unit_x(),
                    Vec4::<f32>::unit_y(),
                    Vec4::<f32>::unit_z(),
                    Vec4::<f32>::new(chunk.x as f32, 0.0f32, chunk.z as f32, 1.0f32));

                let modelview = camera.mul_m(&chunk_translation);

                gl::BindVertexArray(chunk.vao);

                unsafe {
                    gl::UniformMatrix4fv(graphics_resources.uniform_modelview, 1, gl::FALSE, cast::transmute(&modelview));
                    gl::DrawElements(gl::TRIANGLES, chunk.num_elements as i32, gl::UNSIGNED_INT, ptr::null());
                }

                gl::BindVertexArray(0);
            }

            window.swap_buffers();

            check_gl("main loop");

            chunk_loader.update(camera_position.x as i64, camera_position.z as i64);

            let cur_time = extra::time::precise_time_ns();
            num_frames += 1;
            if (cur_time - last_frame_time) > (1000*1000*1000) {
                println!("{} frames per second", num_frames);
                num_frames = 0;
                last_frame_time = cur_time;
            }

            let frame_end_time = extra::time::precise_time_ns();
            let frame_time_ms = (frame_end_time - frame_start_time)/(1000*1000);
            if (frame_time_ms < FRAME_TIME_TARGET_MS) {
                //timer.sleep(FRAME_TIME_TARGET_MS - frame_time_ms);
            }
        }
    }
}

fn load_graphics_resources() -> GraphicsResources {
    let vs = compile_shader(vertex_shader_src.as_bytes(), gl::VERTEX_SHADER);
    let fs = compile_shader(fragment_shader_src.as_bytes(), gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

    let uniform_modelview = unsafe { "modelview".with_c_str(|ptr| gl::GetUniformLocation(program, ptr)) };
    let uniform_projection = unsafe { "projection".with_c_str(|ptr| gl::GetUniformLocation(program, ptr)) };

    return GraphicsResources {
        program: program,
        uniform_modelview: uniform_modelview,
        uniform_projection: uniform_projection,
    };

}

extern "C" {
    fn gluErrorString(error: GLenum) -> *GLubyte;
}

fn check_gl(message : &str) {
    let err = gl::GetError();
    if (err != gl::NO_ERROR) {
        unsafe {
            let err = std::str::raw::from_c_str(gluErrorString(err) as *i8);
            fail!("GL error {} at {}", err, message);
        }
    }
}

fn compile_shader(src: &[u8], ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        //transmute is used here because `as` causes ICE
        //wait a sec, is `src` null-terminated properly?
        gl::ShaderSource(shader, 1, std::cast::transmute(std::ptr::to_unsafe_ptr(&src.as_ptr())), ptr::null());
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!(str::raw::from_utf8(buf).to_owned());
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);
    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!(str::raw::from_utf8(buf).to_owned());
        }
    }
    program
}

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
    fn call(&self, _: glfw::Error, description: ~str) {
        fail!("GLFW Error: {:s}", description);
    }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
    fn call(&self, window: &glfw::Window, key: glfw::Key, _: libc::c_int, action: glfw::Action, _: glfw::Modifiers) {
        match (action, key) {
            (glfw::Press, glfw::KeyEscape) => window.set_should_close(true),
            _ => {}
        }
    }
}

struct FramebufferSizeContext {
    chan: Chan<(u32,u32)>
}
impl glfw::FramebufferSizeCallback for FramebufferSizeContext {
    fn call(&self, _: &glfw::Window, width: i32, height: i32) {
        self.chan.send((width as u32,height as u32));
    }
}
<|endoftext|>


<commit_before>//! Evolve a Population of Individuals in an Environment
//!
//! Evolution is the culmination of individuals in a population competing in a
//! harsh environment for limited resources. Here the environment is determined
//! by the fitness function, the individuals are programs.

use rand;
use rand::distributions::{Range, IndependentSample};
use super::super::grammar::Program;
use super::super::population::Population;
use super::super::environment::Environment;
use super::super::fitness::{Config, ScoreCard, Score};
use super::crossover::crossover;

/// Return the next generation of the population
pub fn succesion(mut rng: &mut rand::Rng, environment: Environment, population: Population) -> Population {
    let config: Config = Config {
        program_length_weight: -1,
        food_distance_weight: -1,
    };
    let Population(last_generation) = population;
    let mut scored_last_generation: Vec<(Program, Score)> = last_generation
        .iter()
        .map(|program| (program.clone(), config.score(program.clone(), environment.clone())))
        .collect();
    scored_last_generation.sort_by(|a,b| b.1.cmp(&a.1));

    let mut next_generation: Vec<Program> = vec!();
    for index in 0..2 {
        let program: Program = scored_last_generation[index].0.clone();
        next_generation.push(program);
    }
    let index_range = Range::new(0, scored_last_generation.len());
    while next_generation.len() < last_generation.len() {
        let left_index = index_range.ind_sample(&mut rng);
        let right_index = index_range.ind_sample(&mut rng);
        let left = scored_last_generation[left_index].0.clone();
        let right = scored_last_generation[right_index].0.clone();
        let (left_child, right_child) = crossover(&mut rng, &left, &right);
        next_generation.push(left_child);
        if next_generation.len() < last_generation.len() {
            next_generation.push(right_child);
        }
    }

    Population(next_generation)
}
<commit_msg>Rename next_generation to generation<commit_after>//! Evolve a Population of Individuals in an Environment
//!
//! Evolution is the culmination of individuals in a population competing in a
//! harsh environment for limited resources. Here the environment is determined
//! by the fitness function, the individuals are programs.

use rand;
use rand::distributions::{Range, IndependentSample};
use super::super::grammar::Program;
use super::super::population::Population;
use super::super::environment::Environment;
use super::super::fitness::{Config, ScoreCard, Score};
use super::crossover::crossover;

/// Return the next generation of the population
pub fn succesion(mut rng: &mut rand::Rng, environment: Environment, population: Population) -> Population {
    let config: Config = Config {
        program_length_weight: -1,
        food_distance_weight: -1,
    };
    let Population(last_generation) = population;
    let mut scored_last_generation: Vec<(Program, Score)> = last_generation
        .iter()
        .map(|program| (program.clone(), config.score(program.clone(), environment.clone())))
        .collect();
    scored_last_generation.sort_by(|a,b| b.1.cmp(&a.1));

    let mut generation: Vec<Program> = vec!();
    for index in 0..2 {
        let program: Program = scored_last_generation[index].0.clone();
        generation.push(program);
    }
    let index_range = Range::new(0, scored_last_generation.len());
    while generation.len() < last_generation.len() {
        let left_index = index_range.ind_sample(&mut rng);
        let right_index = index_range.ind_sample(&mut rng);
        let left = scored_last_generation[left_index].0.clone();
        let right = scored_last_generation[right_index].0.clone();
        let (left_child, right_child) = crossover(&mut rng, &left, &right);
        generation.push(left_child);
        if generation.len() < last_generation.len() {
            generation.push(right_child);
        }
    }

    Population(generation)
}
<|endoftext|>


<commit_before>use std::ops::Bound;

use pagecache::{Measure, M};

use super::*;

fn possible_predecessor(s: &[u8]) -> Option<Vec<u8>> {
    let mut ret = s.to_vec();
    match ret.pop() {
        None => None,
        Some(i) if i == 0 => Some(ret),
        Some(i) => {
            ret.push(i - 1);
            for _ in 0..4 {
                ret.push(255);
            }
            Some(ret)
        }
    }
}

macro_rules! iter_try {
    ($e:expr) => {
        match $e {
            Ok(item) => item,
            Err(e) => return Some(Err(e)),
        }
    };
}

/// An iterator over keys and values in a `Tree`.
pub struct Iter<'a> {
    pub(super) tree: &'a Tree,
    pub(super) hi: Bound<IVec>,
    pub(super) lo: Bound<IVec>,
    pub(super) cached_view: Option<View<'a>>,
    pub(super) tx: Result<Tx<'a, BLinkMaterializer, Frag>>,
    pub(super) going_forward: bool,
}

impl<'a> Iter<'a> {
    /// Iterate over the keys of this Tree
    pub fn keys(self) -> impl 'a + DoubleEndedIterator<Item = Result<IVec>> {
        self.map(|r| r.map(|(k, _v)| k))
    }

    /// Iterate over the values of this Tree
    pub fn values(self) -> impl 'a + DoubleEndedIterator<Item = Result<IVec>> {
        self.map(|r| r.map(|(_k, v)| v))
    }

    fn bounds_collapsed(&self) -> bool {
        match (&self.lo, &self.hi) {
            (Bound::Included(ref start), Bound::Included(ref end))
            | (Bound::Included(ref start), Bound::Excluded(ref end))
            | (Bound::Excluded(ref start), Bound::Included(ref end))
            | (Bound::Excluded(ref start), Bound::Excluded(ref end)) => {
                start > end
            }
            _ => false,
        }
    }

    fn low_key(&self) -> &[u8] {
        match self.lo {
            Bound::Unbounded => &[],
            Bound::Excluded(ref lo) | Bound::Included(ref lo) => lo.as_ref(),
        }
    }

    fn high_key(&self) -> &[u8] {
        const MAX_KEY: &[u8] = &[255; 1024 * 1024];
        match self.hi {
            Bound::Unbounded => MAX_KEY,
            Bound::Excluded(ref hi) | Bound::Included(ref hi) => hi.as_ref(),
        }
    }
}

impl<'a> Iterator for Iter<'a> {
    type Item = Result<(IVec, IVec)>;

    fn next(&mut self) -> Option<Self::Item> {
        let _measure = Measure::new(&M.tree_scan);

        let tx: &'a Tx<'a, _, _> = match self.tx {
            Ok(ref tx) => {
                let tx_ref = tx as *const Tx<'a, _, _>;
                unsafe { &*tx_ref as &'a Tx<'a, _, _> }
            }
            Err(ref e) => return Some(Err(e.clone())),
        };

        let mut view = match (self.going_forward, self.cached_view.take()) {
            (true, Some(view)) => view,
            _ => iter_try!(self.tree.view_for_key(self.low_key(), &tx)),
        };

        loop {
            if self.bounds_collapsed() {
                return None;
            }

            if !view.contains_upper_bound(&self.lo) {
                // view too low (maybe merged, maybe exhausted?)
                let next_pid = view.next?;
                if let Some(v) =
                    iter_try!(self.tree.view_for_pid(next_pid, &tx))
                {
                    view = v;
                }
                continue;
            } else if !view.contains_lower_bound(&self.lo, true) {
                // view too high (maybe split, maybe exhausted?)
                let seek_key = possible_predecessor(view.lo)?;
                view = iter_try!(self.tree.view_for_key(seek_key, &tx));
                continue;
            }

            if let Some((key, value)) =
                view.successor(&self.lo, &self.tree.context)
            {
                self.lo = Bound::Excluded(key.clone());
                self.cached_view = Some(view);
                self.going_forward = true;

                match self.hi {
                    Bound::Unbounded => return Some(Ok((key, value))),
                    Bound::Included(ref h) if *h >= key => {
                        return Some(Ok((key, value)));
                    }
                    Bound::Excluded(ref h) if *h > key => {
                        return Some(Ok((key, value)));
                    }
                    _ => return None,
                }
            } else {
                if view.hi.is_empty() {
                    return None;
                }
                self.lo = Bound::Included(view.hi.clone());
                continue;
            }
        }
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        let _measure = Measure::new(&M.tree_reverse_scan);

        let tx: &'a Tx<'a, _, _> = match self.tx {
            Ok(ref tx) => {
                let tx_ref = tx as *const Tx<'a, _, _>;
                unsafe { &*tx_ref as &'a Tx<'a, _, _> }
            }
            Err(ref e) => return Some(Err(e.clone())),
        };

        let mut view = match (self.going_forward, self.cached_view.take()) {
            (false, Some(view)) => view,
            _ => iter_try!(self.tree.view_for_key(self.high_key(), &tx)),
        };

        let mut _debug_loops = 0;
        loop {
            _debug_loops += 1;
            assert!(_debug_loops < 10000);

            if self.bounds_collapsed() {
                return None;
            }

            if !view.contains_upper_bound(&self.hi) {
                // view too low (maybe merged, maybe exhausted?)
                let next_pid = view.next?;
                if let Some(v) =
                    iter_try!(self.tree.view_for_pid(next_pid, &tx))
                {
                    view = v;
                }
                continue;
            } else if !view.contains_lower_bound(&self.hi, false) {
                // view too high (maybe split, maybe exhausted?)
                let seek_key = possible_predecessor(view.lo)?;
                view = iter_try!(self.tree.view_for_key(seek_key, &tx));
                continue;
            }

            if let Some((key, value)) =
                view.predecessor(&self.hi, &self.tree.context)
            {
                self.hi = Bound::Excluded(key.clone());
                self.cached_view = Some(view);
                self.going_forward = false;

                match self.lo {
                    Bound::Unbounded => return Some(Ok((key, value))),
                    Bound::Included(ref l) if *l <= key => {
                        return Some(Ok((key, value)));
                    }
                    Bound::Excluded(ref l) if *l < key => {
                        return Some(Ok((key, value)));
                    }
                    _ => {
                        return None;
                    }
                }
            } else {
                if view.lo.is_empty() {
                    return None;
                }
                self.hi = Bound::Excluded(view.lo.clone());
                continue;
            }
        }
    }
}

#[test]
fn test_possible_predecessor() {
    assert_eq!(possible_predecessor(b""), None);
    assert_eq!(possible_predecessor(&[0]), Some(vec![]));
    assert_eq!(possible_predecessor(&[0, 0]), Some(vec![0]));
    assert_eq!(
        possible_predecessor(&[0, 1]),
        Some(vec![0, 0, 255, 255, 255, 255])
    );
    assert_eq!(
        possible_predecessor(&[0, 2]),
        Some(vec![0, 1, 255, 255, 255, 255])
    );
    assert_eq!(possible_predecessor(&[1, 0]), Some(vec![1]));
    assert_eq!(
        possible_predecessor(&[1, 1]),
        Some(vec![1, 0, 255, 255, 255, 255])
    );
    assert_eq!(
        possible_predecessor(&[155]),
        Some(vec![154, 255, 255, 255, 255])
    );
}
<commit_msg>Make iteration infinite loop catches consistent<commit_after>use std::ops::Bound;

use pagecache::{Measure, M};

use super::*;

const MAX_LOOPS: usize = 10_000;

fn possible_predecessor(s: &[u8]) -> Option<Vec<u8>> {
    let mut ret = s.to_vec();
    match ret.pop() {
        None => None,
        Some(i) if i == 0 => Some(ret),
        Some(i) => {
            ret.push(i - 1);
            for _ in 0..4 {
                ret.push(255);
            }
            Some(ret)
        }
    }
}

macro_rules! iter_try {
    ($e:expr) => {
        match $e {
            Ok(item) => item,
            Err(e) => return Some(Err(e)),
        }
    };
}

/// An iterator over keys and values in a `Tree`.
pub struct Iter<'a> {
    pub(super) tree: &'a Tree,
    pub(super) hi: Bound<IVec>,
    pub(super) lo: Bound<IVec>,
    pub(super) cached_view: Option<View<'a>>,
    pub(super) tx: Result<Tx<'a, BLinkMaterializer, Frag>>,
    pub(super) going_forward: bool,
}

impl<'a> Iter<'a> {
    /// Iterate over the keys of this Tree
    pub fn keys(self) -> impl 'a + DoubleEndedIterator<Item = Result<IVec>> {
        self.map(|r| r.map(|(k, _v)| k))
    }

    /// Iterate over the values of this Tree
    pub fn values(self) -> impl 'a + DoubleEndedIterator<Item = Result<IVec>> {
        self.map(|r| r.map(|(_k, v)| v))
    }

    fn bounds_collapsed(&self) -> bool {
        match (&self.lo, &self.hi) {
            (Bound::Included(ref start), Bound::Included(ref end))
            | (Bound::Included(ref start), Bound::Excluded(ref end))
            | (Bound::Excluded(ref start), Bound::Included(ref end))
            | (Bound::Excluded(ref start), Bound::Excluded(ref end)) => {
                start > end
            }
            _ => false,
        }
    }

    fn low_key(&self) -> &[u8] {
        match self.lo {
            Bound::Unbounded => &[],
            Bound::Excluded(ref lo) | Bound::Included(ref lo) => lo.as_ref(),
        }
    }

    fn high_key(&self) -> &[u8] {
        const MAX_KEY: &[u8] = &[255; 1024 * 1024];
        match self.hi {
            Bound::Unbounded => MAX_KEY,
            Bound::Excluded(ref hi) | Bound::Included(ref hi) => hi.as_ref(),
        }
    }
}

impl<'a> Iterator for Iter<'a> {
    type Item = Result<(IVec, IVec)>;

    fn next(&mut self) -> Option<Self::Item> {
        let _measure = Measure::new(&M.tree_scan);

        let tx: &'a Tx<'a, _, _> = match self.tx {
            Ok(ref tx) => {
                let tx_ref = tx as *const Tx<'a, _, _>;
                unsafe { &*tx_ref as &'a Tx<'a, _, _> }
            }
            Err(ref e) => return Some(Err(e.clone())),
        };

        let mut view = match (self.going_forward, self.cached_view.take()) {
            (true, Some(view)) => view,
            _ => iter_try!(self.tree.view_for_key(self.low_key(), &tx)),
        };

        for _ in 0..MAX_LOOPS {
            if self.bounds_collapsed() {
                return None;
            }

            if !view.contains_upper_bound(&self.lo) {
                // view too low (maybe merged, maybe exhausted?)
                let next_pid = view.next?;
                if let Some(v) =
                    iter_try!(self.tree.view_for_pid(next_pid, &tx))
                {
                    view = v;
                }
                continue;
            } else if !view.contains_lower_bound(&self.lo, true) {
                // view too high (maybe split, maybe exhausted?)
                let seek_key = possible_predecessor(view.lo)?;
                view = iter_try!(self.tree.view_for_key(seek_key, &tx));
                continue;
            }

            if let Some((key, value)) =
                view.successor(&self.lo, &self.tree.context)
            {
                self.lo = Bound::Excluded(key.clone());
                self.cached_view = Some(view);
                self.going_forward = true;

                match self.hi {
                    Bound::Unbounded => return Some(Ok((key, value))),
                    Bound::Included(ref h) if *h >= key => {
                        return Some(Ok((key, value)));
                    }
                    Bound::Excluded(ref h) if *h > key => {
                        return Some(Ok((key, value)));
                    }
                    _ => return None,
                }
            } else {
                if view.hi.is_empty() {
                    return None;
                }
                self.lo = Bound::Included(view.hi.clone());
                continue;
            }
        }
        panic!(
            "fucked up tree traversal next({:?}) on {:?}",
            self.lo, self.tree
        );
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        let _measure = Measure::new(&M.tree_reverse_scan);

        let tx: &'a Tx<'a, _, _> = match self.tx {
            Ok(ref tx) => {
                let tx_ref = tx as *const Tx<'a, _, _>;
                unsafe { &*tx_ref as &'a Tx<'a, _, _> }
            }
            Err(ref e) => return Some(Err(e.clone())),
        };

        let mut view = match (self.going_forward, self.cached_view.take()) {
            (false, Some(view)) => view,
            _ => iter_try!(self.tree.view_for_key(self.high_key(), &tx)),
        };

        for _ in 0..MAX_LOOPS {
            if self.bounds_collapsed() {
                return None;
            }

            if !view.contains_upper_bound(&self.hi) {
                // view too low (maybe merged, maybe exhausted?)
                let next_pid = view.next?;
                if let Some(v) =
                    iter_try!(self.tree.view_for_pid(next_pid, &tx))
                {
                    view = v;
                }
                continue;
            } else if !view.contains_lower_bound(&self.hi, false) {
                // view too high (maybe split, maybe exhausted?)
                let seek_key = possible_predecessor(view.lo)?;
                view = iter_try!(self.tree.view_for_key(seek_key, &tx));
                continue;
            }

            if let Some((key, value)) =
                view.predecessor(&self.hi, &self.tree.context)
            {
                self.hi = Bound::Excluded(key.clone());
                self.cached_view = Some(view);
                self.going_forward = false;

                match self.lo {
                    Bound::Unbounded => return Some(Ok((key, value))),
                    Bound::Included(ref l) if *l <= key => {
                        return Some(Ok((key, value)));
                    }
                    Bound::Excluded(ref l) if *l < key => {
                        return Some(Ok((key, value)));
                    }
                    _ => {
                        return None;
                    }
                }
            } else {
                if view.lo.is_empty() {
                    return None;
                }
                self.hi = Bound::Excluded(view.lo.clone());
                continue;
            }
        }
        panic!(
            "fucked up tree traversal next_back({:?}) on {:?}",
            self.hi, self.tree
        );
    }
}

#[test]
fn test_possible_predecessor() {
    assert_eq!(possible_predecessor(b""), None);
    assert_eq!(possible_predecessor(&[0]), Some(vec![]));
    assert_eq!(possible_predecessor(&[0, 0]), Some(vec![0]));
    assert_eq!(
        possible_predecessor(&[0, 1]),
        Some(vec![0, 0, 255, 255, 255, 255])
    );
    assert_eq!(
        possible_predecessor(&[0, 2]),
        Some(vec![0, 1, 255, 255, 255, 255])
    );
    assert_eq!(possible_predecessor(&[1, 0]), Some(vec![1]));
    assert_eq!(
        possible_predecessor(&[1, 1]),
        Some(vec![1, 0, 255, 255, 255, 255])
    );
    assert_eq!(
        possible_predecessor(&[155]),
        Some(vec![154, 255, 255, 255, 255])
    );
}
<|endoftext|>