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

//! Programmable flash device that supports the minimum interface that OVMF
//! requires. This is purpose-built to allow OVMF to store UEFI variables in
//! the same way that it stores them on QEMU.
//!
//! For that reason it's heavily based on [QEMU's pflash implementation], while
//! taking even more shortcuts, chief among them being the complete lack of CFI
//! tables, which systems would normally use to learn how to use the device.
//!
//! In addition to full-width reads, we only support single byte writes,
//! block erases, and status requests, which OVMF uses to probe the device to
//! determine if it is pflash.
//!
//! Note that without SMM support in crosvm (which it doesn't yet have) this
//! device is directly accessible to potentially malicious kernels. With SMM
//! and the appropriate changes to this device this could be made more secure
//! by ensuring only the BIOS is able to touch the pflash.
//!
//! [QEMU's pflash implementation]: https://github.com/qemu/qemu/blob/master/hw/block/pflash_cfi01.c

use std::path::PathBuf;

use anyhow::bail;
use base::error;
use data_model::VolatileSlice;
use disk::DiskFile;
use serde::Deserialize;
use serde::Serialize;

use crate::pci::CrosvmDeviceId;
use crate::BusAccessInfo;
use crate::BusDevice;
use crate::DeviceId;

const COMMAND_WRITE_BYTE: u8 = 0x10;
const COMMAND_BLOCK_ERASE: u8 = 0x20;
const COMMAND_CLEAR_STATUS: u8 = 0x50;
const COMMAND_READ_STATUS: u8 = 0x70;
const COMMAND_BLOCK_ERASE_CONFIRM: u8 = 0xd0;
const COMMAND_READ_ARRAY: u8 = 0xff;

const STATUS_READY: u8 = 0x80;

fn pflash_parameters_default_block_size() -> u32 {
    // 4K
    4 * (1 << 10)
}

#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct PflashParameters {
    pub path: PathBuf,
    #[serde(default = "pflash_parameters_default_block_size")]
    pub block_size: u32,
}

#[derive(Debug)]
enum State {
    ReadArray,
    ReadStatus,
    BlockErase(u64),
    Write(u64),
}

pub struct Pflash {
    image: Box<dyn DiskFile>,
    image_size: u64,
    block_size: u32,

    state: State,
    status: u8,
}

impl Pflash {
    pub fn new(image: Box<dyn DiskFile>, block_size: u32) -> anyhow::Result<Pflash> {
        if !block_size.is_power_of_two() {
            bail!("Block size {} is not a power of 2", block_size);
        }
        let image_size = image.get_len()?;
        if image_size % block_size as u64 != 0 {
            bail!(
                "Disk size {} is not a multiple of block size {}",
                image_size,
                block_size
            );
        }

        Ok(Pflash {
            image,
            image_size,
            block_size,
            state: State::ReadArray,
            status: STATUS_READY,
        })
    }
}

impl BusDevice for Pflash {
    fn device_id(&self) -> DeviceId {
        CrosvmDeviceId::Pflash.into()
    }

