<commit_before>/*
 * Copyright (c) 2018 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use std::fs;
use std::io;
use std::path::PathBuf;

use glib::StaticType;
use gtk::{
    CellLayoutExt,
    ContainerExt,
    GtkWindowExt,
    Inhibit,
    TreeModelExt,
    TreeSelectionExt,
    TreeView,
    TreeViewExt,
    WidgetExt,
    Window,
    WindowType,
    prelude::GtkListStoreExtManual,
};
use gtk::Orientation::Vertical;
use relm_derive::Msg;
use relm::{connect, Relm, Update, Widget};

// These two constants stand for the columns of the listmodel and the listview
const VALUE_COL: i32 = 0;
const IS_DIR_COL: i32 = 1;

struct Directory {
    current_dir: PathBuf,
}

#[derive(Msg)]
enum Msg {
    ItemSelect,
    Quit,
}

struct Win {
    tree_view: TreeView,
    model: Directory,
    window: Window,
}

impl Update for Win {
    type Model = Directory;
    type ModelParam = ();
    type Msg = Msg;

    fn model(_: &Relm<Self>, _: ()) -> Directory {
        let working_directory = fs::canonicalize(".").expect("Failed to open directory");
        Directory {
            current_dir: working_directory
        }
    }

    fn update(&mut self, event: Msg) {
        match event {
            Msg::ItemSelect => {
                let selection = self.tree_view.get_selection();
                if let Some((list_model, iter)) = selection.get_selected() {
                    let is_dir: bool = list_model
                        .get_value(&iter, IS_DIR_COL)
                        .get::<bool>()
                        .ok()
                        .and_then(|value| value)
                        .expect("get_value.get<bool> failed");

                    if is_dir {
                        let dir_name = list_model
                            .get_value(&iter, VALUE_COL)
                            .get::<String>()
                            .ok()
                            .and_then(|value| value)
                            .expect("get_value.get<String> failed");

                        println!("{:?} selected", dir_name);
                        let new_dir = if dir_name == ".." {
                            // Go up parent directory, if it exists
                            self.model.current_dir
                                .parent()
                                .unwrap_or(&self.model.current_dir)
                                .to_owned()
                        } else {
                            self.model.current_dir.join(dir_name)
                        };
                        self.model.current_dir = new_dir;
                        let new_model =
                            create_and_fill_model(&self.model.current_dir)
                                .expect("create_and_fill_model failed");

                        self.tree_view.set_model(Some(&new_model));
                    }
                }
            },
            Msg::Quit => gtk::main_quit(),
        }
    }
}

impl Widget for Win {
    type Root = Window;

    fn root(&self) -> Self::Root {
        self.window.clone()
    }

    fn view(relm: &Relm<Self>, model: Self::Model) -> Self {
        let window = gtk::Window::new(WindowType::Toplevel);
        let vbox = gtk::Box::new(Vertical, 0);
        let tree_view = gtk::TreeView::new();
        let column = gtk::TreeViewColumn::new();
        let cell = gtk::CellRendererText::new();

        window.set_title("TreeView example file browser");
        window.set_border_width(10);
        window.set_position(gtk::WindowPosition::Center);
        window.set_default_size(350, 70);

        column.pack_start(&cell, true);
        // Assiciate view's column with model's id column
        column.add_attribute(&cell, "text", 0);
        tree_view.append_column(&column);

        let store_model = create_and_fill_model(&model.current_dir)
                              .expect("create_and_fill_model failed");
        tree_view.set_model(Some(&store_model));

        vbox.add(&tree_view);
        window.add(&vbox);

        window.show_all();

        connect!(relm, tree_view, connect_cursor_changed(_), Msg::ItemSelect);
        connect!(relm, window, connect_delete_event(_, _), return (Some(Msg::Quit), Inhibit(false)));

        Win {
            tree_view,
            model,
            window,
        }
    }
}

fn create_and_fill_model(dir_str: &PathBuf) -> io::Result<gtk::ListStore> {
    // Single row model
    let model = gtk::ListStore::new(&[String::static_type(), bool::static_type()]);

    // Add the parent directory
    model.insert_with_values(None,
                            &[VALUE_COL as u32, IS_DIR_COL as u32],
                            &[&"..", &true]);

    let entry_iter = fs::read_dir(dir_str)?.filter_map(|x| x.ok());
    for entry in entry_iter {
        if let Ok(metadata) = entry.metadata() {

            if let Ok(file_name) = entry.file_name().into_string() {
                let (final_name, is_dir) = if metadata.is_dir() {
                    (format!("{}/", file_name), true)
                } else {
                    (file_name, false)
                };
                model.insert_with_values(None,
                                        &[VALUE_COL as u32, IS_DIR_COL as u32],
                                        &[&final_name, &is_dir]);
            }
        }
    }
    Ok(model)
}

fn main() {
    Win::run(()).expect("Win::run failed");
}
<commit_msg>Use system path separator in tree-view example<commit_after>/*
 * Copyright (c) 2018 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use std::fs;
use std::io;
use std::path::{MAIN_SEPARATOR, PathBuf};

use glib::StaticType;
use gtk::{
    CellLayoutExt,
    ContainerExt,
    GtkWindowExt,
    Inhibit,
    TreeModelExt,
    TreeSelectionExt,
    TreeView,
    TreeViewExt,
    WidgetExt,
    Window,
    WindowType,
    prelude::GtkListStoreExtManual,
};
use gtk::Orientation::Vertical;
use relm_derive::Msg;
use relm::{connect, Relm, Update, Widget};

// These two constants stand for the columns of the listmodel and the listview
const VALUE_COL: i32 = 0;
const IS_DIR_COL: i32 = 1;

struct Directory {
    current_dir: PathBuf,
}

#[derive(Msg)]
enum Msg {
    ItemSelect,
    Quit,
}

struct Win {
    tree_view: TreeView,
    model: Directory,
    window: Window,
}

impl Update for Win {
    type Model = Directory;
    type ModelParam = ();
    type Msg = Msg;

    fn model(_: &Relm<Self>, _: ()) -> Directory {
        let working_directory = fs::canonicalize(".").expect("Failed to open directory");
        Directory {
            current_dir: working_directory
        }
    }

    fn update(&mut self, event: Msg) {
        match event {
            Msg::ItemSelect => {
                let selection = self.tree_view.get_selection();
                if let Some((list_model, iter)) = selection.get_selected() {
                    let is_dir: bool = list_model
                        .get_value(&iter, IS_DIR_COL)
                        .get::<bool>()
                        .ok()
                        .and_then(|value| value)
                        .expect("get_value.get<bool> failed");

                    if is_dir {
                        let dir_name = list_model
                            .get_value(&iter, VALUE_COL)
                            .get::<String>()
                            .ok()
                            .and_then(|value| value)
                            .expect("get_value.get<String> failed");

                        println!("{:?} selected", dir_name);
                        let new_dir = if dir_name == ".." {
                            // Go up parent directory, if it exists
                            self.model.current_dir
                                .parent()
                                .unwrap_or(&self.model.current_dir)
                                .to_owned()
                        } else {
                            self.model.current_dir.join(dir_name)
                        };
                        self.model.current_dir = new_dir;
                        let new_model =
                            create_and_fill_model(&self.model.current_dir)
                                .expect("create_and_fill_model failed");

                        self.tree_view.set_model(Some(&new_model));
                    }
                }
            },
            Msg::Quit => gtk::main_quit(),
        }
    }
}

impl Widget for Win {
    type Root = Window;

    fn root(&self) -> Self::Root {
        self.window.clone()
    }

    fn view(relm: &Relm<Self>, model: Self::Model) -> Self {
        let window = gtk::Window::new(WindowType::Toplevel);
        let vbox = gtk::Box::new(Vertical, 0);
        let tree_view = gtk::TreeView::new();
        let column = gtk::TreeViewColumn::new();
        let cell = gtk::CellRendererText::new();

        window.set_title("TreeView example file browser");
        window.set_border_width(10);
        window.set_position(gtk::WindowPosition::Center);
        window.set_default_size(350, 70);

        column.pack_start(&cell, true);
        // Assiciate view's column with model's id column
        column.add_attribute(&cell, "text", 0);
        tree_view.append_column(&column);

        let store_model = create_and_fill_model(&model.current_dir)
                              .expect("create_and_fill_model failed");
        tree_view.set_model(Some(&store_model));

        vbox.add(&tree_view);
        window.add(&vbox);

        window.show_all();

        connect!(relm, tree_view, connect_cursor_changed(_), Msg::ItemSelect);
        connect!(relm, window, connect_delete_event(_, _), return (Some(Msg::Quit), Inhibit(false)));

        Win {
            tree_view,
            model,
            window,
        }
    }
}

fn create_and_fill_model(dir_str: &PathBuf) -> io::Result<gtk::ListStore> {
    // Single row model
    let model = gtk::ListStore::new(&[String::static_type(), bool::static_type()]);

    // Add the parent directory
    model.insert_with_values(None,
                            &[VALUE_COL as u32, IS_DIR_COL as u32],
                            &[&"..", &true]);

    let entry_iter = fs::read_dir(dir_str)?.filter_map(|x| x.ok());
    for entry in entry_iter {
        if let Ok(metadata) = entry.metadata() {

            if let Ok(file_name) = entry.file_name().into_string() {
                let (final_name, is_dir) = if metadata.is_dir() {
                    (format!("{}{}", file_name, MAIN_SEPARATOR), true)
                } else {
                    (file_name, false)
                };
                model.insert_with_values(None,
                                        &[VALUE_COL as u32, IS_DIR_COL as u32],
                                        &[&final_name, &is_dir]);
            }
        }
    }
    Ok(model)
}

fn main() {
    Win::run(()).expect("Win::run failed");
}
<|endoftext|>


<commit_before><commit_msg>Only exclude std when not running tests<commit_after><|endoftext|>


<commit_before><commit_msg>args vector automatically available to snippets<commit_after><|endoftext|>


<commit_before><commit_msg>Add regex<commit_after><|endoftext|>


<commit_before><commit_msg>revert main file (oops)<commit_after><|endoftext|>


<commit_before><commit_msg>Factor out the frame data parsing routine<commit_after><|endoftext|>


<commit_before>#![allow(dead_code)]
use utils;
//use std::ops::{Index, Deref, DerefMut};
use std::cell::RefCell;
use std::rc::Rc;

pub type MemShared = Rc<RefCell<Memory>>;

pub enum MemType
{
    RAM,
    BASIC,
    CHARGEN,
    IO,
    KERNAL,
}

// specific memory bank - RAM, ROM, IO
struct MemBank
{
    bank_type: MemType, // what am I?
    read_only: bool,    // RAM or ROM?
    offset: u16,        // offset from start of address space
    data: Vec<u8>,
}

impl MemBank
{
    pub fn new(mem_type: MemType) -> MemBank
    {
        let mut mem_bank = MemBank
        {
            bank_type: mem_type,
            read_only: true,
            offset: 0x0000,
            data: Vec::<u8>::new(),
        };

        match mem_bank.bank_type
        {
            MemType::BASIC   => {
                mem_bank.data = utils::open_file("rom/basic.rom", 0);
                mem_bank.offset = 0xA000;
            },
            MemType::CHARGEN => {
                mem_bank.data = utils::open_file("rom/chargen.rom", 0);
                mem_bank.offset = 0xD000;
            },
            MemType::KERNAL  => {
                mem_bank.data = utils::open_file("rom/kernal.rom", 0);
                mem_bank.offset = 0xE000;
            },
            MemType::RAM => {
                mem_bank.data = Vec::<u8>::with_capacity(0x10000);
                for _ in 0..0x10000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.read_only = false;
            },
            MemType::IO => {
                mem_bank.data = Vec::<u8>::with_capacity(0x1000);
                for _ in 0..0x1000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.offset = 0xD000;
                mem_bank.read_only = false;
            }
        }

        mem_bank
    }

    pub fn write(&mut self, addr: u16, val: u8)
    {
        match self.bank_type
        {
            MemType::RAM => self.data[(addr - self.offset) as usize] = val,
            MemType::IO => {
                // TODO: IO access has specific behavior depending on address
                match addr
                {
                    0xD016          => self.data[(addr - self.offset) as usize] = 0xC0 | val,
                    0xD019          => self.data[(addr - self.offset) as usize] = 0x70 | val,
                    0xD01A          => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    0xD01E...0xD01F => (),                             // cannot be written - panic/fail on try?
                    0xD020...0xD02E => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    0xD02F...0xD03F => (),                             // write ignored
                    0xD040...0xD3FF => self.write(0xD000 + (addr % 0x0040), val), // same as 0xD000-0xD03F
                    _ => self.data[(addr - self.offset) as usize] = val
                }

            },
            _ => panic!("Can't write to ROM!")
        }
    }

    pub fn read(&mut self, addr: u16) -> u8
    {
        match self.bank_type
        {
            MemType::IO => {
                // TODO: IO access has specific behavior depending on address
                match addr
                {
                    0xD016          => 0xC0 | self.data[(addr - self.offset) as usize],
                    0xD018          => 0x01 | self.data[(addr - self.offset) as usize],
                    0xD019          => 0x70 | self.data[(addr - self.offset) as usize],
                    0xD01A          => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD01E...0xD01F => {                                  // cannot be written, cleared on read
                        let value = self.data[(addr - self.offset) as usize];
                        self.data[(addr - self.offset) as usize] = 0;
                        value
                    },
                    0xD020...0xD02E => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD02F...0xD03F => 0xFF,                              // always returns 0xFF
                    0xD040...0xD3FF => self.read(0xD000 + (addr % 0x0040)),          // same as 0xD000-0xD03F
                    _ => self.data[(addr - self.offset) as usize]
                }
            },
            _ => self.data[(addr - self.offset) as usize]
        }
    }
}

/*impl Index<u16> for MemBank
{
    type Output = u8;

    fn index<'a>(&'a self, _index: u16) -> &'a u8
    {
        &self.data[_index as usize]
    }
}

impl Deref for MemBank
{
    type Target = Vec<u8>;

    fn deref(&self) -> &Vec<u8>
    {
        &self.data
    }
}

impl DerefMut for MemBank
{
    fn deref_mut(&mut self) -> &mut Vec<u8>
    {
        &mut self.data
    }
}*/

// collective memory storage with all the banks and bank switching support
pub struct Memory
{
    ram:     MemBank,
    basic:   MemBank,
    chargen: MemBank,
    io:      MemBank,
    kernal:  MemBank,

    // bank switching flags
    basic_on:   bool,
    chargen_on: bool,
    io_on:      bool,
    kernal_on:  bool,
    cart_lo_on: bool, // cart flag - unused for now
    cart_hi_on: bool  // cart flag - unused for now
}

impl Memory
{
    pub fn new_shared() -> MemShared
    {
        Rc::new(RefCell::new(Memory
        {
            ram:     MemBank::new(MemType::RAM),     // 64k
            basic:   MemBank::new(MemType::BASIC),   // 8k
            chargen: MemBank::new(MemType::CHARGEN), // 4k
            io:      MemBank::new(MemType::IO),      // 4k (VIC, SID, CIA, Color RAM)
            kernal:  MemBank::new(MemType::KERNAL),  // 8k
            basic_on:   false,
            chargen_on: false,
            io_on:      false,
            kernal_on:  false,
            cart_lo_on: false, // unused for now
            cart_hi_on: false, // unused for now
        }))
    }

    // returns memory bank for current latch setting and address
    pub fn get_bank(&mut self, addr: u16) -> (&mut MemBank)
    {
        match addr
        {
            0x0000...0x9FFF => &mut self.ram,
            0xA000...0xBFFF => if self.basic_on { &mut self.basic } else { &mut self.ram },
            0xC000...0xCFFF => &mut self.ram,
            0xD000...0xDFFF => {
                if self.chargen_on { return &mut self.chargen }
                if self.io_on      { return &mut self.io; }
                return &mut self.ram;
            },
            0xE000...0xFFFF => if self.kernal_on  { &mut self.kernal } else { &mut self.ram },
            _ => panic!("Address out of memory range")
        }
    }

    // returns specific modifiable memory bank
    pub fn get_ram_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::RAM => &mut self.ram,
            MemType::IO  => &mut self.io,
            _            => panic!("Unrecognized RAM bank"),
        }
    }

    // returns specific non-modifiable memory bank
    pub fn get_rom_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::BASIC   => &mut self.basic,
            MemType::CHARGEN => &mut self.chargen,
            MemType::KERNAL  => &mut self.kernal,
            _                => panic!("Unrecognized ROM Abank"),
        }
    }

    pub fn reset(&mut self)
    {
        self.write_byte(0x0000, 0xFF);
        self.write_byte(0x0001, 0x07); // enable kernal, chargen and basic ROMs
    }

    fn update_bank_flags(&mut self)
    {
        // latch state is determined by 3 least significant bits from this location
        let latch = self.ram.read(0x0001) & 0x07;

        self.chargen_on = ((latch & 0x04) == 0) && ((latch & 0x03) != 0); // %0xx except %000
        self.io_on      = ((latch & 0x04) != 0) && ((latch & 0x03) != 0); // %1xx except %100
        self.basic_on   = (latch & 0x03) == 0x03;
        self.kernal_on  = self.basic_on || ((latch & 0x03) == 0x02);
    }

    // Write a byte to memory - returns whether RAM was written (true) or RAM under ROM (false)
    pub fn write_byte(&mut self, addr: u16, value: u8) -> bool
    {
        // RAM under ROM written? Return false to let us know about it
        if self.get_bank(addr).read_only
        {
            self.ram.write(addr, value);
            return false;
        }
        else
        {
            self.get_bank(addr).write(addr, value);
        }

        // update the bank switching flags here, since they can only change on memory write
        // latch byte changed - update bank switching flags
        if addr == 0x0001 { self.update_bank_flags(); }

        return true;
    }

    // Read a byte from memory
    pub fn read_byte(&mut self, addr: u16) -> u8
    {
        self.get_bank(addr).read(addr)
    }

    // Read a word from memory (stored in little endian)
    pub fn read_word_le(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_be: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    // Read a word from memory (stored in big endian: swap low<->high)
    pub fn read_word_be(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_le: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);
        value_le
    }

    // Write word in little endian format (low/high)
    pub fn write_word_le(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_lo);
        let lo = self.write_byte(addr + 0x0001, value_le_hi);

        return hi && lo;
    }

    // Write word in big endian format (high/low)
    pub fn write_word_be(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_hi);
        let lo = self.write_byte(addr + 0x0001, value_le_lo);

        return hi && lo;
    }
}