    fn debug_label(&self) -> String {
        "pflash".to_owned()
    }

    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        let offset = info.offset;
        match &self.state {
            State::ReadArray => {
                self.status = STATUS_READY;

                if offset + data.len() as u64 >= self.image_size {
                    error!("pflash read request beyond disk");
                    return;
                }
                if let Err(e) = self
                    .image
                    .read_exact_at_volatile(VolatileSlice::new(data), offset)
                {
                    error!("pflash failed to read: {}", e);
                }
            }
            State::ReadStatus => {
                self.state = State::ReadArray;
                for d in data {
                    *d = self.status;
                }
            }
            _ => {
                error!(
                    "pflash received unexpected read in state {:?}, recovering to ReadArray mode",
                    self.state
                );
                self.state = State::ReadArray;
            }
        }
    }

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        if data.len() > 1 {
            error!("pflash write request for >1 byte, ignoring");
            return;
        }
        let data = data[0];
        let offset = info.offset;

        match self.state {
            State::Write(expected_offset) => {
                self.state = State::ReadArray;
                self.status = STATUS_READY;

                if offset != expected_offset {
                    error!("pflash received write for offset {} that doesn't match offset from WRITE_BYTE command {}", offset, expected_offset);
                    return;
                }
                if offset >= self.image_size {
                    error!(
                        "pflash offset {} greater than image size {}",
                        offset, self.image_size
                    );
                    return;
                }

                if let Err(e) = self
                    .image
                    .write_all_at_volatile(VolatileSlice::new(&mut [data]), offset)
                {
                    error!("failed to write to pflash: {}", e);
                }
            }
            State::BlockErase(expected_offset) => {
                self.state = State::ReadArray;
                self.status = STATUS_READY;

                if data != COMMAND_BLOCK_ERASE_CONFIRM {
                    error!("pflash write data {} after BLOCK_ERASE command, wanted COMMAND_BLOCK_ERASE_CONFIRM", data);
                    return;
                }
                if offset != expected_offset {
                    error!("pflash offset {} for BLOCK_ERASE_CONFIRM command does not match the one for BLOCK_ERASE {}", offset, expected_offset);
                    return;
                }
                if offset >= self.image_size {
                    error!(
                        "pflash block erase attempt offset {} beyond image size {}",
                        offset, self.image_size
                    );
                    return;
                }
                if offset % self.block_size as u64 != 0 {
                    error!(
                        "pflash block erase offset {} not on block boundary with block size {}",
                        offset, self.block_size
                    );
                    return;
                }

                if let Err(e) = self.image.write_all_at_volatile(
                    VolatileSlice::new(&mut [0xff].repeat(self.block_size.try_into().unwrap())),
                    offset,
                ) {
                    error!("pflash failed to erase block: {}", e);
                }
            }
            _ => {
                // If we're not expecting anything else then assume this is a
                // command to transition states.
                let command = data;

                match command {
                    COMMAND_READ_ARRAY => self.state = State::ReadArray,
                    COMMAND_READ_STATUS => self.state = State::ReadStatus,
                    COMMAND_CLEAR_STATUS => {
                        self.state = State::ReadArray;
                        self.status = 0;
                    }
                    COMMAND_WRITE_BYTE => self.state = State::Write(offset),
                    COMMAND_BLOCK_ERASE => self.state = State::BlockErase(offset),
                    _ => {
                        error!("received unexpected/unsupported pflash command {}, ignoring and returning to read mode", command);
                        self.state = State::ReadArray
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use base::FileReadWriteAtVolatile;
    use tempfile::tempfile;

    use super::*;

    const IMAGE_SIZE: usize = 4 * (1 << 20); // 4M
    const BLOCK_SIZE: u32 = 4 * (1 << 10); // 4K

    fn empty_image() -> Box<dyn DiskFile> {
        let mut f = Box::new(tempfile().unwrap());
        f.write_all_at_volatile(VolatileSlice::new(&mut [0xff].repeat(IMAGE_SIZE)), 0)
            .unwrap();
        f
    }

    fn new(f: Box<dyn DiskFile>) -> Pflash {
        Pflash::new(f, BLOCK_SIZE).unwrap()
    }

    fn off(offset: u64) -> BusAccessInfo {
        BusAccessInfo {
            offset,
            address: 0,
            id: 0,
        }
    }

    #[test]
    fn read() {
        let mut f = empty_image();
        let mut want = [0xde, 0xad, 0xbe, 0xef];
        let offset = 0x1000;
        f.write_all_at_volatile(VolatileSlice::new(&mut want), offset)
            .unwrap();

        let mut pflash = new(f);
        let mut got = [0u8; 4];
        pflash.read(off(offset), &mut got[..]);
        assert_eq!(want, got);
    }

    #[test]
    fn write() {
        let f = empty_image();
        let want = [0xdeu8];
        let offset = 0x1000;

        let mut pflash = new(f);
        pflash.write(off(offset), &[COMMAND_WRITE_BYTE]);
        pflash.write(off(offset), &want);

        // Make sure the data reads back correctly over the bus...
        pflash.write(off(0), &[COMMAND_READ_ARRAY]);
        let mut got = [0u8; 1];
        pflash.read(off(offset), &mut got);
        assert_eq!(want, got);

        // And from the backing file itself...
        pflash
            .image
            .read_exact_at_volatile(VolatileSlice::new(&mut got), offset)
            .unwrap();
        assert_eq!(want, got);

        // And when we recreate the device.
        let mut pflash = new(pflash.image);
        pflash.read(off(offset), &mut got);
        assert_eq!(want, got);

        // Finally make sure our status is ready.
        let mut got = [0u8; 4];
        pflash.write(off(offset), &[COMMAND_READ_STATUS]);
        pflash.read(off(offset), &mut got);
        let want = [STATUS_READY; 4];
        assert_eq!(want, got);
    }

    #[test]
    fn erase() {
        let mut f = empty_image();
        let mut data = [0xde, 0xad, 0xbe, 0xef];
        let offset = 0x1000;
        f.write_all_at_volatile(VolatileSlice::new(&mut data), offset)
            .unwrap();
        f.write_all_at_volatile(VolatileSlice::new(&mut data), offset * 2)
            .unwrap();

        let mut pflash = new(f);
        pflash.write(off(offset), &[COMMAND_BLOCK_ERASE]);
        pflash.write(off(offset), &[COMMAND_BLOCK_ERASE_CONFIRM]);

        pflash.write(off(0), &[COMMAND_READ_ARRAY]);
        let mut got = [0u8; 4];
        pflash.read(off(offset), &mut got);
        let want = [0xffu8; 4];
        assert_eq!(want, got);

        let want = data;
        pflash.read(off(offset * 2), &mut got);
        assert_eq!(want, got);

        // Make sure our status is ready.
        pflash.write(off(offset), &[COMMAND_READ_STATUS]);
        pflash.read(off(offset), &mut got);
        let want = [STATUS_READY; 4];
        assert_eq!(want, got);
    }

    #[test]
    fn status() {
        let mut f = empty_image();
        let mut data = [0xde, 0xad, 0xbe, 0xff];
        let offset = 0x0;
        f.write_all_at_volatile(VolatileSlice::new(&mut data), offset)
            .unwrap();

        let mut pflash = new(f);

        // Make sure we start off in the "ready" status.
        pflash.write(off(offset), &[COMMAND_READ_STATUS]);
        let mut got = [0u8; 4];
        pflash.read(off(offset), &mut got);
        let want = [STATUS_READY; 4];
        assert_eq!(want, got);

        // Make sure we can clear the status properly.
        pflash.write(off(offset), &[COMMAND_CLEAR_STATUS]);
        pflash.write(off(offset), &[COMMAND_READ_STATUS]);
        pflash.read(off(offset), &mut got);
        let want = [0; 4];
        assert_eq!(want, got);
    }

    #[test]
    fn overwrite() {
        let f = empty_image();
        let data = [0];
        let offset = off((16 * IMAGE_SIZE).try_into().unwrap());

        // Ensure a write past the pflash device doesn't grow the backing file.
        let mut pflash = new(f);
        let old_size = pflash.image.get_len().unwrap();
        assert_eq!(old_size, IMAGE_SIZE as u64);

        pflash.write(offset, &[COMMAND_WRITE_BYTE]);
        pflash.write(offset, &data);

        let new_size = pflash.image.get_len().unwrap();
        assert_eq!(new_size, IMAGE_SIZE as u64);
    }
}
<commit_msg>devices: pflash: don't set status on each read<commit_after>// Copyright 2022 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.

//! Programmable flash device that supports the minimum interface that OVMF
//! requires. This is purpose-built to allow OVMF to store UEFI variables in
//! the same way that it stores them on QEMU.
//!
//! For that reason it's heavily based on [QEMU's pflash implementation], while
//! taking even more shortcuts, chief among them being the complete lack of CFI
//! tables, which systems would normally use to learn how to use the device.
//!
//! In addition to full-width reads, we only support single byte writes,
//! block erases, and status requests, which OVMF uses to probe the device to
//! determine if it is pflash.
//!
//! Note that without SMM support in crosvm (which it doesn't yet have) this
//! device is directly accessible to potentially malicious kernels. With SMM
//! and the appropriate changes to this device this could be made more secure
//! by ensuring only the BIOS is able to touch the pflash.
//!
//! [QEMU's pflash implementation]: https://github.com/qemu/qemu/blob/master/hw/block/pflash_cfi01.c

use std::path::PathBuf;

use anyhow::bail;
use base::error;
use data_model::VolatileSlice;
use disk::DiskFile;
use serde::Deserialize;
use serde::Serialize;

use crate::pci::CrosvmDeviceId;
use crate::BusAccessInfo;
use crate::BusDevice;
use crate::DeviceId;

const COMMAND_WRITE_BYTE: u8 = 0x10;
const COMMAND_BLOCK_ERASE: u8 = 0x20;
const COMMAND_CLEAR_STATUS: u8 = 0x50;
const COMMAND_READ_STATUS: u8 = 0x70;
const COMMAND_BLOCK_ERASE_CONFIRM: u8 = 0xd0;
const COMMAND_READ_ARRAY: u8 = 0xff;

const STATUS_READY: u8 = 0x80;

fn pflash_parameters_default_block_size() -> u32 {
    // 4K
    4 * (1 << 10)
}

#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct PflashParameters {
    pub path: PathBuf,
    #[serde(default = "pflash_parameters_default_block_size")]
    pub block_size: u32,
}

#[derive(Debug)]
enum State {
    ReadArray,
    ReadStatus,
    BlockErase(u64),
    Write(u64),
}

pub struct Pflash {
    image: Box<dyn DiskFile>,
    image_size: u64,
    block_size: u32,

    state: State,
    status: u8,
}

impl Pflash {
    pub fn new(image: Box<dyn DiskFile>, block_size: u32) -> anyhow::Result<Pflash> {
        if !block_size.is_power_of_two() {
            bail!("Block size {} is not a power of 2", block_size);
        }
        let image_size = image.get_len()?;
        if image_size % block_size as u64 != 0 {
            bail!(
                "Disk size {} is not a multiple of block size {}",
                image_size,
                block_size
            );
        }

        Ok(Pflash {
            image,
            image_size,
            block_size,
            state: State::ReadArray,
            status: STATUS_READY,
        })
    }
}

impl BusDevice for Pflash {
    fn device_id(&self) -> DeviceId {
        CrosvmDeviceId::Pflash.into()
    }

    fn debug_label(&self) -> String {
        "pflash".to_owned()
    }

    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        let offset = info.offset;
        match &self.state {
            State::ReadArray => {
                if offset + data.len() as u64 >= self.image_size {
                    error!("pflash read request beyond disk");
                    return;
                }
                if let Err(e) = self
                    .image
                    .read_exact_at_volatile(VolatileSlice::new(data), offset)
                {
                    error!("pflash failed to read: {}", e);
                }
            }
            State::ReadStatus => {
                self.state = State::ReadArray;
                for d in data {
                    *d = self.status;
                }
            }
            _ => {
                error!(
                    "pflash received unexpected read in state {:?}, recovering to ReadArray mode",
                    self.state
                );
                self.state = State::ReadArray;
            }
        }
    }

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        if data.len() > 1 {
            error!("pflash write request for >1 byte, ignoring");
            return;
        }
        let data = data[0];
        let offset = info.offset;

        match self.state {
            State::Write(expected_offset) => {
                self.state = State::ReadArray;
                self.status = STATUS_READY;

                if offset != expected_offset {
                    error!("pflash received write for offset {} that doesn't match offset from WRITE_BYTE command {}", offset, expected_offset);
                    return;
                }
                if offset >= self.image_size {
                    error!(
                        "pflash offset {} greater than image size {}",
                        offset, self.image_size
                    );
                    return;
                }

                if let Err(e) = self
                    .image
                    .write_all_at_volatile(VolatileSlice::new(&mut [data]), offset)
                {
                    error!("failed to write to pflash: {}", e);
                }
            }
            State::BlockErase(expected_offset) => {
                self.state = State::ReadArray;
                self.status = STATUS_READY;

                if data != COMMAND_BLOCK_ERASE_CONFIRM {
                    error!("pflash write data {} after BLOCK_ERASE command, wanted COMMAND_BLOCK_ERASE_CONFIRM", data);
                    return;
                }
                if offset != expected_offset {
                    error!("pflash offset {} for BLOCK_ERASE_CONFIRM command does not match the one for BLOCK_ERASE {}", offset, expected_offset);
                    return;
                }
                if offset >= self.image_size {
                    error!(
                        "pflash block erase attempt offset {} beyond image size {}",
                        offset, self.image_size
                    );
                    return;
                }
                if offset % self.block_size as u64 != 0 {
                    error!(
                        "pflash block erase offset {} not on block boundary with block size {}",
                        offset, self.block_size
                    );
                    return;
                }

                if let Err(e) = self.image.write_all_at_volatile(
                    VolatileSlice::new(&mut [0xff].repeat(self.block_size.try_into().unwrap())),
                    offset,
                ) {
                    error!("pflash failed to erase block: {}", e);
                }
            }
            _ => {
                // If we're not expecting anything else then assume this is a
                // command to transition states.
                let command = data;

                match command {
                    COMMAND_READ_ARRAY => {
                        self.state = State::ReadArray;
                        self.status = STATUS_READY;
                    }
                    COMMAND_READ_STATUS => self.state = State::ReadStatus,
                    COMMAND_CLEAR_STATUS => {
                        self.state = State::ReadArray;
                        self.status = 0;
                    }
                    COMMAND_WRITE_BYTE => self.state = State::Write(offset),
                    COMMAND_BLOCK_ERASE => self.state = State::BlockErase(offset),
                    _ => {
                        error!("received unexpected/unsupported pflash command {}, ignoring and returning to read mode", command);
                        self.state = State::ReadArray
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use base::FileReadWriteAtVolatile;
    use tempfile::tempfile;

    use super::*;

    const IMAGE_SIZE: usize = 4 * (1 << 20); // 4M
    const BLOCK_SIZE: u32 = 4 * (1 << 10); // 4K

    fn empty_image() -> Box<dyn DiskFile> {
        let mut f = Box::new(tempfile().unwrap());
        f.write_all_at_volatile(VolatileSlice::new(&mut [0xff].repeat(IMAGE_SIZE)), 0)
            .unwrap();
        f
    }

    fn new(f: Box<dyn DiskFile>) -> Pflash {
        Pflash::new(f, BLOCK_SIZE).unwrap()
    }

    fn off(offset: u64) -> BusAccessInfo {
        BusAccessInfo {
            offset,
            address: 0,
            id: 0,
        }
    }

    #[test]
    fn read() {
        let mut f = empty_image();
        let mut want = [0xde, 0xad, 0xbe, 0xef];
        let offset = 0x1000;
        f.write_all_at_volatile(VolatileSlice::new(&mut want), offset)
            .unwrap();

        let mut pflash = new(f);
        let mut got = [0u8; 4];
        pflash.read(off(offset), &mut got[..]);
        assert_eq!(want, got);
    }

    #[test]
    fn write() {
        let f = empty_image();
        let want = [0xdeu8];
        let offset = 0x1000;

        let mut pflash = new(f);
        pflash.write(off(offset), &[COMMAND_WRITE_BYTE]);
        pflash.write(off(offset), &want);

        // Make sure the data reads back correctly over the bus...
        pflash.write(off(0), &[COMMAND_READ_ARRAY]);
        let mut got = [0u8; 1];
        pflash.read(off(offset), &mut got);
        assert_eq!(want, got);

        // And from the backing file itself...
        pflash
            .image
            .read_exact_at_volatile(VolatileSlice::new(&mut got), offset)
            .unwrap();
        assert_eq!(want, got);

        // And when we recreate the device.
        let mut pflash = new(pflash.image);
        pflash.read(off(offset), &mut got);
        assert_eq!(want, got);

        // Finally make sure our status is ready.
        let mut got = [0u8; 4];
        pflash.write(off(offset), &[COMMAND_READ_STATUS]);
        pflash.read(off(offset), &mut got);
        let want = [STATUS_READY; 4];
        assert_eq!(want, got);
    }

    #[test]
    fn erase() {
        let mut f = empty_image();
        let mut data = [0xde, 0xad, 0xbe, 0xef];
        let offset = 0x1000;
        f.write_all_at_volatile(VolatileSlice::new(&mut data), offset)
            .unwrap();
        f.write_all_at_volatile(VolatileSlice::new(&mut data), offset * 2)
            .unwrap();

        let mut pflash = new(f);
        pflash.write(off(offset), &[COMMAND_BLOCK_ERASE]);
        pflash.write(off(offset), &[COMMAND_BLOCK_ERASE_CONFIRM]);

        pflash.write(off(0), &[COMMAND_READ_ARRAY]);
        let mut got = [0u8; 4];
        pflash.read(off(offset), &mut got);
        let want = [0xffu8; 4];
        assert_eq!(want, got);

        let want = data;
        pflash.read(off(offset * 2), &mut got);
        assert_eq!(want, got);

        // Make sure our status is ready.
        pflash.write(off(offset), &[COMMAND_READ_STATUS]);
        pflash.read(off(offset), &mut got);
        let want = [STATUS_READY; 4];
        assert_eq!(want, got);
    }

    #[test]
    fn status() {
        let mut f = empty_image();
        let mut data = [0xde, 0xad, 0xbe, 0xff];
        let offset = 0x0;
        f.write_all_at_volatile(VolatileSlice::new(&mut data), offset)
            .unwrap();

        let mut pflash = new(f);

        // Make sure we start off in the "ready" status.
        pflash.write(off(offset), &[COMMAND_READ_STATUS]);
        let mut got = [0u8; 4];
        pflash.read(off(offset), &mut got);
        let want = [STATUS_READY; 4];
        assert_eq!(want, got);

        // Make sure we can clear the status properly.
        pflash.write(off(offset), &[COMMAND_CLEAR_STATUS]);
        pflash.write(off(offset), &[COMMAND_READ_STATUS]);
        pflash.read(off(offset), &mut got);
        let want = [0; 4];
        assert_eq!(want, got);

        // We implicitly jump back into READ_ARRAY mode after reading the,
        // status but for OVMF's probe we require that this doesn't actually
        // affect the cleared status.
        pflash.read(off(offset), &mut got);
        pflash.write(off(offset), &[COMMAND_READ_STATUS]);
        pflash.read(off(offset), &mut got);
        let want = [0; 4];
        assert_eq!(want, got);
    }

    #[test]
    fn overwrite() {
        let f = empty_image();
        let data = [0];
        let offset = off((16 * IMAGE_SIZE).try_into().unwrap());

        // Ensure a write past the pflash device doesn't grow the backing file.
        let mut pflash = new(f);
        let old_size = pflash.image.get_len().unwrap();
        assert_eq!(old_size, IMAGE_SIZE as u64);

        pflash.write(offset, &[COMMAND_WRITE_BYTE]);
        pflash.write(offset, &data);

        let new_size = pflash.image.get_len().unwrap();
        assert_eq!(new_size, IMAGE_SIZE as u64);
    }
}
<|endoftext|>


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

#[allow(dead_code)]
#[derive(PartialEq, Eq, Hash, Debug)]
pub enum Method {
    Get,
    Put,
    Post,
    Delete,
    NoImpl,
}

pub trait FromUri {
    fn from_uri(data: &str) -> Self;
}

impl FromUri for String {
    fn from_uri(data: &str) -> String {
        String::from(data)
    }
}

impl FromUri for i32 {
    fn from_uri(data: &str) -> i32 {
        match data.parse::<i32>() {
            Ok(v)  => v,
            Err(e) => panic!("matched integer can't be parsed: {:?}", e),
        }
    }
}

impl FromUri for f32 {
    fn from_uri(data: &str) -> f32 {
        match data.parse::<f32>() {
            Ok(v)  => v,
            Err(e) => panic!("matched float can't be parsed: {:?}", e),
        }
    }
}

#[derive(Debug)]
pub struct Request {
    pub method: Method,
    pub path:   String,
    pub params: Option<HashMap<String, String>>,
    headers:    HashMap<String, String>,
    payload:    Vec<u8>,
}

impl Request {
    pub fn new() -> Request {
        Request {
            method:  Method::NoImpl,
            path:    String::new(),
            headers: HashMap::new(),
            params:  None,
            payload: Vec::new(),
        }
    }

    fn _get(&self, name: &str) -> Option<&String> {
        let val: Option<&String> = match self.params {
            Some(ref p) => p.get(name),
            None        => None,
        };

        val
    }

    pub fn get<T>(&self, name: &str) -> T where T: FromUri {
        match self._get(&name) {
            Some(item) => FromUri::from_uri(&item),
            None       => panic!("invalid route parameter {:?}", name),
        }
    }

    pub fn from_str(rqstr: &str) -> Request {
        let mut req = Request::new();
        req.parse(rqstr);
        req
    }

    pub fn parse(&mut self, rqstr: &str) {
        let mut buf: Vec<&str> = rqstr.splitn(2, "\r\n").collect();
        let ask: Vec<&str> = buf[0].splitn(3, ' ').collect();

        println!("{:?}", ask);

        self.method = match ask[0] {
            "GET"           => Method::Get,
            "PUT" | "PATCH" => Method::Put,
            "POST"          => Method::Post,
            "DELETE"        => Method::Delete,
            _               => Method::NoImpl,
        };
        self.path = String::from(ask[1]);

        loop {
            buf = buf[1].splitn(2, "\r\n").collect();

            if buf[0] == "" {
                if buf[1] == "" {
                    /* no payload */
                    break;
                }

                let tmp: String;
                buf = buf[1].splitn(2, "\r\n").collect();
                tmp = String::from(buf[1]);
                self.payload.extend(tmp.as_bytes());
                break;
            }

            let hdr: Vec<&str> = buf[0].splitn(2, ": ").collect();

            if hdr.len() == 2 {
                self.headers.insert(String::from(hdr[0]), String::from(hdr[1]));
            }
        }
    }

    pub fn has_params(&self) -> bool {
        match self.params {
            Some(_) => true,
            None    => false,
        }
    }
}
<commit_msg>fix a few little bugs in canteen<commit_after>use std::collections::HashMap;

#[allow(dead_code)]
#[derive(PartialEq, Eq, Hash, Debug)]
pub enum Method {
    Get,
    Put,
    Post,
    Delete,
    NoImpl,
}

pub trait FromUri {
    fn from_uri(data: &str) -> Self;
}

impl FromUri for String {
    fn from_uri(data: &str) -> String {
        String::from(data)
    }
}

impl FromUri for i32 {
    fn from_uri(data: &str) -> i32 {
        match data.parse::<i32>() {
            Ok(v)  => v,
            Err(e) => panic!("matched integer can't be parsed: {:?}", e),
        }
    }
}

impl FromUri for f32 {
    fn from_uri(data: &str) -> f32 {
        match data.parse::<f32>() {
            Ok(v)  => v,
            Err(e) => panic!("matched float can't be parsed: {:?}", e),
        }
    }
}

#[derive(Debug)]
pub struct Request {
    pub method:  Method,
    pub path:    String,
    pub params:  Option<HashMap<String, String>>,
    pub payload: Vec<u8>,
    headers:     HashMap<String, String>,
}

impl Request {
    pub fn new() -> Request {
        Request {
            method:  Method::NoImpl,
            path:    String::new(),
            headers: HashMap::new(),
            params:  None,
            payload: Vec::new(),
        }
    }

    fn _get(&self, name: &str) -> Option<&String> {
        let val: Option<&String> = match self.params {
            Some(ref p) => p.get(name),
            None        => None,
        };

        val
    }

    pub fn get<T>(&self, name: &str) -> T where T: FromUri {
        match self._get(&name) {
            Some(item) => FromUri::from_uri(&item),
            None       => panic!("invalid route parameter {:?}", name),
        }
    }

    pub fn from_str(rqstr: &str) -> Request {
        let mut req = Request::new();
        req.parse(rqstr);
        req
    }

    pub fn parse(&mut self, rqstr: &str) {
        let mut buf: Vec<&str> = rqstr.splitn(2, "\r\n").collect();
        let ask: Vec<&str> = buf[0].splitn(3, ' ').collect();

        println!("{:?}", ask);

        self.method = match ask[0] {
            "GET"           => Method::Get,
            "PUT" | "PATCH" => Method::Put,
            "POST"          => Method::Post,
            "DELETE"        => Method::Delete,
            _               => Method::NoImpl,
        };
        self.path = String::from(ask[1]);

        loop {
            buf = buf[1].splitn(2, "\r\n").collect();
            println!("{:?}", buf);

            if buf[0] == "" {
                if buf.len() == 1 || buf[1] == "" {
                    /* no payload */
                    break;
                }

                let tmp: String;
                tmp = String::from(buf[1]);
                self.payload.extend(tmp.as_bytes());
                break;
            }

            let hdr: Vec<&str> = buf[0].splitn(2, ": ").collect();

            if hdr.len() == 2 {
                self.headers.insert(String::from(hdr[0]), String::from(hdr[1]));
            }
        }
    }

    pub fn has_params(&self) -> bool {
        match self.params {
            Some(_) => true,
            None    => false,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    chain_state::ChainState, data_cache::RemoteCache, execution_context::InterpreterContext,
    loaded_data::loaded_module::LoadedModule, runtime::VMRuntime,
};
use bytecode_verifier::VerifiedModule;
use libra_types::identifier::Identifier;
use libra_types::{identifier::IdentStr, language_storage::ModuleId};
use move_vm_definition::MoveVMImpl;
use vm::{errors::VMResult, gas_schedule::CostTable, transaction_metadata::TransactionMetadata};
use vm_cache_map::Arena;
use vm_runtime_types::{loaded_data::struct_def::StructDef, values::Value};

rental! {
    mod move_vm_definition {
        use super::*;

        #[rental]
        pub struct MoveVMImpl {
            alloc: Box<Arena<LoadedModule>>,
            runtime: VMRuntime<'alloc>,
        }
    }
}

pub struct MoveVM(MoveVMImpl);

impl MoveVM {
    pub fn new() -> Self {
        MoveVM(MoveVMImpl::new(Box::new(Arena::new()), |arena| {
            VMRuntime::new(&*arena)
        }))
    }

    // API for temporal backward compatibility.
    // TODO: Get rid of it later with the following three api after LibraVM refactor.
    pub fn execute_runtime<F, T>(&self, f: F) -> T
    where
        F: FnOnce(&VMRuntime) -> T,
    {
        self.0.rent(|runtime| f(runtime))
    }

    pub fn execute_function<S: ChainState>(
        &self,
        module: &ModuleId,
        function_name: &IdentStr,
        gas_schedule: &CostTable,
        chain_state: &mut S,
        txn_data: &TransactionMetadata,
        args: Vec<Value>,
    ) -> VMResult<()> {
        self.0.rent(|runtime| {
            runtime.execute_function(
                chain_state,
                txn_data,
                gas_schedule,
                module,
                function_name,
                args,
            )
        })
    }

    #[allow(unused)]
    pub fn execute_script<S: ChainState>(
        &self,
        script: Vec<u8>,
        gas_schedule: &CostTable,
        chain_state: &mut S,
        txn_data: &TransactionMetadata,
        args: Vec<Value>,
    ) -> VMResult<()> {
        self.0.rent(|runtime| {
            runtime.execute_script(chain_state, txn_data, gas_schedule, script, args)
        })
    }

    pub fn publish_module<S: ChainState>(
        &self,
        module: Vec<u8>,
        chain_state: &mut S,
        txn_data: &TransactionMetadata,
    ) -> VMResult<()> {
        self.0
            .rent(|runtime| runtime.publish_module(module, chain_state, txn_data))
    }

    pub fn cache_module(&mut self, module: VerifiedModule) {
        self.0.rent_mut(|runtime| runtime.cache_module(module))
    }

    pub fn resolve_struct_def_by_name(
        &self,
        module_id: &ModuleId,
        name: &Identifier,
        context: &mut dyn InterpreterContext,
    ) -> VMResult<StructDef> {
        self.0
            .rent(|runtime| runtime.resolve_struct_def_by_name(module_id, name, context))
    }

    pub fn load_gas_schedule<S: ChainState>(
        &self,
        chain_state: &mut S,
        data_view: &dyn RemoteCache,
    ) -> VMResult<CostTable> {
        self.0
            .rent(|runtime| runtime.load_gas_schedule(chain_state, data_view))
    }
}

impl Default for MoveVM {
    fn default() -> Self {
        Self::new()
    }
}
<commit_msg>[vm-runtime] make resolve_struct_def_by_name use the ChainState API<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    chain_state::ChainState, data_cache::RemoteCache, loaded_data::loaded_module::LoadedModule,
    runtime::VMRuntime,
};
use bytecode_verifier::VerifiedModule;
use libra_types::identifier::Identifier;
use libra_types::{identifier::IdentStr, language_storage::ModuleId};
use move_vm_definition::MoveVMImpl;
use vm::{errors::VMResult, gas_schedule::CostTable, transaction_metadata::TransactionMetadata};
use vm_cache_map::Arena;
use vm_runtime_types::{loaded_data::struct_def::StructDef, values::Value};

rental! {
    mod move_vm_definition {
        use super::*;

        #[rental]
        pub struct MoveVMImpl {
            alloc: Box<Arena<LoadedModule>>,
            runtime: VMRuntime<'alloc>,
        }
    }
}

pub struct MoveVM(MoveVMImpl);

impl MoveVM {
    pub fn new() -> Self {
        MoveVM(MoveVMImpl::new(Box::new(Arena::new()), |arena| {
            VMRuntime::new(&*arena)
        }))
    }

    // API for temporal backward compatibility.
    // TODO: Get rid of it later with the following three api after LibraVM refactor.
    pub fn execute_runtime<F, T>(&self, f: F) -> T
    where
        F: FnOnce(&VMRuntime) -> T,
    {
        self.0.rent(|runtime| f(runtime))
    }

    pub fn execute_function<S: ChainState>(
        &self,
        module: &ModuleId,
        function_name: &IdentStr,
        gas_schedule: &CostTable,
        chain_state: &mut S,
        txn_data: &TransactionMetadata,
        args: Vec<Value>,
    ) -> VMResult<()> {
        self.0.rent(|runtime| {
            runtime.execute_function(
                chain_state,
                txn_data,
                gas_schedule,
                module,
                function_name,
                args,
            )
        })
    }

    #[allow(unused)]
    pub fn execute_script<S: ChainState>(
        &self,
        script: Vec<u8>,
        gas_schedule: &CostTable,
        chain_state: &mut S,
        txn_data: &TransactionMetadata,
        args: Vec<Value>,
    ) -> VMResult<()> {
        self.0.rent(|runtime| {
            runtime.execute_script(chain_state, txn_data, gas_schedule, script, args)
        })
    }

    pub fn publish_module<S: ChainState>(
        &self,
        module: Vec<u8>,
        chain_state: &mut S,
        txn_data: &TransactionMetadata,
    ) -> VMResult<()> {
        self.0
            .rent(|runtime| runtime.publish_module(module, chain_state, txn_data))
    }

    pub fn cache_module(&mut self, module: VerifiedModule) {
        self.0.rent_mut(|runtime| runtime.cache_module(module))
    }

    pub fn resolve_struct_def_by_name<S: ChainState>(
        &self,
        module_id: &ModuleId,
        name: &Identifier,
        chain_state: &mut S,
    ) -> VMResult<StructDef> {
        self.0
            .rent(|runtime| runtime.resolve_struct_def_by_name(module_id, name, chain_state))
    }

    pub fn load_gas_schedule<S: ChainState>(
        &self,
        chain_state: &mut S,
        data_view: &dyn RemoteCache,
    ) -> VMResult<CostTable> {
        self.0
            .rent(|runtime| runtime.load_gas_schedule(chain_state, data_view))
    }
}

impl Default for MoveVM {
    fn default() -> Self {
        Self::new()
    }
}
<|endoftext|>


<commit_before>//! Complete fields in record literals and patterns.
use ra_syntax::{ast, ast::NameOwner, SmolStr};

use crate::completion::{CompletionContext, Completions};

pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
    let (ty, variant, already_present_fields) =
        match (ctx.record_lit_pat.as_ref(), ctx.record_lit_syntax.as_ref()) {
            (None, None) => return None,
            (Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"),
            (Some(record_pat), _) => (
                ctx.sema.type_of_pat(&record_pat.clone().into())?,
                ctx.sema.resolve_record_pattern(record_pat)?,
                pattern_ascribed_fields(record_pat),
            ),
            (_, Some(record_lit)) => (
                ctx.sema.type_of_expr(&record_lit.clone().into())?,
                ctx.sema.resolve_record_literal(record_lit)?,
                literal_ascribed_fields(record_lit),
            ),
        };

    for (field, field_ty) in ty.variant_fields(ctx.db, variant).into_iter().filter(|(field, _)| {
        // FIXME: already_present_names better be `Vec<hir::Name>`
        !already_present_fields.contains(&SmolStr::from(field.name(ctx.db).to_string()))
    }) {
        acc.add_field(ctx, field, &field_ty);
    }
    Some(())
}

fn literal_ascribed_fields(record_lit: &ast::RecordLit) -> Vec<SmolStr> {
    record_lit
        .record_field_list()
        .map(|field_list| field_list.fields())
        .map(|fields| {
            fields
                .into_iter()
                .filter_map(|field| field.name_ref())
                .map(|name_ref| name_ref.text().clone())
                .collect()
        })
        .unwrap_or_default()
}

fn pattern_ascribed_fields(record_pat: &ast::RecordPat) -> Vec<SmolStr> {
    record_pat
        .record_field_pat_list()
        .map(|pat_list| {
            pat_list
                .record_field_pats()
                .filter_map(|fild_pat| fild_pat.name())
                .chain(pat_list.bind_pats().filter_map(|bind_pat| bind_pat.name()))
                .map(|name| name.text().clone())
                .collect()
        })
        .unwrap_or_default()
}

#[cfg(test)]
mod tests {
    mod record_lit_tests {
        use insta::assert_debug_snapshot;

        use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};

        fn complete(code: &str) -> Vec<CompletionItem> {
            do_completion(code, CompletionKind::Reference)
        }

        #[test]
        fn test_record_pattern_field() {
            let completions = complete(
                r"
            struct S { foo: u32 }

            fn process(f: S) {
                match f {
                    S { f<|>: 92 } => (),
                }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "foo",
                source_range: [117; 118),
                delete: [117; 118),
                insert: "foo",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_pattern_enum_variant() {
            let completions = complete(
                r"
            enum E {
                S { foo: u32, bar: () }
            }

            fn process(e: E) {
                match e {
                    E::S { <|> } => (),
                }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "bar",
                source_range: [161; 161),
                delete: [161; 161),
                insert: "bar",
                kind: Field,
                detail: "()",
            },
            CompletionItem {
                label: "foo",
                source_range: [161; 161),
                delete: [161; 161),
                insert: "foo",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_pattern_field_in_simple_macro() {
            let completions = complete(
                r"
            macro_rules! m { ($e:expr) => { $e } }
            struct S { foo: u32 }

            fn process(f: S) {
                m!(match f {
                    S { f<|>: 92 } => (),
                })
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "foo",
                source_range: [171; 172),
                delete: [171; 172),
                insert: "foo",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn only_missing_fields_are_completed_in_destruct_pats() {
            let completions = complete(
                r"
            struct S {
                foo1: u32,
                foo2: u32,
                bar: u32,
                baz: u32,
            }

            fn main() {
                let s = S {
                    foo1: 1,
                    foo2: 2,
                    bar: 3,
                    baz: 4,
                };
                if let S { foo1, foo2: a, <|> } = s {}
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "bar",
                source_range: [372; 372),
                delete: [372; 372),
                insert: "bar",
                kind: Field,
                detail: "u32",
            },
            CompletionItem {
                label: "baz",
                source_range: [372; 372),
                delete: [372; 372),
                insert: "baz",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }
    }

    mod record_pat_tests {
        use insta::assert_debug_snapshot;

        use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};

        fn complete(code: &str) -> Vec<CompletionItem> {
            do_completion(code, CompletionKind::Reference)
        }

        #[test]
        fn test_record_literal_deprecated_field() {
            let completions = complete(
                r"
            struct A {
                #[deprecated]
                the_field: u32,
            }
            fn foo() {
               A { the<|> }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "the_field",
                source_range: [142; 145),
                delete: [142; 145),
                insert: "the_field",
                kind: Field,
                detail: "u32",
                deprecated: true,
            },
        ]
        "###);
        }

        #[test]
        fn test_record_literal_field() {
            let completions = complete(
                r"
            struct A { the_field: u32 }
            fn foo() {
               A { the<|> }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "the_field",
                source_range: [83; 86),
                delete: [83; 86),
                insert: "the_field",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_literal_enum_variant() {
            let completions = complete(
                r"
            enum E {
                A { a: u32 }
            }
            fn foo() {
                let _ = E::A { <|> }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "a",
                source_range: [119; 119),
                delete: [119; 119),
                insert: "a",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_literal_two_structs() {
            let completions = complete(
                r"
            struct A { a: u32 }
            struct B { b: u32 }

            fn foo() {
               let _: A = B { <|> }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "b",
                source_range: [119; 119),
                delete: [119; 119),
                insert: "b",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_literal_generic_struct() {
            let completions = complete(
                r"
            struct A<T> { a: T }

            fn foo() {
               let _: A<u32> = A { <|> }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "a",
                source_range: [93; 93),
                delete: [93; 93),
                insert: "a",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_literal_field_in_simple_macro() {
            let completions = complete(
                r"
            macro_rules! m { ($e:expr) => { $e } }
            struct A { the_field: u32 }
            fn foo() {
               m!(A { the<|> })
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "the_field",
                source_range: [137; 140),
                delete: [137; 140),
                insert: "the_field",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn only_missing_fields_are_completed() {
            let completions = complete(
                r"
            struct S {
                foo1: u32,
                foo2: u32,
                bar: u32,
                baz: u32,
            }

            fn main() {
                let foo1 = 1;
                let s = S {
                    foo1,
                    foo2: 5,
                    <|>
                }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "bar",
                source_range: [302; 302),
                delete: [302; 302),
                insert: "bar",
                kind: Field,
                detail: "u32",
            },
            CompletionItem {
                label: "baz",
                source_range: [302; 302),
                delete: [302; 302),
                insert: "baz",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }
    }
}
<commit_msg>Fix names of test modules<commit_after>//! Complete fields in record literals and patterns.
use ra_syntax::{ast, ast::NameOwner, SmolStr};

use crate::completion::{CompletionContext, Completions};

pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
    let (ty, variant, already_present_fields) =
        match (ctx.record_lit_pat.as_ref(), ctx.record_lit_syntax.as_ref()) {
            (None, None) => return None,
            (Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"),
            (Some(record_pat), _) => (
                ctx.sema.type_of_pat(&record_pat.clone().into())?,
                ctx.sema.resolve_record_pattern(record_pat)?,
                pattern_ascribed_fields(record_pat),
            ),
            (_, Some(record_lit)) => (
                ctx.sema.type_of_expr(&record_lit.clone().into())?,
                ctx.sema.resolve_record_literal(record_lit)?,
                literal_ascribed_fields(record_lit),
            ),
        };

    for (field, field_ty) in ty.variant_fields(ctx.db, variant).into_iter().filter(|(field, _)| {
        // FIXME: already_present_names better be `Vec<hir::Name>`
        !already_present_fields.contains(&SmolStr::from(field.name(ctx.db).to_string()))
    }) {
        acc.add_field(ctx, field, &field_ty);
    }
    Some(())
}

fn literal_ascribed_fields(record_lit: &ast::RecordLit) -> Vec<SmolStr> {
    record_lit
        .record_field_list()
        .map(|field_list| field_list.fields())
        .map(|fields| {
            fields
                .into_iter()
                .filter_map(|field| field.name_ref())
                .map(|name_ref| name_ref.text().clone())
                .collect()
        })
        .unwrap_or_default()
}

fn pattern_ascribed_fields(record_pat: &ast::RecordPat) -> Vec<SmolStr> {
    record_pat
        .record_field_pat_list()
        .map(|pat_list| {
            pat_list
                .record_field_pats()
                .filter_map(|fild_pat| fild_pat.name())
                .chain(pat_list.bind_pats().filter_map(|bind_pat| bind_pat.name()))
                .map(|name| name.text().clone())
                .collect()
        })
        .unwrap_or_default()
}

#[cfg(test)]
mod tests {
    mod record_pat_tests {
        use insta::assert_debug_snapshot;

        use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};

        fn complete(code: &str) -> Vec<CompletionItem> {
            do_completion(code, CompletionKind::Reference)
        }

        #[test]
        fn test_record_pattern_field() {
            let completions = complete(
                r"
            struct S { foo: u32 }

            fn process(f: S) {
                match f {
                    S { f<|>: 92 } => (),
                }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "foo",
                source_range: [117; 118),
                delete: [117; 118),
                insert: "foo",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_pattern_enum_variant() {
            let completions = complete(
                r"
            enum E {
                S { foo: u32, bar: () }
            }

            fn process(e: E) {
                match e {
                    E::S { <|> } => (),
                }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "bar",
                source_range: [161; 161),
                delete: [161; 161),
                insert: "bar",
                kind: Field,
                detail: "()",
            },
            CompletionItem {
                label: "foo",
                source_range: [161; 161),
                delete: [161; 161),
                insert: "foo",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_pattern_field_in_simple_macro() {
            let completions = complete(
                r"
            macro_rules! m { ($e:expr) => { $e } }
            struct S { foo: u32 }

            fn process(f: S) {
                m!(match f {
                    S { f<|>: 92 } => (),
                })
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "foo",
                source_range: [171; 172),
                delete: [171; 172),
                insert: "foo",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn only_missing_fields_are_completed_in_destruct_pats() {
            let completions = complete(
                r"
            struct S {
                foo1: u32,
                foo2: u32,
                bar: u32,
                baz: u32,
            }

            fn main() {
                let s = S {
                    foo1: 1,
                    foo2: 2,
                    bar: 3,
                    baz: 4,
                };
                if let S { foo1, foo2: a, <|> } = s {}
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "bar",
                source_range: [372; 372),
                delete: [372; 372),
                insert: "bar",
                kind: Field,
                detail: "u32",
            },
            CompletionItem {
                label: "baz",
                source_range: [372; 372),
                delete: [372; 372),
                insert: "baz",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }
    }

    mod record_lit_tests {
        use insta::assert_debug_snapshot;

        use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};

        fn complete(code: &str) -> Vec<CompletionItem> {
            do_completion(code, CompletionKind::Reference)
        }

        #[test]
        fn test_record_literal_deprecated_field() {
            let completions = complete(
                r"
            struct A {
                #[deprecated]
                the_field: u32,
            }
            fn foo() {
               A { the<|> }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "the_field",
                source_range: [142; 145),
                delete: [142; 145),
                insert: "the_field",
                kind: Field,
                detail: "u32",
                deprecated: true,
            },
        ]
        "###);
        }

        #[test]
        fn test_record_literal_field() {
            let completions = complete(
                r"
            struct A { the_field: u32 }
            fn foo() {
               A { the<|> }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "the_field",
                source_range: [83; 86),
                delete: [83; 86),
                insert: "the_field",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_literal_enum_variant() {
            let completions = complete(
                r"
            enum E {
                A { a: u32 }
            }
            fn foo() {
                let _ = E::A { <|> }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "a",
                source_range: [119; 119),
                delete: [119; 119),
                insert: "a",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_literal_two_structs() {
            let completions = complete(
                r"
            struct A { a: u32 }
            struct B { b: u32 }

            fn foo() {
               let _: A = B { <|> }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "b",
                source_range: [119; 119),
                delete: [119; 119),
                insert: "b",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_literal_generic_struct() {
            let completions = complete(
                r"
            struct A<T> { a: T }

            fn foo() {
               let _: A<u32> = A { <|> }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "a",
                source_range: [93; 93),
                delete: [93; 93),
                insert: "a",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn test_record_literal_field_in_simple_macro() {
            let completions = complete(
                r"
            macro_rules! m { ($e:expr) => { $e } }
            struct A { the_field: u32 }
            fn foo() {
               m!(A { the<|> })
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "the_field",
                source_range: [137; 140),
                delete: [137; 140),
                insert: "the_field",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }

        #[test]
        fn only_missing_fields_are_completed() {
            let completions = complete(
                r"
            struct S {
                foo1: u32,
                foo2: u32,
                bar: u32,
                baz: u32,
            }

            fn main() {
                let foo1 = 1;
                let s = S {
                    foo1,
                    foo2: 5,
                    <|>
                }
            }
            ",
            );
            assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "bar",
                source_range: [302; 302),
                delete: [302; 302),
                insert: "bar",
                kind: Field,
                detail: "u32",
            },
            CompletionItem {
                label: "baz",
                source_range: [302; 302),
                delete: [302; 302),
                insert: "baz",
                kind: Field,
                detail: "u32",
            },
        ]
        "###);
        }
    }
}
<|endoftext|>


<commit_before>use audio::Buffer;
use audio::Requester;
use audio::cpal;
use audio::sample::{Sample, ToSample};
use std;
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;

// TODO: For some reason using the render function in the cpal event loop requires it to be
// Sync, but I don't think this should really be necessary.
pub trait RenderFn<M, S>: Fn(M, Buffer<S>) -> (M, Buffer<S>) {}
impl<M, S, F> RenderFn<M, S> for F where F: Fn(M, Buffer<S>) -> (M, Buffer<S>) {}

/// A handle around an output audio stream.
#[derive(Clone)]
pub struct Output<M> {
    /// The user's audio model
    model: Arc<Mutex<Option<M>>>,
    /// A unique ID associated with this stream's "voice" on the cpal EventLoop.
    voice_id: cpal::VoiceId,
    /// A handle to the CPAL audio event loop.
    event_loop: Arc<cpal::EventLoop>,
    /// A channel for sending model updates to the audio thread.
    update_tx: mpsc::Sender<Box<super::UpdateFn<M>>>,
    /// Whether or not the stream is currently paused.
    is_paused: bool,
}

pub struct Builder<M, F, S=f32> {
    pub(crate) event_loop: Arc<cpal::EventLoop>,
    pub model: M,
    pub render: F,
    pub sample_rate: Option<u32>,
    pub channels: Option<usize>,
    pub frames_per_buffer: Option<usize>,
    pub device: Option<Device>,
    pub(crate) sample_format: PhantomData<S>,
}

/// An iterator yielding a `audio::stream::DeviceId` for each output device.
pub struct Devices {
    pub(crate) endpoints: cpal::EndpointsIterator,
}

/// A device that can be used to spawn an output audio stream.
pub struct Device {
    pub(crate) endpoint: cpal::Endpoint,
}

impl Iterator for Devices {
    type Item = Device;
    fn next(&mut self) -> Option<Self::Item> {
        self.endpoints.next().map(|endpoint| Device { endpoint })
    }
}

impl Device {
    /// An iterator yielding all PCM stream formats supported by the device.
    pub fn supported_formats(&self)
        -> Result<cpal::SupportedFormatsIterator, cpal::FormatsEnumerationError>
    {
        self.endpoint.supported_formats()
    }

    /// The name of the device.
    pub fn name(&self) -> String {
        self.endpoint.name()
    }
}

#[derive(Debug)]
pub enum BuildError {
    DefaultDevice,
    FormatEnumeration(cpal::FormatsEnumerationError),
    Creation(cpal::CreationError),
}

impl From<cpal::CreationError> for BuildError {
    fn from(e: cpal::CreationError) -> Self {
        BuildError::Creation(e)
    }
}

impl From<cpal::FormatsEnumerationError> for BuildError {
    fn from(e: cpal::FormatsEnumerationError) -> Self {
        BuildError::FormatEnumeration(e)
    }
}

impl std::error::Error for BuildError {
    fn description(&self) -> &str {
        match *self {
            BuildError::DefaultDevice => "Failed to get default output device",
            BuildError::FormatEnumeration(ref err) => err.description(),
            BuildError::Creation(ref err) => err.description(),
        }
    }
}

impl std::fmt::Display for BuildError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl<M, F, S> Builder<M, F, S> {
    pub fn sample_rate(mut self, sample_rate: u32) -> Self {
        assert!(sample_rate > 0);
        self.sample_rate = Some(sample_rate);
        self
    }

    pub fn channels(mut self, channels: usize) -> Self {
        assert!(channels > 0);
        self.channels = Some(channels);
        self
    }

    pub fn device(mut self, device: Device) -> Self {
        self.device = Some(device);
        self
    }

    pub fn frames_per_buffer(mut self, frames_per_buffer: usize) -> Self {
        assert!(frames_per_buffer > 0);
        self.frames_per_buffer = Some(frames_per_buffer);
        self
    }

    pub fn build(self) -> Result<Output<M>, BuildError>
        where S: Sample + ToSample<u16> + ToSample<i16> + ToSample<f32>,
              M: 'static + Send,
              F: 'static + RenderFn<M, S> + Send,
    {
        let Builder {
            event_loop,
            model,
            render,
            sample_rate,
            channels,
            frames_per_buffer,
            device,
            ..
        } = self;

        let endpoint = match device {
            None => cpal::default_endpoint().ok_or(BuildError::DefaultDevice)?,
            Some(Device { endpoint }) => endpoint,
        };

        let supported_format = endpoint
            .supported_formats()?
            .next()
            .expect("Failed to get any output device stream formats");
        let min_sample_rate = supported_format.min_samples_rate;
        let max_sample_rate = supported_format.max_samples_rate;
        let mut format = supported_format.with_max_samples_rate();

        if let Some(ch) = channels {
            format.channels.resize(ch, cpal::ChannelPosition::FrontLeft);
        }
        if let Some(sr) = sample_rate {
            format.samples_rate = cpal::SamplesRate(sr);
        } else {
            let default = cpal::SamplesRate(super::DEFAULT_SAMPLE_RATE);
            if default <= max_sample_rate && default >= min_sample_rate {
                format.samples_rate = default;
            }
        }

        let voice_id = event_loop.build_voice(&endpoint, &format)?;
        let (update_tx, update_rx) = mpsc::channel();
        let model = Arc::new(Mutex::new(Some(model)));
        let model_2 = model.clone();
        let event_loop_2 = event_loop.clone();
        let num_channels = format.channels.len();
        let sample_rate = format.samples_rate.0;

        std::thread::Builder::new()
            .name(format!("cpal audio output stream: {}", endpoint.name()))
            .spawn(move || {
                // A buffer for collecting model updates.
                let mut pending_updates: Vec<Box<super::UpdateFn<M>>> = Vec::new();

                // Get the specified frames_per_buffer or fall back to a default.
                let frames_per_buffer = frames_per_buffer.unwrap_or(Buffer::<S>::DEFAULT_LEN_FRAMES);

                // An audio requester which requests frames from the model+render pair with a
                // specific buffer size, regardless of the buffer size requested by the OS.
                let mut requester = Requester::new(frames_per_buffer, num_channels);

                // An intermediary buffer for converting cpal samples to the target sample
                // format.
                let mut samples = vec![S::equilibrium(); frames_per_buffer * num_channels];

                // Run the loop, in turn blocking the thread.
                event_loop_2.run(move |_voice_id, mut output| {

                    // Collect and process any pending updates.
                    macro_rules! process_pending_updates {
                        () => {
                            // Collect any pending updates.
                            pending_updates.extend(update_rx.try_iter());

                            // If there are some updates available, take the lock and apply them.
                            if !pending_updates.is_empty() {
                                if let Ok(mut guard) = model_2.lock() {
                                    let mut model = guard.take().unwrap();
                                    for mut update in pending_updates.drain(..) {
                                        update(&mut model);
                                    }
                                    *guard = Some(model);
                                }
                            }
                        };
                    }

                    process_pending_updates!();

                    samples.clear();
                    samples.resize(output.len(), S::equilibrium());
                    if let Ok(mut guard) = model_2.lock() {
                        let mut m = guard.take().unwrap();
                        m = requester.fill_buffer(m, &render, &mut samples, num_channels, sample_rate);
                        *guard = Some(m);
                    }

                    // A function to simplify filling the unknown buffer type.
                    fn fill_output<O, S>(output: &mut [O], buffer: &[S])
                    where
                        O: Sample,
                        S: Sample + ToSample<O>,
                    {
                        for (out_sample, sample) in output.iter_mut().zip(buffer) {
                            *out_sample = sample.to_sample();
                        }
                    }

                    // Process the given buffer.
                    match output {
                        cpal::UnknownTypeBuffer::U16(ref mut buffer) => fill_output(buffer, &samples),
                        cpal::UnknownTypeBuffer::I16(ref mut buffer) => fill_output(buffer, &samples),
                        cpal::UnknownTypeBuffer::F32(ref mut buffer) => fill_output(buffer, &samples),
                    }

                    process_pending_updates!();
                })
            })
            .expect("Failed to spawn thread for cpal audio output stream");

        let output = Output {
            model,
            voice_id,
            event_loop,
            update_tx,
            is_paused: true,
        };
        Ok(output)
    }
}

impl<M> Output<M> {
    /// Command the audio device to start playing this stream.
    ///
    /// Calling this will activate rendering, in turn calling the given audio render function.
    ///
    /// Has no effect if the stream is already playing.
    pub fn play(&mut self) {
        self.event_loop.play(self.voice_id.clone());
        self.is_paused = false;
    }

    /// Command the audio device to stop playback.
    ///
    /// Calling this will pause rendering, in turn .
    ///
    /// Has no effect is the voice was already paused.
    pub fn pause(&mut self) {
        self.is_paused = true;
        self.event_loop.pause(self.voice_id.clone());
    }

    /// Whether or not the stream is currently playing.
    pub fn is_playing(&self) -> bool {
        !self.is_paused
    }

    /// Whether or not the stream is currently paused.
    pub fn is_paused(&self) -> bool {
        self.is_paused
    }

    /// Send the given model update to the audio thread to be applied ASAP.
    ///
    /// If the audio is currently rendering, the update will be applied immediately after the
    /// function call completes.
    ///
    /// If the stream is currently paused, the update will be applied immediately.
    ///
    /// **Note:** This function will be applied on the real-time audio thread so users should
    /// avoid performing any kind of I/O, locking, blocking, (de)allocations or anything that
    /// may run for an indeterminate amount of time.
    pub fn send<F>(&self, mut update: F)
        -> Result<(), mpsc::SendError<Box<FnMut(&mut M) + Send + 'static>>>
        where F: FnMut(&mut M) + Send + 'static,
    {
        // NOTE: The following code may mean that on extremely rare occasions an update does
        // not get applied for an indeterminate amount of time. This might be the case if a
        // stream is unpaused but becomes paused *immediately* after the `is_paused` atomic
        // condition is read as `false` - the update would be sent but the stream would be
        // paused and in turn the update will not get processed until the stream is unpaused
        // again. It would be nice to work out a solution to this that does not require
        // spawning another thread for each stream.

        // If the thread is currently paused, take the lock and immediately apply it as we know
        // there will be no contention.
        if self.is_paused {
            if let Ok(mut guard) = self.model.lock() {
                let mut model = guard.take().unwrap();
                update(&mut model);
                *guard = Some(model);
            }
        // Otherwise send the update to the audio thread.
        } else {
            self.update_tx.send(Box::new(update))?;
        }

        Ok(())
    }
}

impl<M> Drop for Output<M> {
    fn drop(&mut self) {
        if self.is_playing() {
            self.pause();
        }
        self.event_loop.destroy_voice(self.voice_id.clone());
    }
}
<commit_msg>Clarify comment on audio thread contention<commit_after>use audio::Buffer;
use audio::Requester;
use audio::cpal;
use audio::sample::{Sample, ToSample};
use std;
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;

// TODO: For some reason using the render function in the cpal event loop requires it to be
// Sync, but I don't think this should really be necessary.
pub trait RenderFn<M, S>: Fn(M, Buffer<S>) -> (M, Buffer<S>) {}
impl<M, S, F> RenderFn<M, S> for F where F: Fn(M, Buffer<S>) -> (M, Buffer<S>) {}

/// A handle around an output audio stream.
#[derive(Clone)]
pub struct Output<M> {
    /// The user's audio model
    model: Arc<Mutex<Option<M>>>,
    /// A unique ID associated with this stream's "voice" on the cpal EventLoop.
    voice_id: cpal::VoiceId,
    /// A handle to the CPAL audio event loop.
    event_loop: Arc<cpal::EventLoop>,
    /// A channel for sending model updates to the audio thread.
    update_tx: mpsc::Sender<Box<super::UpdateFn<M>>>,
    /// Whether or not the stream is currently paused.
    is_paused: bool,
}

pub struct Builder<M, F, S=f32> {
    pub(crate) event_loop: Arc<cpal::EventLoop>,
    pub model: M,
    pub render: F,
    pub sample_rate: Option<u32>,
    pub channels: Option<usize>,
    pub frames_per_buffer: Option<usize>,
    pub device: Option<Device>,
    pub(crate) sample_format: PhantomData<S>,
}

/// An iterator yielding a `audio::stream::DeviceId` for each output device.
pub struct Devices {
    pub(crate) endpoints: cpal::EndpointsIterator,
}

/// A device that can be used to spawn an output audio stream.
pub struct Device {
    pub(crate) endpoint: cpal::Endpoint,
}

impl Iterator for Devices {
    type Item = Device;
    fn next(&mut self) -> Option<Self::Item> {
        self.endpoints.next().map(|endpoint| Device { endpoint })
    }
}

impl Device {
    /// An iterator yielding all PCM stream formats supported by the device.
    pub fn supported_formats(&self)
        -> Result<cpal::SupportedFormatsIterator, cpal::FormatsEnumerationError>
    {
        self.endpoint.supported_formats()
    }

    /// The name of the device.
    pub fn name(&self) -> String {
        self.endpoint.name()
    }
}

#[derive(Debug)]
pub enum BuildError {
    DefaultDevice,
    FormatEnumeration(cpal::FormatsEnumerationError),
    Creation(cpal::CreationError),
}

impl From<cpal::CreationError> for BuildError {
    fn from(e: cpal::CreationError) -> Self {
        BuildError::Creation(e)
    }
}

impl From<cpal::FormatsEnumerationError> for BuildError {
    fn from(e: cpal::FormatsEnumerationError) -> Self {
        BuildError::FormatEnumeration(e)
    }
}

impl std::error::Error for BuildError {
    fn description(&self) -> &str {
        match *self {
            BuildError::DefaultDevice => "Failed to get default output device",
            BuildError::FormatEnumeration(ref err) => err.description(),
            BuildError::Creation(ref err) => err.description(),
        }
    }
}

impl std::fmt::Display for BuildError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl<M, F, S> Builder<M, F, S> {
    pub fn sample_rate(mut self, sample_rate: u32) -> Self {
        assert!(sample_rate > 0);
        self.sample_rate = Some(sample_rate);
        self
    }

    pub fn channels(mut self, channels: usize) -> Self {
        assert!(channels > 0);
        self.channels = Some(channels);
        self
    }

    pub fn device(mut self, device: Device) -> Self {
        self.device = Some(device);
        self
    }

    pub fn frames_per_buffer(mut self, frames_per_buffer: usize) -> Self {
        assert!(frames_per_buffer > 0);
        self.frames_per_buffer = Some(frames_per_buffer);
        self
    }

    pub fn build(self) -> Result<Output<M>, BuildError>
        where S: Sample + ToSample<u16> + ToSample<i16> + ToSample<f32>,
              M: 'static + Send,
              F: 'static + RenderFn<M, S> + Send,
    {
        let Builder {
            event_loop,
            model,
            render,
            sample_rate,
            channels,
            frames_per_buffer,
            device,
            ..
        } = self;

        let endpoint = match device {
            None => cpal::default_endpoint().ok_or(BuildError::DefaultDevice)?,
            Some(Device { endpoint }) => endpoint,
        };

        let supported_format = endpoint
            .supported_formats()?
            .next()
            .expect("Failed to get any output device stream formats");
        let min_sample_rate = supported_format.min_samples_rate;
        let max_sample_rate = supported_format.max_samples_rate;
        let mut format = supported_format.with_max_samples_rate();

        if let Some(ch) = channels {
            format.channels.resize(ch, cpal::ChannelPosition::FrontLeft);
        }
        if let Some(sr) = sample_rate {
            format.samples_rate = cpal::SamplesRate(sr);
        } else {
            let default = cpal::SamplesRate(super::DEFAULT_SAMPLE_RATE);
            if default <= max_sample_rate && default >= min_sample_rate {
                format.samples_rate = default;
            }
        }

        let voice_id = event_loop.build_voice(&endpoint, &format)?;
        let (update_tx, update_rx) = mpsc::channel();
        let model = Arc::new(Mutex::new(Some(model)));
        let model_2 = model.clone();
        let event_loop_2 = event_loop.clone();
        let num_channels = format.channels.len();
        let sample_rate = format.samples_rate.0;

        std::thread::Builder::new()
            .name(format!("cpal audio output stream: {}", endpoint.name()))
            .spawn(move || {
                // A buffer for collecting model updates.
                let mut pending_updates: Vec<Box<super::UpdateFn<M>>> = Vec::new();

                // Get the specified frames_per_buffer or fall back to a default.
                let frames_per_buffer = frames_per_buffer.unwrap_or(Buffer::<S>::DEFAULT_LEN_FRAMES);

                // An audio requester which requests frames from the model+render pair with a
                // specific buffer size, regardless of the buffer size requested by the OS.
                let mut requester = Requester::new(frames_per_buffer, num_channels);

                // An intermediary buffer for converting cpal samples to the target sample
                // format.
                let mut samples = vec![S::equilibrium(); frames_per_buffer * num_channels];

                // Run the loop, in turn blocking the thread.
                event_loop_2.run(move |_voice_id, mut output| {

                    // Collect and process any pending updates.
                    macro_rules! process_pending_updates {
                        () => {
                            // Collect any pending updates.
                            pending_updates.extend(update_rx.try_iter());

                            // If there are some updates available, take the lock and apply them.
                            if !pending_updates.is_empty() {
                                if let Ok(mut guard) = model_2.lock() {
                                    let mut model = guard.take().unwrap();
                                    for mut update in pending_updates.drain(..) {
                                        update(&mut model);
                                    }
                                    *guard = Some(model);
                                }
                            }
                        };
                    }

                    process_pending_updates!();

                    samples.clear();
                    samples.resize(output.len(), S::equilibrium());
                    if let Ok(mut guard) = model_2.lock() {
                        let mut m = guard.take().unwrap();
                        m = requester.fill_buffer(m, &render, &mut samples, num_channels, sample_rate);
                        *guard = Some(m);
                    }

                    // A function to simplify filling the unknown buffer type.
                    fn fill_output<O, S>(output: &mut [O], buffer: &[S])
                    where
                        O: Sample,
                        S: Sample + ToSample<O>,
                    {
                        for (out_sample, sample) in output.iter_mut().zip(buffer) {
                            *out_sample = sample.to_sample();
                        }
                    }

                    // Process the given buffer.
                    match output {
                        cpal::UnknownTypeBuffer::U16(ref mut buffer) => fill_output(buffer, &samples),
                        cpal::UnknownTypeBuffer::I16(ref mut buffer) => fill_output(buffer, &samples),
                        cpal::UnknownTypeBuffer::F32(ref mut buffer) => fill_output(buffer, &samples),
                    }

                    process_pending_updates!();
                })
            })
            .expect("Failed to spawn thread for cpal audio output stream");

        let output = Output {
            model,
            voice_id,
            event_loop,
            update_tx,
            is_paused: true,
        };
        Ok(output)
    }
}

impl<M> Output<M> {
    /// Command the audio device to start playing this stream.
    ///
    /// Calling this will activate rendering, in turn calling the given audio render function.
    ///
    /// Has no effect if the stream is already playing.
    pub fn play(&mut self) {
        self.event_loop.play(self.voice_id.clone());
        self.is_paused = false;
    }

    /// Command the audio device to stop playback.
    ///
    /// Calling this will pause rendering, in turn .
    ///
    /// Has no effect is the voice was already paused.
    pub fn pause(&mut self) {
        self.is_paused = true;
        self.event_loop.pause(self.voice_id.clone());
    }

    /// Whether or not the stream is currently playing.
    pub fn is_playing(&self) -> bool {
        !self.is_paused
    }

    /// Whether or not the stream is currently paused.
    pub fn is_paused(&self) -> bool {
        self.is_paused
    }

    /// Send the given model update to the audio thread to be applied ASAP.
    ///
    /// If the audio is currently rendering, the update will be applied immediately after the
    /// function call completes.
    ///
    /// If the stream is currently paused, the update will be applied immediately.
    ///
    /// **Note:** This function will be applied on the real-time audio thread so users should
    /// avoid performing any kind of I/O, locking, blocking, (de)allocations or anything that
    /// may run for an indeterminate amount of time.
    pub fn send<F>(&self, mut update: F)
        -> Result<(), mpsc::SendError<Box<FnMut(&mut M) + Send + 'static>>>
        where F: FnMut(&mut M) + Send + 'static,
    {
        // NOTE: The following code may mean that on extremely rare occasions an update does
        // not get applied for an indeterminate amount of time. This might be the case if a
        // stream is unpaused but becomes paused *immediately* after the `is_paused` atomic
        // condition is read as `false` - the update would be sent but the stream would be
        // paused and in turn the update will not get processed until the stream is unpaused
        // again. It would be nice to work out a solution to this that does not require
        // spawning another thread for each stream.

        // If the thread is currently paused, take the lock and immediately apply it as we know
        // there will be no contention with the audio thread.
        if self.is_paused {
            if let Ok(mut guard) = self.model.lock() {
                let mut model = guard.take().unwrap();
                update(&mut model);
                *guard = Some(model);
            }
        // Otherwise send the update to the audio thread.
        } else {
            self.update_tx.send(Box::new(update))?;
        }

        Ok(())
    }
}

impl<M> Drop for Output<M> {
    fn drop(&mut self) {
        if self.is_playing() {
            self.pause();
        }
        self.event_loop.destroy_voice(self.voice_id.clone());
    }
}
<|endoftext|>