<commit_msg>added missing pub qualifier<commit_after>#![allow(dead_code)]
use utils;
//use std::ops::{Index, Deref, DerefMut};
use std::cell::RefCell;
use std::rc::Rc;

pub type MemShared = Rc<RefCell<Memory>>;

pub enum MemType
{
    RAM,
    BASIC,
    CHARGEN,
    IO,
    KERNAL,
}

// specific memory bank - RAM, ROM, IO
struct MemBank
{
    bank_type: MemType, // what am I?
    read_only: bool,    // RAM or ROM?
    offset: u16,        // offset from start of address space
    data: Vec<u8>,
}

impl MemBank
{
    pub fn new(mem_type: MemType) -> MemBank
    {
        let mut mem_bank = MemBank
        {
            bank_type: mem_type,
            read_only: true,
            offset: 0x0000,
            data: Vec::<u8>::new(),
        };

        match mem_bank.bank_type
        {
            MemType::BASIC   => {
                mem_bank.data = utils::open_file("rom/basic.rom", 0);
                mem_bank.offset = 0xA000;
            },
            MemType::CHARGEN => {
                mem_bank.data = utils::open_file("rom/chargen.rom", 0);
                mem_bank.offset = 0xD000;
            },
            MemType::KERNAL  => {
                mem_bank.data = utils::open_file("rom/kernal.rom", 0);
                mem_bank.offset = 0xE000;
            },
            MemType::RAM => {
                mem_bank.data = Vec::<u8>::with_capacity(0x10000);
                for _ in 0..0x10000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.read_only = false;
            },
            MemType::IO => {
                mem_bank.data = Vec::<u8>::with_capacity(0x1000);
                for _ in 0..0x1000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.offset = 0xD000;
                mem_bank.read_only = false;
            }
        }

        mem_bank
    }

    pub fn write(&mut self, addr: u16, val: u8)
    {
        match self.bank_type
        {
            MemType::RAM => self.data[(addr - self.offset) as usize] = val,
            MemType::IO => {
                // TODO: IO access has specific behavior depending on address
                match addr
                {
                    0xD016          => self.data[(addr - self.offset) as usize] = 0xC0 | val,
                    0xD019          => self.data[(addr - self.offset) as usize] = 0x70 | val,
                    0xD01A          => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    0xD01E...0xD01F => (),                             // cannot be written - panic/fail on try?
                    0xD020...0xD02E => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    0xD02F...0xD03F => (),                             // write ignored
                    0xD040...0xD3FF => self.write(0xD000 + (addr % 0x0040), val), // same as 0xD000-0xD03F
                    _ => self.data[(addr - self.offset) as usize] = val
                }

            },
            _ => panic!("Can't write to ROM!")
        }
    }

    pub fn read(&mut self, addr: u16) -> u8
    {
        match self.bank_type
        {
            MemType::IO => {
                // TODO: IO access has specific behavior depending on address
                match addr
                {
                    0xD016          => 0xC0 | self.data[(addr - self.offset) as usize],
                    0xD018          => 0x01 | self.data[(addr - self.offset) as usize],
                    0xD019          => 0x70 | self.data[(addr - self.offset) as usize],
                    0xD01A          => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD01E...0xD01F => {                                  // cannot be written, cleared on read
                        let value = self.data[(addr - self.offset) as usize];
                        self.data[(addr - self.offset) as usize] = 0;
                        value
                    },
                    0xD020...0xD02E => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD02F...0xD03F => 0xFF,                              // always returns 0xFF
                    0xD040...0xD3FF => self.read(0xD000 + (addr % 0x0040)),          // same as 0xD000-0xD03F
                    _ => self.data[(addr - self.offset) as usize]
                }
            },
            _ => self.data[(addr - self.offset) as usize]
        }
    }
}

/*impl Index<u16> for MemBank
{
    type Output = u8;

    fn index<'a>(&'a self, _index: u16) -> &'a u8
    {
        &self.data[_index as usize]
    }
}

impl Deref for MemBank
{
    type Target = Vec<u8>;

    fn deref(&self) -> &Vec<u8>
    {
        &self.data
    }
}

impl DerefMut for MemBank
{
    fn deref_mut(&mut self) -> &mut Vec<u8>
    {
        &mut self.data
    }
}*/

// collective memory storage with all the banks and bank switching support
pub struct Memory
{
    ram:     MemBank,
    basic:   MemBank,
    chargen: MemBank,
    io:      MemBank,
    kernal:  MemBank,

    // bank switching flags
    basic_on:   bool,
    chargen_on: bool,
    pub io_on:  bool,
    kernal_on:  bool,
    cart_lo_on: bool, // cart flag - unused for now
    cart_hi_on: bool  // cart flag - unused for now
}

impl Memory
{
    pub fn new_shared() -> MemShared
    {
        Rc::new(RefCell::new(Memory
        {
            ram:     MemBank::new(MemType::RAM),     // 64k
            basic:   MemBank::new(MemType::BASIC),   // 8k
            chargen: MemBank::new(MemType::CHARGEN), // 4k
            io:      MemBank::new(MemType::IO),      // 4k (VIC, SID, CIA, Color RAM)
            kernal:  MemBank::new(MemType::KERNAL),  // 8k
            basic_on:   false,
            chargen_on: false,
            io_on:      false,
            kernal_on:  false,
            cart_lo_on: false, // unused for now
            cart_hi_on: false, // unused for now
        }))
    }

    // returns memory bank for current latch setting and address
    pub fn get_bank(&mut self, addr: u16) -> (&mut MemBank)
    {
        match addr
        {
            0x0000...0x9FFF => &mut self.ram,
            0xA000...0xBFFF => if self.basic_on { &mut self.basic } else { &mut self.ram },
            0xC000...0xCFFF => &mut self.ram,
            0xD000...0xDFFF => {
                if self.chargen_on { return &mut self.chargen }
                if self.io_on      { return &mut self.io; }
                return &mut self.ram;
            },
            0xE000...0xFFFF => if self.kernal_on  { &mut self.kernal } else { &mut self.ram },
            _ => panic!("Address out of memory range")
        }
    }

    // returns specific modifiable memory bank
    pub fn get_ram_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::RAM => &mut self.ram,
            MemType::IO  => &mut self.io,
            _            => panic!("Unrecognized RAM bank"),
        }
    }

    // returns specific non-modifiable memory bank
    pub fn get_rom_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::BASIC   => &mut self.basic,
            MemType::CHARGEN => &mut self.chargen,
            MemType::KERNAL  => &mut self.kernal,
            _                => panic!("Unrecognized ROM Abank"),
        }
    }

    pub fn reset(&mut self)
    {
        self.write_byte(0x0000, 0xFF);
        self.write_byte(0x0001, 0x07); // enable kernal, chargen and basic ROMs
    }

    fn update_bank_flags(&mut self)
    {
        // latch state is determined by 3 least significant bits from this location
        let latch = self.ram.read(0x0001) & 0x07;

        self.chargen_on = ((latch & 0x04) == 0) && ((latch & 0x03) != 0); // %0xx except %000
        self.io_on      = ((latch & 0x04) != 0) && ((latch & 0x03) != 0); // %1xx except %100
        self.basic_on   = (latch & 0x03) == 0x03;
        self.kernal_on  = self.basic_on || ((latch & 0x03) == 0x02);
    }

    // Write a byte to memory - returns whether RAM was written (true) or RAM under ROM (false)
    pub fn write_byte(&mut self, addr: u16, value: u8) -> bool
    {
        // RAM under ROM written? Return false to let us know about it
        if self.get_bank(addr).read_only
        {
            self.ram.write(addr, value);
            return false;
        }
        else
        {
            self.get_bank(addr).write(addr, value);
        }

        // update the bank switching flags here, since they can only change on memory write
        // latch byte changed - update bank switching flags
        if addr == 0x0001 { self.update_bank_flags(); }

        return true;
    }

    // Read a byte from memory
    pub fn read_byte(&mut self, addr: u16) -> u8
    {
        self.get_bank(addr).read(addr)
    }

    // Read a word from memory (stored in little endian)
    pub fn read_word_le(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_be: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    // Read a word from memory (stored in big endian: swap low<->high)
    pub fn read_word_be(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_le: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);
        value_le
    }

    // Write word in little endian format (low/high)
    pub fn write_word_le(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_lo);
        let lo = self.write_byte(addr + 0x0001, value_le_hi);

        return hi && lo;
    }

    // Write word in big endian format (high/low)
    pub fn write_word_be(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_hi);
        let lo = self.write_byte(addr + 0x0001, value_le_lo);

        return hi && lo;
    }
}

<|endoftext|>


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

#![crate_type = "rlib"]

pub static mut statik: int = 0;

struct A;
impl Drop for A {
    fn drop(&mut self) {
        unsafe { statik = 1; }
    }
}

pub fn callback(f: ||) {
    let _a = A;
    f();
}
<commit_msg>fix run-make test<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_type = "rlib"]

pub static mut statik: int = 0;

struct A;
impl Drop for A {
    fn drop(&mut self) {
        unsafe { statik = 1; }
    }
}

pub fn callback<F>(f: F) where F: FnOnce() {
    let _a = A;
    f();
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::path::{Path, PathBuf};
use yaml_rust::{Yaml, YamlEmitter, YamlLoader};

/// List of directories containing files to expand. The first tuple element is the source
/// directory, while the second tuple element is the destination directory.
#[rustfmt::skip]
static TO_EXPAND: &[(&str, &str)] = &[
    ("src/ci/github-actions", ".github/workflows"),
];

/// Name of a special key that will be removed from all the maps in expanded configuration files.
/// This key can then be used to contain shared anchors.
static REMOVE_MAP_KEY: &str = "x--expand-yaml-anchors--remove";

/// Message that will be included at the top of all the expanded files. {source} will be replaced
/// with the source filename relative to the base path.
static HEADER_MESSAGE: &str = "\
#############################################################
#   WARNING: automatically generated file, DO NOT CHANGE!   #
#############################################################

# This file was automatically generated by the expand-yaml-anchors tool. The
# source file that generated this one is:
#
#   {source}
#
# Once you make changes to that file you need to run:
#
#   ./x.py run src/tools/expand-yaml-anchors/
#
# The CI build will fail if the tool is not run after changes to this file.

";

enum Mode {
    Check,
    Generate,
}

struct App {
    mode: Mode,
    base: PathBuf,
}

impl App {
    fn from_args() -> Result<Self, Box<dyn Error>> {
        // Parse CLI arguments
        let args = std::env::args().skip(1).collect::<Vec<_>>();
        let (mode, base) = match args.iter().map(|s| s.as_str()).collect::<Vec<_>>().as_slice() {
            ["generate", ref base] => (Mode::Generate, PathBuf::from(base)),
            ["check", ref base] => (Mode::Check, PathBuf::from(base)),
            _ => {
                eprintln!("usage: expand-yaml-anchors <source-dir> <dest-dir>");
                std::process::exit(1);
            }
        };

        Ok(App { mode, base })
    }

    fn run(&self) -> Result<(), Box<dyn Error>> {
        for (source, dest) in TO_EXPAND {
            let source = self.base.join(source);
            let dest = self.base.join(dest);
            for entry in std::fs::read_dir(&source)? {
                let path = entry?.path();
                if !path.is_file() || path.extension().and_then(|e| e.to_str()) != Some("yml") {
                    continue;
                }

                let dest_path = dest.join(path.file_name().unwrap());
                self.expand(&path, &dest_path).with_context(|| match self.mode {
                    Mode::Generate => format!(
                        "failed to expand {} into {}",
                        self.path(&path),
                        self.path(&dest_path)
                    ),
                    Mode::Check => format!("{} is not up to date", self.path(&dest_path)),
                })?;
            }
        }
        Ok(())
    }

    fn expand(&self, source: &Path, dest: &Path) -> Result<(), Box<dyn Error>> {
        let content = std::fs::read_to_string(source)
            .with_context(|| format!("failed to read {}", self.path(source)))?;

        let mut buf = HEADER_MESSAGE.replace("{source}", &self.path(source).to_string());

        let documents = YamlLoader::load_from_str(&content)
            .with_context(|| format!("failed to parse {}", self.path(source)))?;
        for mut document in documents.into_iter() {
            document = yaml_merge_keys::merge_keys(document)
                .with_context(|| format!("failed to expand {}", self.path(source)))?;
            document = filter_document(document);

            YamlEmitter::new(&mut buf).dump(&document).map_err(|err| WithContext {
                context: "failed to serialize the expanded yaml".into(),
                source: Box::new(err),
            })?;
            buf.push('\n');
        }

        match self.mode {
            Mode::Check => {
                let old = std::fs::read_to_string(dest)
                    .with_context(|| format!("failed to read {}", self.path(dest)))?;
                if old != buf {
                    return Err(Box::new(StrError(format!(
                        "{} and {} are different",
                        self.path(source),
                        self.path(dest),
                    ))));
                }
            }
            Mode::Generate => {
                std::fs::write(dest, buf.as_bytes())
                    .with_context(|| format!("failed to write to {}", self.path(dest)))?;
            }
        }
        Ok(())
    }

    fn path<'a>(&self, path: &'a Path) -> impl std::fmt::Display + 'a {
        path.strip_prefix(&self.base).unwrap_or(path).display()
    }
}

fn filter_document(document: Yaml) -> Yaml {
    match document {
        Yaml::Hash(map) => Yaml::Hash(
            map.into_iter()
                .filter(|(key, _)| {
                    if let Yaml::String(string) = &key { string != REMOVE_MAP_KEY } else { true }
                })
                .map(|(key, value)| (filter_document(key), filter_document(value)))
                .collect(),
        ),
        Yaml::Array(vec) => Yaml::Array(vec.into_iter().map(filter_document).collect()),
        other => other,
    }
}

fn main() {
    if let Err(err) = App::from_args().and_then(|app| app.run()) {
        eprintln!("error: {}", err);

        let mut source = err.as_ref() as &dyn Error;
        while let Some(err) = source.source() {
            eprintln!("caused by: {}", err);
            source = err;
        }

        std::process::exit(1);
    }
}

#[derive(Debug)]
struct StrError(String);

impl Error for StrError {}

impl std::fmt::Display for StrError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Display::fmt(&self.0, f)
    }
}

#[derive(Debug)]
struct WithContext {
    context: String,
    source: Box<dyn Error>,
}

impl std::fmt::Display for WithContext {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.context)
    }
}

impl Error for WithContext {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        Some(self.source.as_ref())
    }
}

pub(crate) trait ResultExt<T> {
    fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T, Box<dyn Error>>;
}

impl<T, E: Into<Box<dyn Error>>> ResultExt<T> for Result<T, E> {
    fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T, Box<dyn Error>> {
        match self {
            Ok(ok) => Ok(ok),
            Err(err) => Err(WithContext { source: err.into(), context: f() }.into()),
        }
    }
}
<commit_msg>expand-yaml-anchors: Make the output directory separator-insensitive<commit_after>use std::error::Error;
use std::path::{Path, PathBuf};
use yaml_rust::{Yaml, YamlEmitter, YamlLoader};

/// List of directories containing files to expand. The first tuple element is the source
/// directory, while the second tuple element is the destination directory.
#[rustfmt::skip]
static TO_EXPAND: &[(&str, &str)] = &[
    ("src/ci/github-actions", ".github/workflows"),
];

/// Name of a special key that will be removed from all the maps in expanded configuration files.
/// This key can then be used to contain shared anchors.
static REMOVE_MAP_KEY: &str = "x--expand-yaml-anchors--remove";

/// Message that will be included at the top of all the expanded files. {source} will be replaced
/// with the source filename relative to the base path.
static HEADER_MESSAGE: &str = "\
#############################################################
#   WARNING: automatically generated file, DO NOT CHANGE!   #
#############################################################

# This file was automatically generated by the expand-yaml-anchors tool. The
# source file that generated this one is:
#
#   {source}
#
# Once you make changes to that file you need to run:
#
#   ./x.py run src/tools/expand-yaml-anchors/
#
# The CI build will fail if the tool is not run after changes to this file.

";

enum Mode {
    Check,
    Generate,
}

struct App {
    mode: Mode,
    base: PathBuf,
}

impl App {
    fn from_args() -> Result<Self, Box<dyn Error>> {
        // Parse CLI arguments
        let args = std::env::args().skip(1).collect::<Vec<_>>();
        let (mode, base) = match args.iter().map(|s| s.as_str()).collect::<Vec<_>>().as_slice() {
            ["generate", ref base] => (Mode::Generate, PathBuf::from(base)),
            ["check", ref base] => (Mode::Check, PathBuf::from(base)),
            _ => {
                eprintln!("usage: expand-yaml-anchors <source-dir> <dest-dir>");
                std::process::exit(1);
            }
        };

        Ok(App { mode, base })
    }

    fn run(&self) -> Result<(), Box<dyn Error>> {
        for (source, dest) in TO_EXPAND {
            let source = self.base.join(source);
            let dest = self.base.join(dest);
            for entry in std::fs::read_dir(&source)? {
                let path = entry?.path();
                if !path.is_file() || path.extension().and_then(|e| e.to_str()) != Some("yml") {
                    continue;
                }

                let dest_path = dest.join(path.file_name().unwrap());
                self.expand(&path, &dest_path).with_context(|| match self.mode {
                    Mode::Generate => format!(
                        "failed to expand {} into {}",
                        self.path(&path),
                        self.path(&dest_path)
                    ),
                    Mode::Check => format!("{} is not up to date", self.path(&dest_path)),
                })?;
            }
        }
        Ok(())
    }

    fn expand(&self, source: &Path, dest: &Path) -> Result<(), Box<dyn Error>> {
        let content = std::fs::read_to_string(source)
            .with_context(|| format!("failed to read {}", self.path(source)))?;

        let mut buf =
            HEADER_MESSAGE.replace("{source}", &self.path(source).to_string().replace("\\", "/"));

        let documents = YamlLoader::load_from_str(&content)
            .with_context(|| format!("failed to parse {}", self.path(source)))?;
        for mut document in documents.into_iter() {
            document = yaml_merge_keys::merge_keys(document)
                .with_context(|| format!("failed to expand {}", self.path(source)))?;
            document = filter_document(document);

            YamlEmitter::new(&mut buf).dump(&document).map_err(|err| WithContext {
                context: "failed to serialize the expanded yaml".into(),
                source: Box::new(err),
            })?;
            buf.push('\n');
        }

        match self.mode {
            Mode::Check => {
                let old = std::fs::read_to_string(dest)
                    .with_context(|| format!("failed to read {}", self.path(dest)))?;
                if old != buf {
                    return Err(Box::new(StrError(format!(
                        "{} and {} are different",
                        self.path(source),
                        self.path(dest),
                    ))));
                }
            }
            Mode::Generate => {
                std::fs::write(dest, buf.as_bytes())
                    .with_context(|| format!("failed to write to {}", self.path(dest)))?;
            }
        }
        Ok(())
    }

    fn path<'a>(&self, path: &'a Path) -> impl std::fmt::Display + 'a {
        path.strip_prefix(&self.base).unwrap_or(path).display()
    }
}

fn filter_document(document: Yaml) -> Yaml {
    match document {
        Yaml::Hash(map) => Yaml::Hash(
            map.into_iter()
                .filter(|(key, _)| {
                    if let Yaml::String(string) = &key { string != REMOVE_MAP_KEY } else { true }
                })
                .map(|(key, value)| (filter_document(key), filter_document(value)))
                .collect(),
        ),
        Yaml::Array(vec) => Yaml::Array(vec.into_iter().map(filter_document).collect()),
        other => other,
    }
}

fn main() {
    if let Err(err) = App::from_args().and_then(|app| app.run()) {
        eprintln!("error: {}", err);

        let mut source = err.as_ref() as &dyn Error;
        while let Some(err) = source.source() {
            eprintln!("caused by: {}", err);
            source = err;
        }

        std::process::exit(1);
    }
}

#[derive(Debug)]
struct StrError(String);

impl Error for StrError {}

impl std::fmt::Display for StrError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Display::fmt(&self.0, f)
    }
}

#[derive(Debug)]
struct WithContext {
    context: String,
    source: Box<dyn Error>,
}

impl std::fmt::Display for WithContext {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.context)
    }
}

impl Error for WithContext {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        Some(self.source.as_ref())
    }
}

pub(crate) trait ResultExt<T> {
    fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T, Box<dyn Error>>;
}

impl<T, E: Into<Box<dyn Error>>> ResultExt<T> for Result<T, E> {
    fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T, Box<dyn Error>> {
        match self {
            Ok(ok) => Ok(ok),
            Err(err) => Err(WithContext { source: err.into(), context: f() }.into()),
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::fmt;
use std::io;
use std::ops::Deref;
use std::ops::DerefMut;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;

use bytes::BufMut;
use bytes::Bytes;
use bytes::BytesMut;
use futures::future;
use futures::Future;
use futures::Stream;
use tokio::io::AsyncRead;
use tokio::io::ReadBuf;

use crate::solicit_async::TryFutureBox;
use crate::solicit_async::TryStreamBox;
use crate::DataOrTrailers;
use crate::Headers;

pub trait StreamAfterHeaders: fmt::Debug + Unpin + Send + 'static {
    /// Fetch the next message without increasing the window size.
    ///
    /// This is lower-level operation, might not be needed to be used.
    fn poll_next_no_auto(
        &mut self,
        cx: &mut Context<'_>,
    ) -> Poll<Option<crate::Result<DataOrTrailers>>>;

    /// `Stream`-like operation.
    fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<crate::Result<DataOrTrailers>>>;

    /// Poll `DATA` frame from the stream.
    ///
    /// Note when this operation returns `None`, trailers can still be fetched
    /// with [`poll_trailers`].
    fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<crate::Result<Bytes>>>;

    /// Poll trailing `HEADERS` frame from the stream.
    ///
    /// This operation returns `None` if not all `DATA` frames fetched yet.
    fn poll_trailers(&mut self, cx: &mut Context<'_>) -> Poll<Option<crate::Result<Headers>>>;

    /// Current effective Window size known to the caller. This is a sum of:
    ///
    /// * window size known to the peer
    /// * all `DATA` messages traveling in the network
    /// * all `DATA` frame not yet fetched from this stream
    fn in_window_size(&self) -> u32;

    /// Explicitly request to increase Window size.
    ///
    /// Note this operation might be expensive, because each invocation sends a `WINDOW_UPDATE`
    /// frame. You probably might want to use default or update the default with
    /// [`set_auto_in_window_size`].
    fn inc_in_window(&mut self, delta: u32) -> crate::Result<()>;

    /// Window will be increased each time current window size drops below the half
    /// of given value when `poll_next` is used.
    fn set_auto_in_window_size(&mut self, window_size: u32) -> crate::Result<()>;

    // Utilities

    /// Fetch next frame.
    fn next<'a>(
        &'a mut self,
    ) -> Pin<Box<dyn Future<Output = crate::Result<Option<DataOrTrailers>>> + 'a>> {
        Box::pin(future::poll_fn(move |cx| self.poll_next(cx)?.map(Ok)))
    }

    /// Fetch next `DATA`.
    fn next_data<'a>(
        &'a mut self,
    ) -> Pin<Box<dyn Future<Output = crate::Result<Option<Bytes>>> + Send + 'a>> {
        Box::pin(future::poll_fn(move |cx| self.poll_data(cx)?.map(Ok)))
    }

    /// Fetch trailers. This returns `None` if not all `DATA` frames processed.
    fn next_trailers<'a>(
        &'a mut self,
    ) -> Pin<Box<dyn Future<Output = crate::Result<Option<Headers>>> + 'a>> {
        Box::pin(future::poll_fn(move |cx| self.poll_trailers(cx)?.map(Ok)))
    }

    fn into_read(self) -> Pin<Box<dyn AsyncRead + Send + 'static>>
    where
        Self: Sized,
    {
        Box::pin(AsRead {
            stream: self,
            rem: Bytes::new(),
        })
    }

    fn into_stream(self) -> TryStreamBox<DataOrTrailers>
    where
        Self: Sized,
    {
        Box::pin(AsStream(self))
    }

    fn filter_data(self) -> TryStreamBox<Bytes>
    where
        Self: Sized,
    {
        Box::pin(DataStream(self))
    }

    fn collect_data(mut self) -> TryFutureBox<Bytes>
    where
        Self: Sized,
    {
        Box::pin(async move {
            let mut r = BytesMut::new();
            loop {
                match self.next_data().await? {
                    None => return Ok(r.freeze()),
                    Some(b) => {
                        // TODO: figure out how to efficiently extend from Bytes
                        r.put_slice(&b)
                    }
                }
            }
        })
    }
}

struct AsStream<S: StreamAfterHeaders>(S);

impl<S: StreamAfterHeaders> Stream for AsStream<S> {
    type Item = crate::Result<DataOrTrailers>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        Pin::new(&mut self.get_mut().0).poll_next(cx)
    }
}

struct DataStream<S: StreamAfterHeaders>(S);

impl<S: StreamAfterHeaders> Stream for DataStream<S> {
    type Item = crate::Result<Bytes>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        Pin::new(&mut self.get_mut().0).poll_data(cx)
    }
}

pub struct AsRead<S: StreamAfterHeaders> {
    stream: S,
    rem: Bytes,
}

impl<S: StreamAfterHeaders> AsyncRead for AsRead<S> {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf,
    ) -> Poll<io::Result<()>> {
        // TODO: untested
        let me = self.get_mut();

        loop {
            if !me.rem.is_empty() {
                let min = cmp::min(me.rem.len(), buf.remaining());
                buf.put_slice(&me.rem.split_to(min));
                return Poll::Ready(Ok(()));
            }

            me.rem = match Pin::new(&mut me.stream).poll_data(cx) {
                Poll::Ready(Some(Err(e))) => return Poll::Ready(Err(e.into())),
                Poll::Ready(None) => return Poll::Ready(Ok(())),
                Poll::Ready(Some(Ok(bytes))) => bytes,
                Poll::Pending => return Poll::Pending,
            }
        }
    }
}

pub type StreamAfterHeadersBox = Pin<Box<dyn StreamAfterHeaders>>;

#[derive(Debug)]
pub(crate) struct HttpStreamAfterHeadersEmpty;

impl StreamAfterHeaders for HttpStreamAfterHeadersEmpty {
    fn poll_next(&mut self, _cx: &mut Context<'_>) -> Poll<Option<crate::Result<DataOrTrailers>>> {
        Poll::Ready(None)
    }

    fn in_window_size(&self) -> u32 {
        0
    }

    fn inc_in_window(&mut self, _delta: u32) -> crate::Result<()> {
        Ok(())
    }

    fn set_auto_in_window_size(&mut self, _window_size: u32) -> crate::Result<()> {
        Ok(())
    }

    fn poll_next_no_auto(
        &mut self,
        _cx: &mut Context<'_>,
    ) -> Poll<Option<crate::Result<DataOrTrailers>>> {
        Poll::Ready(None)
    }

    fn poll_data(&mut self, _cx: &mut Context<'_>) -> Poll<Option<crate::Result<Bytes>>> {
        Poll::Ready(None)
    }

    fn poll_trailers(&mut self, _cx: &mut Context<'_>) -> Poll<Option<crate::Result<Headers>>> {
        Poll::Ready(None)
    }
}

impl StreamAfterHeaders for Pin<Box<dyn StreamAfterHeaders>> {
    fn poll_next(&mut self, _cx: &mut Context<'_>) -> Poll<Option<crate::Result<DataOrTrailers>>> {
        self.deref_mut().poll_next(_cx)
    }

    fn in_window_size(&self) -> u32 {
        self.deref().in_window_size()
    }

    fn inc_in_window(&mut self, delta: u32) -> crate::Result<()> {
        self.deref_mut().inc_in_window(delta)
    }

    fn set_auto_in_window_size(&mut self, window_size: u32) -> crate::Result<()> {
        self.deref_mut().set_auto_in_window_size(window_size)
    }

    fn poll_next_no_auto(
        &mut self,
        cx: &mut Context<'_>,
    ) -> Poll<Option<crate::Result<DataOrTrailers>>> {
        self.deref_mut().poll_next_no_auto(cx)
    }

    fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<crate::Result<Bytes>>> {
        self.deref_mut().poll_data(cx)
    }

    fn poll_trailers(&mut self, cx: &mut Context<'_>) -> Poll<Option<crate::Result<Headers>>> {
        self.deref_mut().poll_trailers(cx)
    }
}
<commit_msg>Fix doc<commit_after>use std::cmp;
use std::fmt;
use std::io;
use std::ops::Deref;
use std::ops::DerefMut;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;

use bytes::BufMut;
use bytes::Bytes;
use bytes::BytesMut;
use futures::future;
use futures::Future;
use futures::Stream;
use tokio::io::AsyncRead;
use tokio::io::ReadBuf;

use crate::solicit_async::TryFutureBox;
use crate::solicit_async::TryStreamBox;
use crate::DataOrTrailers;
use crate::Headers;

pub trait StreamAfterHeaders: fmt::Debug + Unpin + Send + 'static {
    /// Fetch the next message without increasing the window size.
    ///
    /// This is lower-level operation, might not be needed to be used.
    fn poll_next_no_auto(
        &mut self,
        cx: &mut Context<'_>,
    ) -> Poll<Option<crate::Result<DataOrTrailers>>>;

    /// Fetch next frame and auto-update in window.
    fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<crate::Result<DataOrTrailers>>>;

    /// Poll `DATA` frame from the stream.
    ///
    /// Note when this operation returns `None`, trailers can still be fetched
    /// with [`poll_trailers`](Self::poll_trailers).
    fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<crate::Result<Bytes>>>;

    /// Poll trailing `HEADERS` frame from the stream.
    ///
    /// This operation returns `None` if not all `DATA` frames fetched yet.
    fn poll_trailers(&mut self, cx: &mut Context<'_>) -> Poll<Option<crate::Result<Headers>>>;

    /// Current effective Window size known to the caller. This is a sum of:
    ///
    /// * window size known to the peer
    /// * all `DATA` messages traveling in the network
    /// * all `DATA` frame not yet fetched from this stream
    fn in_window_size(&self) -> u32;

    /// Explicitly request to increase Window size.
    ///
    /// Note this operation might be expensive, because each invocation sends a `WINDOW_UPDATE`
    /// frame. You probably might want to use default or update the default with
    /// [`set_auto_in_window_size`](Self::set_auto_in_window_size).
    fn inc_in_window(&mut self, delta: u32) -> crate::Result<()>;

    /// Window will be increased each time current window size drops below the half
    /// of given value when `poll_next` is used.
    fn set_auto_in_window_size(&mut self, window_size: u32) -> crate::Result<()>;

    // Utilities

    /// Fetch next frame.
    fn next<'a>(
        &'a mut self,
    ) -> Pin<Box<dyn Future<Output = crate::Result<Option<DataOrTrailers>>> + 'a>> {
        Box::pin(future::poll_fn(move |cx| self.poll_next(cx)?.map(Ok)))
    }

    /// Fetch next `DATA`.
    fn next_data<'a>(
        &'a mut self,
    ) -> Pin<Box<dyn Future<Output = crate::Result<Option<Bytes>>> + Send + 'a>> {
        Box::pin(future::poll_fn(move |cx| self.poll_data(cx)?.map(Ok)))
    }

    /// Fetch trailers. This returns `None` if not all `DATA` frames processed.
    fn next_trailers<'a>(
        &'a mut self,
    ) -> Pin<Box<dyn Future<Output = crate::Result<Option<Headers>>> + 'a>> {
        Box::pin(future::poll_fn(move |cx| self.poll_trailers(cx)?.map(Ok)))
    }

    fn into_read(self) -> Pin<Box<dyn AsyncRead + Send + 'static>>
    where
        Self: Sized,
    {
        Box::pin(AsRead {
            stream: self,
            rem: Bytes::new(),
        })
    }

    fn into_stream(self) -> TryStreamBox<DataOrTrailers>
    where
        Self: Sized,
    {
        Box::pin(AsStream(self))
    }

    fn filter_data(self) -> TryStreamBox<Bytes>
    where
        Self: Sized,
    {
        Box::pin(DataStream(self))
    }

    fn collect_data(mut self) -> TryFutureBox<Bytes>
    where
        Self: Sized,
    {
        Box::pin(async move {
            let mut r = BytesMut::new();
            loop {
                match self.next_data().await? {
                    None => return Ok(r.freeze()),
                    Some(b) => {
                        // TODO: figure out how to efficiently extend from Bytes
                        r.put_slice(&b)
                    }
                }
            }
        })
    }
}

struct AsStream<S: StreamAfterHeaders>(S);

impl<S: StreamAfterHeaders> Stream for AsStream<S> {
    type Item = crate::Result<DataOrTrailers>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        Pin::new(&mut self.get_mut().0).poll_next(cx)
    }
}

struct DataStream<S: StreamAfterHeaders>(S);

impl<S: StreamAfterHeaders> Stream for DataStream<S> {
    type Item = crate::Result<Bytes>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        Pin::new(&mut self.get_mut().0).poll_data(cx)
    }
}

pub struct AsRead<S: StreamAfterHeaders> {
    stream: S,
    rem: Bytes,
}

impl<S: StreamAfterHeaders> AsyncRead for AsRead<S> {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf,
    ) -> Poll<io::Result<()>> {
        // TODO: untested
        let me = self.get_mut();

        loop {
            if !me.rem.is_empty() {
                let min = cmp::min(me.rem.len(), buf.remaining());
                buf.put_slice(&me.rem.split_to(min));
                return Poll::Ready(Ok(()));
            }

            me.rem = match Pin::new(&mut me.stream).poll_data(cx) {
                Poll::Ready(Some(Err(e))) => return Poll::Ready(Err(e.into())),
                Poll::Ready(None) => return Poll::Ready(Ok(())),
                Poll::Ready(Some(Ok(bytes))) => bytes,
                Poll::Pending => return Poll::Pending,
            }
        }
    }
}

pub type StreamAfterHeadersBox = Pin<Box<dyn StreamAfterHeaders>>;

#[derive(Debug)]
pub(crate) struct HttpStreamAfterHeadersEmpty;

impl StreamAfterHeaders for HttpStreamAfterHeadersEmpty {
    fn poll_next(&mut self, _cx: &mut Context<'_>) -> Poll<Option<crate::Result<DataOrTrailers>>> {
        Poll::Ready(None)
    }

    fn in_window_size(&self) -> u32 {
        0
    }

    fn inc_in_window(&mut self, _delta: u32) -> crate::Result<()> {
        Ok(())
    }

    fn set_auto_in_window_size(&mut self, _window_size: u32) -> crate::Result<()> {
        Ok(())
    }

    fn poll_next_no_auto(
        &mut self,
        _cx: &mut Context<'_>,
    ) -> Poll<Option<crate::Result<DataOrTrailers>>> {
        Poll::Ready(None)
    }

    fn poll_data(&mut self, _cx: &mut Context<'_>) -> Poll<Option<crate::Result<Bytes>>> {
        Poll::Ready(None)
    }

    fn poll_trailers(&mut self, _cx: &mut Context<'_>) -> Poll<Option<crate::Result<Headers>>> {
        Poll::Ready(None)
    }
}

impl StreamAfterHeaders for Pin<Box<dyn StreamAfterHeaders>> {
    fn poll_next(&mut self, _cx: &mut Context<'_>) -> Poll<Option<crate::Result<DataOrTrailers>>> {
        self.deref_mut().poll_next(_cx)
    }

    fn in_window_size(&self) -> u32 {
        self.deref().in_window_size()
    }

    fn inc_in_window(&mut self, delta: u32) -> crate::Result<()> {
        self.deref_mut().inc_in_window(delta)
    }

    fn set_auto_in_window_size(&mut self, window_size: u32) -> crate::Result<()> {
        self.deref_mut().set_auto_in_window_size(window_size)
    }

    fn poll_next_no_auto(
        &mut self,
        cx: &mut Context<'_>,
    ) -> Poll<Option<crate::Result<DataOrTrailers>>> {
        self.deref_mut().poll_next_no_auto(cx)
    }

    fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<crate::Result<Bytes>>> {
        self.deref_mut().poll_data(cx)
    }

    fn poll_trailers(&mut self, cx: &mut Context<'_>) -> Poll<Option<crate::Result<Headers>>> {
        self.deref_mut().poll_trailers(cx)
    }
}
<|endoftext|>


<commit_before>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use term;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc::channel;
use std::thread::{self, JoinHandle};

/// Because sometimes, you just want a global variable.
static mut show_spinner: bool = true;

pub struct Spinner {
    tx: Sender<isize>,
    guard: JoinHandle<()>
}

impl Spinner {
    pub fn start() -> Spinner {
        let (tx, rx) = channel::<isize>();
        let spinner = thread::spawn(move|| { Spinner::spin(rx) });
        Spinner{ tx: tx, guard: spinner }
    }

    pub fn stop(self) {
        let _ = self.tx.send(1);
        let _ = self.guard.join();
    }

    fn spin(rx: Receiver<isize>) {
        let spinner_chars = vec!["|", "/", "-", "\\"];
        for spin in spinner_chars.iter().cycle() {
            unsafe {
                if show_spinner {
                    say("yellow", *spin);
                }
            }
            let r = rx.try_recv();
            match r {
                Ok(_) => {
                    unsafe {
                        if show_spinner {
                            say("white", "\x08 \x08");
                        }
                    }
                    break;
                },
                Err(_) => {
                    thread::sleep_ms(100);
                    unsafe {
                        if show_spinner {
                            say("white", "\x08");
                        }
                    }
                    continue;
                }
            }
        }
    }
}

pub fn turn_off_spinner() {
    unsafe {
        show_spinner = false;
    }
}

fn say_term(mut t: Box<term::StdoutTerminal>, color: &str, to_say: &str) {
    let color_const = match color {
        "green" => term::color::BRIGHT_GREEN,
        "yellow" => term::color::BRIGHT_YELLOW,
        "red" => term::color::BRIGHT_RED,
        "magenta" => term::color::BRIGHT_MAGENTA,
        "white" => term::color::WHITE,
        _ => term::color::WHITE
    };
    t.fg(color_const).unwrap();
    t.write_all(to_say.as_bytes()).unwrap();
    t.reset().unwrap();
}

pub fn say(color: &str, to_say: &str) {
    match term::stdout() {
        Some(t) => say_term(t, color, to_say),
        None => print!("{}", to_say)
    }
}

pub fn sayln(color: &str, to_say: &str) {
    say(color, to_say);
    say(color, "\n");
}
<commit_msg>Fix the spinner<commit_after>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use term;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc::channel;
use std::thread::{self, JoinHandle};
use std::io::prelude::*;
use std::io;

/// Because sometimes, you just want a global variable.
static mut show_spinner: bool = true;

pub struct Spinner {
    tx: Sender<isize>,
    guard: JoinHandle<()>
}

impl Spinner {
    pub fn start() -> Spinner {
        let (tx, rx) = channel::<isize>();
        let spinner = thread::spawn(move|| { Spinner::spin(rx) });
        Spinner{ tx: tx, guard: spinner }
    }

    pub fn stop(self) {
        let _ = self.tx.send(1);
        let _ = self.guard.join();
    }

    fn spin(rx: Receiver<isize>) {
        let spinner_chars = vec!["|", "/", "-", "\\"];
        for spin in spinner_chars.iter().cycle() {
            unsafe {
                if show_spinner {
                    say("yellow", *spin);
                }
            }
            let r = rx.try_recv();
            match r {
                Ok(_) => {
                    unsafe {
                        if show_spinner {
                            say("white", "\x08 \x08");
                        }
                    }
                    break;
                },
                Err(_) => {
                    thread::sleep_ms(100);
                    unsafe {
                        if show_spinner {
                            say("white", "\x08");
                        }
                    }
                    continue;
                }
            }
        }
    }
}

pub fn turn_off_spinner() {
    unsafe {
        show_spinner = false;
    }
}

fn say_term(mut t: Box<term::StdoutTerminal>, color: &str, to_say: &str) {
    let color_const = match color {
        "green" => term::color::BRIGHT_GREEN,
        "yellow" => term::color::BRIGHT_YELLOW,
        "red" => term::color::BRIGHT_RED,
        "magenta" => term::color::BRIGHT_MAGENTA,
        "white" => term::color::WHITE,
        _ => term::color::WHITE
    };
    t.fg(color_const).unwrap();
    t.write_all(to_say.as_bytes()).unwrap();
    t.reset().unwrap();
    io::stdout().flush().ok().expect("Could not flush stdout");
}

pub fn say(color: &str, to_say: &str) {
    match term::stdout() {
        Some(t) => say_term(t, color, to_say),
        None => {
            print!("{}", to_say);
            io::stdout().flush().ok().expect("Could not flush stdout");
        }
    }
}

pub fn sayln(color: &str, to_say: &str) {
    say(color, to_say);
    say(color, "\n");
}
<|endoftext|>


<commit_before>use std::{iter, ptr, vec};

use serde::de::{
    self,
    value::{Error, SeqDeserializer},
    Deserializer, IntoDeserializer,
};

#[derive(Debug)]
pub enum ValOrVec<T> {
    Val(T),
    Vec(Vec<T>),
}

impl<T> ValOrVec<T> {
    pub fn push(&mut self, new_val: T) {
        match self {
            // To transform a Self::Val into a Self::Vec, we take the existing
            // value out via ptr::read and add it to a vector, together with the
            // new value. Since setting self to `ValOrVec::Vec` normally would
            // cause T's Drop implementation to run if it has one (which would
            // free resources that will now be owned by the first vec element),
            // we instead use ptr::write to set self to Self::Vec.
            ValOrVec::Val(val) => {
                let mut vec = Vec::with_capacity(2);
                // Safety: since the vec is pre-allocated, push can't panic, so
                //   there is no opportunity for outside code to observe an
                //   invalid state of self.
                unsafe {
                    let existing_val = ptr::read(val);
                    vec.push(existing_val);
                    vec.push(new_val);
                    ptr::write(self, ValOrVec::Vec(vec))
                }
            }
            ValOrVec::Vec(vec) => vec.push(new_val),
        }
    }
}

impl<T> IntoIterator for ValOrVec<T> {
    type Item = T;
    type IntoIter = IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter::new(self)
    }
}

pub enum IntoIter<T> {
    Val(iter::Once<T>),
    Vec(vec::IntoIter<T>),
}

impl<T> IntoIter<T> {
    fn new(vv: ValOrVec<T>) -> Self {
        match vv {
            ValOrVec::Val(val) => IntoIter::Val(iter::once(val)),
            ValOrVec::Vec(vec) => IntoIter::Vec(vec.into_iter()),
        }
    }
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            IntoIter::Val(iter) => iter.next(),
            IntoIter::Vec(iter) => iter.next(),
        }
    }
}

impl<'de, T> IntoDeserializer<'de> for ValOrVec<T>
where
    T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>,
{
    type Deserializer = Self;

    fn into_deserializer(self) -> Self::Deserializer {
        self
    }
}

macro_rules! forward_to_part {
    ($($method:ident,)*) => {
        $(
            fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
                where V: de::Visitor<'de>
            {
                match self {
                    ValOrVec::Val(val) => val.$method(visitor),
                    ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")),
                }
            }
        )*
    }
}

impl<'de, T> Deserializer<'de> for ValOrVec<T>
where
    T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>,
{
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self {
            ValOrVec::Val(val) => val.deserialize_any(visitor),
            ValOrVec::Vec(_) => self.deserialize_seq(visitor),
        }
    }

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_seq(SeqDeserializer::new(self.into_iter()))
    }

    fn deserialize_enum<V>(
        self,
        name: &'static str,
        variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self {
            ValOrVec::Val(val) => val.deserialize_enum(name, variants, visitor),
            ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")),
        }
    }

    fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self {
            ValOrVec::Val(val) => val.deserialize_tuple(len, visitor),
            ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")),
        }
    }

    fn deserialize_struct<V>(
        self,
        name: &'static str,
        fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self {
            ValOrVec::Val(val) => val.deserialize_struct(name, fields, visitor),
            ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")),
        }
    }

    fn deserialize_unit_struct<V>(
        self,
        name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self {
            ValOrVec::Val(val) => val.deserialize_unit_struct(name, visitor),
            ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")),
        }
    }

    fn deserialize_tuple_struct<V>(
        self,
        name: &'static str,
        len: usize,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self {
            ValOrVec::Val(val) => val.deserialize_tuple_struct(name, len, visitor),
            ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")),
        }
    }

    fn deserialize_newtype_struct<V>(
        self,
        name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self {
            ValOrVec::Val(val) => val.deserialize_newtype_struct(name, visitor),
            ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")),
        }
    }

    forward_to_part! {
        deserialize_bool,
        deserialize_char,
        deserialize_str,
        deserialize_string,
        deserialize_bytes,
        deserialize_byte_buf,
        deserialize_unit,
        deserialize_u8,
        deserialize_u16,
        deserialize_u32,
        deserialize_u64,
        deserialize_i8,
        deserialize_i16,
        deserialize_i32,
        deserialize_i64,
        deserialize_f32,
        deserialize_f64,
        deserialize_option,
        deserialize_identifier,
        deserialize_ignored_any,
        deserialize_map,
    }
}

#[cfg(test)]
mod tests {
    use std::borrow::Cow;

    use matches::assert_matches;

    use super::ValOrVec;

    #[test]
    fn cow_borrowed() {
        let mut x = ValOrVec::Val(Cow::Borrowed("a"));
        x.push(Cow::Borrowed("b"));
        x.push(Cow::Borrowed("c"));
        assert_matches!(x, ValOrVec::Vec(v) if v == vec!["a", "b", "c"]);
    }

    #[test]
    fn cow_owned() {
        let mut x = ValOrVec::Val(Cow::from("a".to_owned()));
        x.push(Cow::from("b".to_owned()));
        x.push(Cow::from("c".to_owned()));
        assert_matches!(
            x,
            ValOrVec::Vec(v) if v == vec!["a".to_owned(), "b".to_owned(), "c".to_owned()]
        );
    }
}
<commit_msg>serde: Simplify Deserializer implementation for ValOrVec<commit_after>use std::{iter, ptr, vec};

use serde::de::{
    self,
    value::{Error, SeqDeserializer},
    Deserializer, IntoDeserializer,
};

#[derive(Debug)]
pub enum ValOrVec<T> {
    Val(T),
    Vec(Vec<T>),
}

impl<T> ValOrVec<T> {
    pub fn push(&mut self, new_val: T) {
        match self {
            // To transform a Self::Val into a Self::Vec, we take the existing
            // value out via ptr::read and add it to a vector, together with the
            // new value. Since setting self to `ValOrVec::Vec` normally would
            // cause T's Drop implementation to run if it has one (which would
            // free resources that will now be owned by the first vec element),
            // we instead use ptr::write to set self to Self::Vec.
            ValOrVec::Val(val) => {
                let mut vec = Vec::with_capacity(2);
                // Safety: since the vec is pre-allocated, push can't panic, so
                //   there is no opportunity for outside code to observe an
                //   invalid state of self.
                unsafe {
                    let existing_val = ptr::read(val);
                    vec.push(existing_val);
                    vec.push(new_val);
                    ptr::write(self, ValOrVec::Vec(vec))
                }
            }
            ValOrVec::Vec(vec) => vec.push(new_val),
        }
    }

    fn deserialize_val<U, E, F>(self, f: F) -> Result<U, E>
    where
        F: FnOnce(T) -> Result<U, E>,
        E: de::Error,
    {
        match self {
            ValOrVec::Val(val) => f(val),
            ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")),
        }
    }
}

impl<T> IntoIterator for ValOrVec<T> {
    type Item = T;
    type IntoIter = IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter::new(self)
    }
}

pub enum IntoIter<T> {
    Val(iter::Once<T>),
    Vec(vec::IntoIter<T>),
}

impl<T> IntoIter<T> {
    fn new(vv: ValOrVec<T>) -> Self {
        match vv {
            ValOrVec::Val(val) => IntoIter::Val(iter::once(val)),
            ValOrVec::Vec(vec) => IntoIter::Vec(vec.into_iter()),
        }
    }
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            IntoIter::Val(iter) => iter.next(),
            IntoIter::Vec(iter) => iter.next(),
        }
    }
}

impl<'de, T> IntoDeserializer<'de> for ValOrVec<T>
where
    T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>,
{
    type Deserializer = Self;

    fn into_deserializer(self) -> Self::Deserializer {
        self
    }
}

macro_rules! forward_to_part {
    ($($method:ident,)*) => {
        $(
            fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
                where V: de::Visitor<'de>
            {
                self.deserialize_val(move |val| val.$method(visitor))
            }
        )*
    }
}

impl<'de, T> Deserializer<'de> for ValOrVec<T>
where
    T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>,
{
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self {
            ValOrVec::Val(val) => val.deserialize_any(visitor),
            ValOrVec::Vec(_) => self.deserialize_seq(visitor),
        }
    }

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_seq(SeqDeserializer::new(self.into_iter()))
    }

    fn deserialize_enum<V>(
        self,
        name: &'static str,
        variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_val(move |val| val.deserialize_enum(name, variants, visitor))
    }

    fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_val(move |val| val.deserialize_tuple(len, visitor))
    }

    fn deserialize_struct<V>(
        self,
        name: &'static str,
        fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_val(move |val| val.deserialize_struct(name, fields, visitor))
    }

    fn deserialize_unit_struct<V>(
        self,
        name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_val(move |val| val.deserialize_unit_struct(name, visitor))
    }

    fn deserialize_tuple_struct<V>(
        self,
        name: &'static str,
        len: usize,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_val(move |val| val.deserialize_tuple_struct(name, len, visitor))
    }

    fn deserialize_newtype_struct<V>(
        self,
        name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_val(move |val| val.deserialize_newtype_struct(name, visitor))
    }

    forward_to_part! {
        deserialize_bool,
        deserialize_char,
        deserialize_str,
        deserialize_string,
        deserialize_bytes,
        deserialize_byte_buf,
        deserialize_unit,
        deserialize_u8,
        deserialize_u16,
        deserialize_u32,
        deserialize_u64,
        deserialize_i8,
        deserialize_i16,
        deserialize_i32,
        deserialize_i64,
        deserialize_f32,
        deserialize_f64,
        deserialize_option,
        deserialize_identifier,
        deserialize_ignored_any,
        deserialize_map,
    }
}

#[cfg(test)]
mod tests {
    use std::borrow::Cow;

    use matches::assert_matches;

    use super::ValOrVec;

    #[test]
    fn cow_borrowed() {
        let mut x = ValOrVec::Val(Cow::Borrowed("a"));
        x.push(Cow::Borrowed("b"));
        x.push(Cow::Borrowed("c"));
        assert_matches!(x, ValOrVec::Vec(v) if v == vec!["a", "b", "c"]);
    }

    #[test]
    fn cow_owned() {
        let mut x = ValOrVec::Val(Cow::from("a".to_owned()));
        x.push(Cow::from("b".to_owned()));
        x.push(Cow::from("c".to_owned()));
        assert_matches!(
            x,
            ValOrVec::Vec(v) if v == vec!["a".to_owned(), "b".to_owned(), "c".to_owned()]
        );
    }
}
<|endoftext|>