<commit_before>//! Game window operations.

use input::InputEvent;

/// Settings for window behavior.
pub struct WindowSettings {
    /// Title of the window.
    pub title: String,
    /// The size of the window.
    pub size: [u32, ..2],
    /// Number samples per pixel (anti-aliasing).
    pub samples: u8,
    /// If true, the window is fullscreen.
    pub fullscreen: bool,
    /// If true, exit when pressing Esc.
    pub exit_on_esc: bool,
}

impl WindowSettings {
    /// Gets default settings.
    ///
    /// This exits the window when pressing `Esc`.
    /// The background color is set to black.
    pub fn default() -> WindowSettings {
        WindowSettings {
            title: "Piston".to_string(),
            size: [640, 480],
            samples: 0,
            fullscreen: false,
            exit_on_esc: true,
        }
    }
}

/// Implemented by window back-end.
pub trait Window {
    /// Get the window's settings.
    fn get_settings<'a>(&'a self) -> &'a WindowSettings;

    /// Returns true if the window should close.
    fn should_close(&self) -> bool;

    /// Inform the window that it should close.
    fn close(&mut self);

    /// Get the window's size
    fn get_size(&self) -> (u32, u32);

    /// Get the size in drawing coordinates.
    fn get_draw_size(&self) -> (u32, u32) {
        self.get_size()
    }

    /// Swap buffers.
    fn swap_buffers(&self) {}

    /// When the cursor is captured,
    /// it is hidden and the cursor position does not change.
    /// Only relative mouse motion is registered.
    fn capture_cursor(&mut self, _enabled: bool) {}

    /// Poll a event from window's event queue.
    fn poll_event(&mut self) -> Option<InputEvent> { None }
}

/// An implementation of GameWindow that represents running without a window at all
pub struct NoWindow {
    settings: WindowSettings,
    should_close: bool
}

impl NoWindow {
    /// Create a new nonexistant game window
    pub fn new(settings: WindowSettings) -> NoWindow {
         NoWindow {
             settings: settings,
             should_close: false
         }
    }
}

impl Window for NoWindow {
     fn get_settings<'a>(&'a self) -> &'a WindowSettings {
        &self.settings
     }

    fn should_close(&self) -> bool {
        self.should_close
    }

    fn close(&mut self) {
        self.should_close = true
    }

    fn get_size(&self) -> (u32, u32) {
        (0, 0)
    }
}
<commit_msg>Removed optional methods on Window<commit_after>//! Game window operations.

use input::InputEvent;

/// Settings for window behavior.
pub struct WindowSettings {
    /// Title of the window.
    pub title: String,
    /// The size of the window.
    pub size: [u32, ..2],
    /// Number samples per pixel (anti-aliasing).
    pub samples: u8,
    /// If true, the window is fullscreen.
    pub fullscreen: bool,
    /// If true, exit when pressing Esc.
    pub exit_on_esc: bool,
}

impl WindowSettings {
    /// Gets default settings.
    ///
    /// This exits the window when pressing `Esc`.
    /// The background color is set to black.
    pub fn default() -> WindowSettings {
        WindowSettings {
            title: "Piston".to_string(),
            size: [640, 480],
            samples: 0,
            fullscreen: false,
            exit_on_esc: true,
        }
    }
}

/// Implemented by window back-end.
pub trait Window {
    /// Get the window's settings.
    fn get_settings<'a>(&'a self) -> &'a WindowSettings;

    /// Returns true if the window should close.
    fn should_close(&self) -> bool;

    /// Inform the window that it should close.
    fn close(&mut self);

    /// Get the window's size
    fn get_size(&self) -> (u32, u32);

    /// Get the size in drawing coordinates.
    fn get_draw_size(&self) -> (u32, u32);

    /// Swap buffers.
    fn swap_buffers(&self);

    /// When the cursor is captured,
    /// it is hidden and the cursor position does not change.
    /// Only relative mouse motion is registered.
    fn capture_cursor(&mut self, _enabled: bool);

    /// Poll a event from window's event queue.
    fn poll_event(&mut self) -> Option<InputEvent>;
}

/// An implementation of GameWindow that represents running without a window at all
pub struct NoWindow {
    settings: WindowSettings,
    should_close: bool
}

impl NoWindow {
    /// Create a new nonexistant game window
    pub fn new(settings: WindowSettings) -> NoWindow {
         NoWindow {
             settings: settings,
             should_close: false
         }
    }
}

impl Window for NoWindow {
     fn get_settings<'a>(&'a self) -> &'a WindowSettings {
        &self.settings
     }

    fn should_close(&self) -> bool {
        self.should_close
    }

    fn close(&mut self) {
        self.should_close = true
    }

    fn get_size(&self) -> (u32, u32) {
        (0, 0)
    }

    fn get_draw_size(&self) -> (u32, u32) {
        self.get_size()
    }

    fn swap_buffers(&self) {}

    fn capture_cursor(&mut self, _enabled: bool) {}

    fn poll_event(&mut self) -> Option<InputEvent> { None }
}
<|endoftext|>


<commit_before>//
// Copyright 2022 The Project Oak Authors
//
// 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.
//

//! Simple I/O driver for communication between the guest and the host via shared memory.

#![no_std]
extern crate alloc;

use alloc::{collections::VecDeque, vec, vec::Vec};
use core::{marker::PhantomData, result::Result};
use sev_guest::io::{IoPortFactory, PortReader, PortWriter};
use x86_64::instructions::port::{PortReadOnly, PortWriteOnly};

/// The default I/O port to use for the most significant bytes of the output buffer guest-physical
/// address.
pub const DEFAULT_OUTPUT_BUFFER_MSB_PORT: u16 = 0x6421;
/// The default I/O port to use for the least significant bytes of the output buffer guest-physical
/// address.
pub const DEFAULT_OUTPUT_BUFFER_LSB_PORT: u16 = 0x6422;
/// The default I/O port to use for the length of output messages.
pub const DEFAULT_OUTPUT_LENGTH_PORT: u16 = 0x6423;

/// The default I/O port to use for the most significant bytes of the input buffer guest-physical
/// address.
pub const DEFAULT_INPUT_BUFFER_MSB_PORT: u16 = 0x6424;
/// The default I/O port to use for the least significant bytes of the input buffer guest-physical
/// address.
pub const DEFAULT_INPUT_BUFFER_LSB_PORT: u16 = 0x6425;
/// The default I/O port to use for the length of input messages.
pub const DEFAULT_INPUT_LENGTH_PORT: u16 = 0x6426;

/// The length of the buffer that will be used for output messages.
pub const OUTPUT_BUFFER_LEGNTH: usize = 4096;
/// The length of the buffer that will be used for input messages.
pub const INPUT_BUFFER_LEGNTH: usize = 4096;

/// A Simple IO device implementation that uses direct port-based IO.
pub type RawSimpleIo<'a> = SimpleIo<'a, PortReadOnly<u32>, PortWriteOnly<u32>>;

/// The simple I/O channel driver implementation.
pub struct SimpleIo<'a, R: PortReader<u32> + 'a, W: PortWriter<u32> + 'a> {
    output_buffer: Vec<u8>,
    input_buffer: Vec<u8>,
    output_length_port: W,
    input_length_port: R,
    _phantom: PhantomData<&'a W>,
}

impl<'a, R, W> SimpleIo<'a, R, W>
where
    R: PortReader<u32> + 'a,
    W: PortWriter<u32> + 'a,
{
    pub fn new<F: IoPortFactory<'a, u32, R, W>>(
        io_port_factory: F,
        output_buffer_msb_port: u16,
        output_buffer_lsb_port: u16,
        output_length_port: u16,
        input_buffer_msb_port: u16,
        input_buffer_lsb_port: u16,
        input_length_port: u16,
    ) -> Result<Self, &'static str> {
        let output_buffer = vec![0; OUTPUT_BUFFER_LEGNTH];
        let input_buffer = vec![0; INPUT_BUFFER_LEGNTH];
        let output_length_port = io_port_factory.new_writer(output_length_port);
        let input_length_port = io_port_factory.new_reader(input_length_port);

        write_address(
            &io_port_factory,
            output_buffer.as_ptr(),
            output_buffer_msb_port,
            output_buffer_lsb_port,
        )?;
        write_address(
            &io_port_factory,
            input_buffer.as_ptr(),
            input_buffer_msb_port,
            input_buffer_lsb_port,
        )?;

        Ok(Self {
            output_buffer,
            input_buffer,
            output_length_port,
            input_length_port,
            _phantom: PhantomData,
        })
    }

    pub fn new_with_defaults<F: IoPortFactory<'a, u32, R, W>>(
        io_port_factory: F,
    ) -> Result<Self, &'static str> {
        SimpleIo::new(
            io_port_factory,
            DEFAULT_OUTPUT_BUFFER_MSB_PORT,
            DEFAULT_OUTPUT_BUFFER_LSB_PORT,
            DEFAULT_OUTPUT_LENGTH_PORT,
            DEFAULT_INPUT_BUFFER_MSB_PORT,
            DEFAULT_INPUT_BUFFER_LSB_PORT,
            DEFAULT_INPUT_LENGTH_PORT,
        )
    }

    /// Reads the next available bytes from the input buffer, if any are available.
    pub fn read_bytes(&mut self) -> Option<VecDeque<u8>> {
        // Safety: we read the value as a u32 and validate it before using it.
        let length = unsafe { self.input_length_port.try_read().ok()? } as usize;

        // Use a memory fence to ensure the read from the device happens before the read from the
        // buffer.
        core::sync::atomic::fence(core::sync::atomic::Ordering::Acquire);

        if length == 0 {
            return None;
        }

        // A length larger than the buffer size indicates a corrupt or malicious VMM device
        // implementation. This is probably not recoverable, so panic.
        assert!(
            length <= INPUT_BUFFER_LEGNTH,
            "Invalid simple IO input message length."
        );
        let mut result = VecDeque::with_capacity(length);
        result.extend(&self.input_buffer[..length]);

        Some(result)
    }

    /// Writes the data to the output buffer and notifies the host.
    ///
    /// Returns the number of bytes written, if any.
    pub fn write_bytes(&mut self, data: &[u8]) -> Option<usize> {
        if data.is_empty() {
            return None;
        }

        let length = core::cmp::min(OUTPUT_BUFFER_LEGNTH, data.len());
        self.output_buffer[..length].copy_from_slice(&data[..length]);

        // Use a memory fence to ensure that the data is written to the buffer before we notify the
        // VMM.
        core::sync::atomic::fence(core::sync::atomic::Ordering::Release);

        // Safety: this usage is safe, as we as only write an uninterpreted u32 value to the port.
        unsafe {
            self.output_length_port.try_write(length as u32).ok()?;
        }

        Some(length)
    }
}

fn write_address<
    'a,
    R: PortReader<u32> + 'a,
    W: PortWriter<u32> + 'a,
    F: IoPortFactory<'a, u32, R, W>,
>(
    io_port_factory: &F,
    buffer_pointer: *const u8,
    msb_port: u16,
    lsb_port: u16,
) -> Result<(), &'static str> {
    // Split the 64-bit address into its least- and most significant bytes.
    let address = get_guest_physiscal_address(buffer_pointer) as u64;
    let address_msb = (address >> 32) as u32;
    let address_lsb = address as u32;
    // Safety: this usage is safe, as we as only write uninterpreted u32 values to the ports.
    unsafe {
        io_port_factory
            .new_writer(msb_port)
            .try_write(address_msb)?;
        io_port_factory.new_writer(lsb_port).try_write(address_lsb)
    }
}

fn get_guest_physiscal_address(pointer: *const u8) -> usize {
    // Assume identity mapping for now.
    pointer as usize
}
<commit_msg>Distinguish between `VirtAddr` and `PhysAddr` in the simple_io crate.<commit_after>//
// Copyright 2022 The Project Oak Authors
//
// 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.
//

//! Simple I/O driver for communication between the guest and the host via shared memory.

#![no_std]
extern crate alloc;

use alloc::{collections::VecDeque, vec, vec::Vec};
use core::{marker::PhantomData, result::Result};
use sev_guest::io::{IoPortFactory, PortReader, PortWriter};
use x86_64::{
    instructions::port::{PortReadOnly, PortWriteOnly},
    PhysAddr, VirtAddr,
};

/// The default I/O port to use for the most significant bytes of the output buffer guest-physical
/// address.
pub const DEFAULT_OUTPUT_BUFFER_MSB_PORT: u16 = 0x6421;
/// The default I/O port to use for the least significant bytes of the output buffer guest-physical
/// address.
pub const DEFAULT_OUTPUT_BUFFER_LSB_PORT: u16 = 0x6422;
/// The default I/O port to use for the length of output messages.
pub const DEFAULT_OUTPUT_LENGTH_PORT: u16 = 0x6423;

/// The default I/O port to use for the most significant bytes of the input buffer guest-physical
/// address.
pub const DEFAULT_INPUT_BUFFER_MSB_PORT: u16 = 0x6424;
/// The default I/O port to use for the least significant bytes of the input buffer guest-physical
/// address.
pub const DEFAULT_INPUT_BUFFER_LSB_PORT: u16 = 0x6425;
/// The default I/O port to use for the length of input messages.
pub const DEFAULT_INPUT_LENGTH_PORT: u16 = 0x6426;

/// The length of the buffer that will be used for output messages.
pub const OUTPUT_BUFFER_LEGNTH: usize = 4096;
/// The length of the buffer that will be used for input messages.
pub const INPUT_BUFFER_LEGNTH: usize = 4096;

/// A Simple IO device implementation that uses direct port-based IO.
pub type RawSimpleIo<'a> = SimpleIo<'a, PortReadOnly<u32>, PortWriteOnly<u32>>;

/// The simple I/O channel driver implementation.
pub struct SimpleIo<'a, R: PortReader<u32> + 'a, W: PortWriter<u32> + 'a> {
    output_buffer: Vec<u8>,
    input_buffer: Vec<u8>,
    output_length_port: W,
    input_length_port: R,
    _phantom: PhantomData<&'a W>,
}

impl<'a, R, W> SimpleIo<'a, R, W>
where
    R: PortReader<u32> + 'a,
    W: PortWriter<u32> + 'a,
{
    pub fn new<F: IoPortFactory<'a, u32, R, W>>(
        io_port_factory: F,
        output_buffer_msb_port: u16,
        output_buffer_lsb_port: u16,
        output_length_port: u16,
        input_buffer_msb_port: u16,
        input_buffer_lsb_port: u16,
        input_length_port: u16,
    ) -> Result<Self, &'static str> {
        let output_buffer = vec![0; OUTPUT_BUFFER_LEGNTH];
        let input_buffer = vec![0; INPUT_BUFFER_LEGNTH];
        let output_length_port = io_port_factory.new_writer(output_length_port);
        let input_length_port = io_port_factory.new_reader(input_length_port);

        write_address(
            &io_port_factory,
            VirtAddr::from_ptr(output_buffer.as_ptr()),
            output_buffer_msb_port,
            output_buffer_lsb_port,
        )?;
        write_address(
            &io_port_factory,
            VirtAddr::from_ptr(input_buffer.as_ptr()),
            input_buffer_msb_port,
            input_buffer_lsb_port,
        )?;

        Ok(Self {
            output_buffer,
            input_buffer,
            output_length_port,
            input_length_port,
            _phantom: PhantomData,
        })
    }

    pub fn new_with_defaults<F: IoPortFactory<'a, u32, R, W>>(
        io_port_factory: F,
    ) -> Result<Self, &'static str> {
        SimpleIo::new(
            io_port_factory,
            DEFAULT_OUTPUT_BUFFER_MSB_PORT,
            DEFAULT_OUTPUT_BUFFER_LSB_PORT,
            DEFAULT_OUTPUT_LENGTH_PORT,
            DEFAULT_INPUT_BUFFER_MSB_PORT,
            DEFAULT_INPUT_BUFFER_LSB_PORT,
            DEFAULT_INPUT_LENGTH_PORT,
        )
    }

    /// Reads the next available bytes from the input buffer, if any are available.
    pub fn read_bytes(&mut self) -> Option<VecDeque<u8>> {
        // Safety: we read the value as a u32 and validate it before using it.
        let length = unsafe { self.input_length_port.try_read().ok()? } as usize;

        // Use a memory fence to ensure the read from the device happens before the read from the
        // buffer.
        core::sync::atomic::fence(core::sync::atomic::Ordering::Acquire);

        if length == 0 {
            return None;
        }

        // A length larger than the buffer size indicates a corrupt or malicious VMM device
        // implementation. This is probably not recoverable, so panic.
        assert!(
            length <= INPUT_BUFFER_LEGNTH,
            "Invalid simple IO input message length."
        );
        let mut result = VecDeque::with_capacity(length);
        result.extend(&self.input_buffer[..length]);

        Some(result)
    }

    /// Writes the data to the output buffer and notifies the host.
    ///
    /// Returns the number of bytes written, if any.
    pub fn write_bytes(&mut self, data: &[u8]) -> Option<usize> {
        if data.is_empty() {
            return None;
        }

        let length = core::cmp::min(OUTPUT_BUFFER_LEGNTH, data.len());
        self.output_buffer[..length].copy_from_slice(&data[..length]);

        // Use a memory fence to ensure that the data is written to the buffer before we notify the
        // VMM.
        core::sync::atomic::fence(core::sync::atomic::Ordering::Release);

        // Safety: this usage is safe, as we as only write an uninterpreted u32 value to the port.
        unsafe {
            self.output_length_port.try_write(length as u32).ok()?;
        }

        Some(length)
    }
}

fn write_address<
    'a,
    R: PortReader<u32> + 'a,
    W: PortWriter<u32> + 'a,
    F: IoPortFactory<'a, u32, R, W>,
>(
    io_port_factory: &F,
    buffer_pointer: VirtAddr,
    msb_port: u16,
    lsb_port: u16,
) -> Result<(), &'static str> {
    // Split the 64-bit address into its least- and most significant bytes.
    let address = get_guest_physical_address(buffer_pointer).as_u64();
    let address_msb = (address >> 32) as u32;
    let address_lsb = address as u32;
    // Safety: this usage is safe, as we as only write uninterpreted u32 values to the ports.
    unsafe {
        io_port_factory
            .new_writer(msb_port)
            .try_write(address_msb)?;
        io_port_factory.new_writer(lsb_port).try_write(address_lsb)
    }
}

fn get_guest_physical_address(pointer: VirtAddr) -> PhysAddr {
    // Assume identity mapping for now.
    PhysAddr::new(pointer.as_u64())
}
<|endoftext|>


<commit_before>// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0.

use raft::eraftpb::MessageType;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use test_raftstore::*;

// Test if a singleton can apply a log before persisting it.
#[test]
fn test_singleton_cannot_early_apply() {
    let mut cluster = new_node_cluster(0, 1);
    cluster.pd_client.disable_default_operator();
    // So compact log will not be triggered automatically.
    configure_for_request_snapshot(&mut cluster);
    cluster.run();
    // Put one key first to cache leader.
    cluster.must_put(b"k0", b"v0");

    let store_1_fp = "raft_before_save_on_store_1";

    // Check singleton region can be scheduled correctly.
    fail::cfg(store_1_fp, "pause").unwrap();
    cluster.async_put(b"k1", b"v1").unwrap();
    sleep_ms(100);

    must_get_none(&cluster.get_engine(1), b"k1");

    fail::remove(store_1_fp);
    must_get_equal(&cluster.get_engine(1), b"k1", b"v1");
}

#[test]
fn test_multi_early_apply() {
    let mut cluster = new_node_cluster(0, 3);
    cluster.pd_client.disable_default_operator();
    cluster.cfg.raft_store.store_batch_system.pool_size = 1;
    cluster.run_conf_change();
    // Check mixed regions can be scheduled correctly.
    let r1 = cluster.get_region(b"k1");
    cluster.must_split(&r1, b"k2");
    cluster.pd_client.must_add_peer(r1.get_id(), new_peer(2, 2));
    // Put key value to cache leader.
    cluster.must_put(b"k0", b"v0");
    cluster.must_put(b"k3", b"v3");
    must_get_equal(&cluster.get_engine(1), b"k0", b"v0");
    must_get_equal(&cluster.get_engine(1), b"k3", b"v3");

    let store_1_fp = "raft_before_save_on_store_1";

    let executed = AtomicBool::new(false);
    cluster.add_send_filter(CloneFilterFactory(
        RegionPacketFilter::new(1, 1)
            .direction(Direction::Send)
            .msg_type(MessageType::MsgAppend)
            // Just for callback, so never filter.
            .when(Arc::new(AtomicBool::new(false)))
            .set_msg_callback(Arc::new(move |_| {
                if !executed.swap(true, Ordering::SeqCst) {
                    fail::cfg(store_1_fp, "pause").unwrap();
                }
            })),
    ));
    cluster.async_put(b"k4", b"v4").unwrap();
    // Sleep a while so that follower will send append response.
    sleep_ms(100);
    cluster.async_put(b"k11", b"v22").unwrap();
    // Now the store thread of store 1 pauses on `store_1_fp`.
    // Set `store_1_fp` again to make this store thread does not pause on it.
    // Then leader 1 will receive the append response and commit the log.
    fail::cfg(store_1_fp, "pause").unwrap();
    must_get_equal(&cluster.get_engine(1), b"k4", b"v4");
    must_get_none(&cluster.get_engine(1), b"k11");
    fail::remove(store_1_fp);
    must_get_equal(&cluster.get_engine(1), b"k11", b"v22");
}
<commit_msg>test: stablize test_multi_early_apply test (#9259)<commit_after>// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0.

use raft::eraftpb::MessageType;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use test_raftstore::*;

// Test if a singleton can apply a log before persisting it.
#[test]
fn test_singleton_cannot_early_apply() {
    let mut cluster = new_node_cluster(0, 1);
    cluster.pd_client.disable_default_operator();
    // So compact log will not be triggered automatically.
    configure_for_request_snapshot(&mut cluster);

    cluster.run();
    // Put one key first to cache leader.
    cluster.must_put(b"k0", b"v0");

    let store_1_fp = "raft_before_save_on_store_1";

    // Check singleton region can be scheduled correctly.
    fail::cfg(store_1_fp, "pause").unwrap();
    cluster.async_put(b"k1", b"v1").unwrap();
    sleep_ms(100);

    must_get_none(&cluster.get_engine(1), b"k1");

    fail::remove(store_1_fp);
    must_get_equal(&cluster.get_engine(1), b"k1", b"v1");
}

#[test]
fn test_multi_early_apply() {
    let mut cluster = new_node_cluster(0, 3);
    cluster.pd_client.disable_default_operator();
    cluster.cfg.raft_store.store_batch_system.pool_size = 1;
    // So compact log will not be triggered automatically.
    configure_for_request_snapshot(&mut cluster);

    cluster.run_conf_change();
    // Check mixed regions can be scheduled correctly.
    let r1 = cluster.get_region(b"k1");
    cluster.must_split(&r1, b"k2");
    cluster.pd_client.must_add_peer(r1.get_id(), new_peer(2, 2));
    // Put key value to cache leader.
    cluster.must_put(b"k0", b"v0");
    cluster.must_put(b"k3", b"v3");
    must_get_equal(&cluster.get_engine(1), b"k0", b"v0");
    must_get_equal(&cluster.get_engine(1), b"k3", b"v3");

    let store_1_fp = "raft_before_save_on_store_1";

    let executed = AtomicBool::new(false);
    cluster.add_send_filter(CloneFilterFactory(
        RegionPacketFilter::new(1, 1)
            .direction(Direction::Send)
            .msg_type(MessageType::MsgAppend)
            // Just for callback, so never filter.
            .when(Arc::new(AtomicBool::new(false)))
            .set_msg_callback(Arc::new(move |_| {
                if !executed.swap(true, Ordering::SeqCst) {
                    fail::cfg(store_1_fp, "pause").unwrap();
                }
            })),
    ));
    cluster.async_put(b"k4", b"v4").unwrap();
    // Sleep a while so that follower will send append response.
    sleep_ms(100);
    cluster.async_put(b"k11", b"v22").unwrap();
    // Now the store thread of store 1 pauses on `store_1_fp`.
    // Set `store_1_fp` again to make this store thread does not pause on it.
    // Then leader 1 will receive the append response and commit the log.
    fail::cfg(store_1_fp, "pause").unwrap();
    must_get_equal(&cluster.get_engine(1), b"k4", b"v4");
    must_get_none(&cluster.get_engine(1), b"k11");
    fail::remove(store_1_fp);
    must_get_equal(&cluster.get_engine(1), b"k11", b"v22");
}
<|endoftext|>


<commit_before>#![unstable(reason = "not public", issue = "0", feature = "fd")]

use crate::cmp;
use crate::io::{self, Read, Initializer, IoSlice, IoSliceMut};
use crate::mem;
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::cvt;
use crate::sys_common::AsInner;

use libc::{c_int, c_void, ssize_t};

#[derive(Debug)]
pub struct FileDesc {
    fd: c_int,
}

fn max_len() -> usize {
    // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
    // with the man page quoting that if the count of bytes to read is
    // greater than `SSIZE_MAX` the result is "unspecified".
    //
    // On macOS, however, apparently the 64-bit libc is either buggy or
    // intentionally showing odd behavior by rejecting any read with a size
    // larger than or equal to INT_MAX. To handle both of these the read
    // size is capped on both platforms.
    if cfg!(target_os = "macos") {
        <c_int>::max_value() as usize - 1
    } else {
        <ssize_t>::max_value() as usize
    }
}

impl FileDesc {
    pub fn new(fd: c_int) -> FileDesc {
        FileDesc { fd }
    }

    pub fn raw(&self) -> c_int { self.fd }

    /// Extracts the actual file descriptor without closing it.
    pub fn into_raw(self) -> c_int {
        let fd = self.fd;
        mem::forget(self);
        fd
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::read(self.fd,
                       buf.as_mut_ptr() as *mut c_void,
                       cmp::min(buf.len(), max_len()))
        })?;
        Ok(ret as usize)
    }

    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::readv(self.fd,
                        bufs.as_ptr() as *const libc::iovec,
                        cmp::min(bufs.len(), c_int::max_value() as usize) as c_int)
        })?;
        Ok(ret as usize)
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pread64;

        #[cfg(target_os = "emscripten")]
        unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
            -> io::Result<isize>
        {
            use crate::convert::TryInto;
            use libc::pread64;
            // pread64 on emscripten actually takes a 32 bit offset
            if let Ok(o) = offset.try_into() {
                cvt(pread64(fd, buf, count, o))
            } else {
                Err(io::Error::new(io::ErrorKind::InvalidInput,
                                   "cannot pread >2GB"))
            }
        }

        #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
        unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
            -> io::Result<isize>
        {
            #[cfg(target_os = "linux")]
            use libc::pread64;
            #[cfg(not(target_os = "linux"))]
            use libc::pread as pread64;
            cvt(pread64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pread64(self.fd,
                        buf.as_mut_ptr() as *mut c_void,
                        cmp::min(buf.len(), max_len()),
                        offset as i64)
                .map(|n| n as usize)
        }
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::write(self.fd,
                        buf.as_ptr() as *const c_void,
                        cmp::min(buf.len(), max_len()))
        })?;
        Ok(ret as usize)
    }

    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::writev(self.fd,
                         bufs.as_ptr() as *const libc::iovec,
                         cmp::min(bufs.len(), c_int::max_value() as usize) as c_int)
        })?;
        Ok(ret as usize)
    }

    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pwrite64;

        #[cfg(target_os = "emscripten")]
        unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
            -> io::Result<isize>
        {
            use crate::convert::TryInto;
            use libc::pwrite64;
            // pwrite64 on emscripten actually takes a 32 bit offset
            if let Ok(o) = offset.try_into() {
                cvt(pwrite64(fd, buf, count, o))
            } else {
                Err(io::Error::new(io::ErrorKind::InvalidInput,
                                   "cannot pwrite >2GB"))
            }
        }

        #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
        unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
            -> io::Result<isize>
        {
            #[cfg(target_os = "linux")]
            use libc::pwrite64;
            #[cfg(not(target_os = "linux"))]
            use libc::pwrite as pwrite64;
            cvt(pwrite64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pwrite64(self.fd,
                         buf.as_ptr() as *const c_void,
                         cmp::min(buf.len(), max_len()),
                         offset as i64)
                .map(|n| n as usize)
        }
    }

    #[cfg(target_os = "linux")]
    pub fn get_cloexec(&self) -> io::Result<bool> {
        unsafe {
            Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0)
        }
    }

    #[cfg(not(any(target_env = "newlib",
                  target_os = "solaris",
                  target_os = "emscripten",
                  target_os = "fuchsia",
                  target_os = "l4re",
                  target_os = "haiku")))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
            Ok(())
        }
    }
    #[cfg(any(target_env = "newlib",
              target_os = "solaris",
              target_os = "emscripten",
              target_os = "fuchsia",
              target_os = "l4re",
              target_os = "haiku"))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
            let new = previous | libc::FD_CLOEXEC;
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
            }
            Ok(())
        }
    }

    #[cfg(target_os = "linux")]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let v = nonblocking as c_int;
            cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
            Ok(())
        }
    }

    #[cfg(not(target_os = "linux"))]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
            let new = if nonblocking {
                previous | libc::O_NONBLOCK
            } else {
                previous & !libc::O_NONBLOCK
            };
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
            }
            Ok(())
        }
    }

    pub fn duplicate(&self) -> io::Result<FileDesc> {
        // We want to atomically duplicate this file descriptor and set the
        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
        // flag, however, isn't supported on older Linux kernels (earlier than
        // 2.6.24).
        //
        // To detect this and ensure that CLOEXEC is still set, we
        // follow a strategy similar to musl [1] where if passing
        // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
        // supported (the third parameter, 0, is always valid), so we stop
        // trying that.
        //
        // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
        // resolve so we at least compile this.
        //
        // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
        #[cfg(any(target_os = "android", target_os = "haiku"))]
        use libc::F_DUPFD as F_DUPFD_CLOEXEC;
        #[cfg(not(any(target_os = "android", target_os="haiku")))]
        use libc::F_DUPFD_CLOEXEC;

        let make_filedesc = |fd| {
            let fd = FileDesc::new(fd);
            fd.set_cloexec()?;
            Ok(fd)
        };
        static TRY_CLOEXEC: AtomicBool =
            AtomicBool::new(!cfg!(target_os = "android"));
        let fd = self.raw();
        if TRY_CLOEXEC.load(Ordering::Relaxed) {
            match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
                // We *still* call the `set_cloexec` method as apparently some
                // linux kernel at some point stopped setting CLOEXEC even
                // though it reported doing so on F_DUPFD_CLOEXEC.
                Ok(fd) => {
                    return Ok(if cfg!(target_os = "linux") {
                        make_filedesc(fd)?
                    } else {
                        FileDesc::new(fd)
                    })
                }
                Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
                    TRY_CLOEXEC.store(false, Ordering::Relaxed);
                }
                Err(e) => return Err(e),
            }
        }
        cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc)
    }
}

impl<'a> Read for &'a FileDesc {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

impl AsInner<c_int> for FileDesc {
    fn as_inner(&self) -> &c_int { &self.fd }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        // Note that errors are ignored when closing a file descriptor. The
        // reason for this is that if an error occurs we don't actually know if
        // the file descriptor was closed or not, and if we retried (for
        // something like EINTR), we might close another valid file descriptor
        // opened after we closed ours.
        let _ = unsafe { libc::close(self.fd) };
    }
}
<commit_msg>Rollup merge of #62425 - cyphar:linux-cloexec-use-fcntl, r=alexcrichton<commit_after>#![unstable(reason = "not public", issue = "0", feature = "fd")]

use crate::cmp;
use crate::io::{self, Read, Initializer, IoSlice, IoSliceMut};
use crate::mem;
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::cvt;
use crate::sys_common::AsInner;

use libc::{c_int, c_void, ssize_t};

#[derive(Debug)]
pub struct FileDesc {
    fd: c_int,
}

fn max_len() -> usize {
    // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
    // with the man page quoting that if the count of bytes to read is
    // greater than `SSIZE_MAX` the result is "unspecified".
    //
    // On macOS, however, apparently the 64-bit libc is either buggy or
    // intentionally showing odd behavior by rejecting any read with a size
    // larger than or equal to INT_MAX. To handle both of these the read
    // size is capped on both platforms.
    if cfg!(target_os = "macos") {
        <c_int>::max_value() as usize - 1
    } else {
        <ssize_t>::max_value() as usize
    }
}

impl FileDesc {
    pub fn new(fd: c_int) -> FileDesc {
        FileDesc { fd }
    }

    pub fn raw(&self) -> c_int { self.fd }

    /// Extracts the actual file descriptor without closing it.
    pub fn into_raw(self) -> c_int {
        let fd = self.fd;
        mem::forget(self);
        fd
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::read(self.fd,
                       buf.as_mut_ptr() as *mut c_void,
                       cmp::min(buf.len(), max_len()))
        })?;
        Ok(ret as usize)
    }

    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::readv(self.fd,
                        bufs.as_ptr() as *const libc::iovec,
                        cmp::min(bufs.len(), c_int::max_value() as usize) as c_int)
        })?;
        Ok(ret as usize)
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pread64;

        #[cfg(target_os = "emscripten")]
        unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
            -> io::Result<isize>
        {
            use crate::convert::TryInto;
            use libc::pread64;
            // pread64 on emscripten actually takes a 32 bit offset
            if let Ok(o) = offset.try_into() {
                cvt(pread64(fd, buf, count, o))
            } else {
                Err(io::Error::new(io::ErrorKind::InvalidInput,
                                   "cannot pread >2GB"))
            }
        }

        #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
        unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
            -> io::Result<isize>
        {
            #[cfg(target_os = "linux")]
            use libc::pread64;
            #[cfg(not(target_os = "linux"))]
            use libc::pread as pread64;
            cvt(pread64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pread64(self.fd,
                        buf.as_mut_ptr() as *mut c_void,
                        cmp::min(buf.len(), max_len()),
                        offset as i64)
                .map(|n| n as usize)
        }
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::write(self.fd,
                        buf.as_ptr() as *const c_void,
                        cmp::min(buf.len(), max_len()))
        })?;
        Ok(ret as usize)
    }

    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::writev(self.fd,
                         bufs.as_ptr() as *const libc::iovec,
                         cmp::min(bufs.len(), c_int::max_value() as usize) as c_int)
        })?;
        Ok(ret as usize)
    }

    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pwrite64;

        #[cfg(target_os = "emscripten")]
        unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
            -> io::Result<isize>
        {
            use crate::convert::TryInto;
            use libc::pwrite64;
            // pwrite64 on emscripten actually takes a 32 bit offset
            if let Ok(o) = offset.try_into() {
                cvt(pwrite64(fd, buf, count, o))
            } else {
                Err(io::Error::new(io::ErrorKind::InvalidInput,
                                   "cannot pwrite >2GB"))
            }
        }

        #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
        unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
            -> io::Result<isize>
        {
            #[cfg(target_os = "linux")]
            use libc::pwrite64;
            #[cfg(not(target_os = "linux"))]
            use libc::pwrite as pwrite64;
            cvt(pwrite64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pwrite64(self.fd,
                         buf.as_ptr() as *const c_void,
                         cmp::min(buf.len(), max_len()),
                         offset as i64)
                .map(|n| n as usize)
        }
    }

    #[cfg(target_os = "linux")]
    pub fn get_cloexec(&self) -> io::Result<bool> {
        unsafe {
            Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0)
        }
    }

    #[cfg(not(any(target_env = "newlib",
                  target_os = "solaris",
                  target_os = "emscripten",
                  target_os = "fuchsia",
                  target_os = "l4re",
                  target_os = "linux",
                  target_os = "haiku")))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
            Ok(())
        }
    }
    #[cfg(any(target_env = "newlib",
              target_os = "solaris",
              target_os = "emscripten",
              target_os = "fuchsia",
              target_os = "l4re",
              target_os = "linux",
              target_os = "haiku"))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
            let new = previous | libc::FD_CLOEXEC;
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
            }
            Ok(())
        }
    }

    #[cfg(target_os = "linux")]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let v = nonblocking as c_int;
            cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
            Ok(())
        }
    }

    #[cfg(not(target_os = "linux"))]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
            let new = if nonblocking {
                previous | libc::O_NONBLOCK
            } else {
                previous & !libc::O_NONBLOCK
            };
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
            }
            Ok(())
        }
    }

    pub fn duplicate(&self) -> io::Result<FileDesc> {
        // We want to atomically duplicate this file descriptor and set the
        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
        // flag, however, isn't supported on older Linux kernels (earlier than
        // 2.6.24).
        //
        // To detect this and ensure that CLOEXEC is still set, we
        // follow a strategy similar to musl [1] where if passing
        // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
        // supported (the third parameter, 0, is always valid), so we stop
        // trying that.
        //
        // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
        // resolve so we at least compile this.
        //
        // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
        #[cfg(any(target_os = "android", target_os = "haiku"))]
        use libc::F_DUPFD as F_DUPFD_CLOEXEC;
        #[cfg(not(any(target_os = "android", target_os="haiku")))]
        use libc::F_DUPFD_CLOEXEC;

        let make_filedesc = |fd| {
            let fd = FileDesc::new(fd);
            fd.set_cloexec()?;
            Ok(fd)
        };
        static TRY_CLOEXEC: AtomicBool =
            AtomicBool::new(!cfg!(target_os = "android"));
        let fd = self.raw();
        if TRY_CLOEXEC.load(Ordering::Relaxed) {
            match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
                // We *still* call the `set_cloexec` method as apparently some
                // linux kernel at some point stopped setting CLOEXEC even
                // though it reported doing so on F_DUPFD_CLOEXEC.
                Ok(fd) => {
                    return Ok(if cfg!(target_os = "linux") {
                        make_filedesc(fd)?
                    } else {
                        FileDesc::new(fd)
                    })
                }
                Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
                    TRY_CLOEXEC.store(false, Ordering::Relaxed);
                }
                Err(e) => return Err(e),
            }
        }
        cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc)
    }
}

impl<'a> Read for &'a FileDesc {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

impl AsInner<c_int> for FileDesc {
    fn as_inner(&self) -> &c_int { &self.fd }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        // Note that errors are ignored when closing a file descriptor. The
        // reason for this is that if an error occurs we don't actually know if
        // the file descriptor was closed or not, and if we retried (for
        // something like EINTR), we might close another valid file descriptor
        // opened after we closed ours.
        let _ = unsafe { libc::close(self.fd) };
    }
}
<|endoftext|>


<commit_before>use log::info;
use parking_lot::Mutex;
use std::path::*;
use std::str::FromStr;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};

pub mod block;
pub mod index;
pub mod store;

pub use self::block::*;
pub use self::index::Indexer;
pub use self::store::BlockStore;

use crate::asset::{self, Asset, AssetSymbol, Balance, EMPTY_GOLD};
use crate::constants;
use crate::crypto::*;
use crate::script::*;
use crate::tx::*;

pub struct Blockchain {
    indexer: Arc<Indexer>,
    store: Mutex<BlockStore>,
}

#[derive(Clone, Debug)]
pub struct Properties {
    pub height: u64,
    pub token_supply: Balance,
    pub network_fee: Balance,
}

impl Blockchain {
    ///
    /// Creates a new `Blockchain` with an associated indexer and backing
    /// storage is automatically created based on the given `path`.
    ///
    pub fn new(path: &Path) -> Blockchain {
        let indexer = Arc::new(Indexer::new(&Path::join(path, "index")));
        let store = BlockStore::new(&Path::join(path, "blklog"), Arc::clone(&indexer));
        Blockchain {
            indexer,
            store: Mutex::new(store),
        }
    }

    pub fn get_properties(&self) -> Properties {
        Properties {
            height: self.get_chain_height(),
            token_supply: self.indexer.get_token_supply(),
            network_fee: self
                .get_network_fee()
                .expect("unexpected error retrieving network fee"),
        }
    }

    #[inline(always)]
    pub fn get_bond(&self, minter: &PublicKey) -> Option<BondTx> {
        self.indexer.get_bond(minter)
    }

    #[inline(always)]
    pub fn get_chain_height(&self) -> u64 {
        self.indexer.get_chain_height()
    }

    pub fn get_chain_head(&self) -> Arc<SignedBlock> {
        let store = self.store.lock();
        let height = store.get_chain_height();
        store.get(height).expect("Failed to get blockchain head")
    }

    pub fn get_block(&self, height: u64) -> Option<Arc<SignedBlock>> {
        let store = self.store.lock();
        store.get(height)
    }

    pub fn get_total_fee(&self, hash: &ScriptHash) -> Option<Balance> {
        let net_fee = self.get_network_fee()?;
        let addr_fee = self.get_address_fee(hash)?;
        Some(Balance {
            gold: net_fee.gold.add(&addr_fee.gold)?,
            silver: net_fee.silver.add(&addr_fee.silver)?,
        })
    }

    pub fn get_address_fee(&self, hash: &ScriptHash) -> Option<Balance> {
        use crate::constants::*;

        let mut tx_count = 1;
        let head = self.get_chain_height();
        for (delta, i) in (0..=head).rev().enumerate() {
            let block = self.get_block(i).unwrap();
            for tx in &block.transactions {
                let has_match = match tx {
                    TxVariant::RewardTx(_) => false,
                    TxVariant::BondTx(tx) => &tx.staker == hash,
                    TxVariant::TransferTx(tx) => &tx.from == hash,
                };
                if has_match {
                    tx_count += 1;
                }
            }
            if delta + 1 == FEE_RESET_WINDOW {
                break;
            }
        }

        let prec = asset::MAX_PRECISION;
        let gold = GOLD_FEE_MIN.mul(&GOLD_FEE_MULT.pow(tx_count as u16, prec)?, prec)?;
        let silver = SILVER_FEE_MIN.mul(&SILVER_FEE_MULT.pow(tx_count as u16, prec)?, prec)?;
        Some(Balance { gold, silver })
    }

    pub fn get_network_fee(&self) -> Option<Balance> {
        // The network fee adjusts every 5 blocks so that users have a bigger time
        // frame to confirm the fee they want to spend without suddenly changing.
        use crate::constants::*;
        let max_height = self.get_chain_height();
        let max_height = max_height - (max_height % 5);
        let min_height = if max_height > NETWORK_FEE_AVG_WINDOW {
            max_height - NETWORK_FEE_AVG_WINDOW
        } else {
            0
        };

        let mut tx_count: u64 = 1;
        for i in min_height..=max_height {
            tx_count += self.get_block(i).unwrap().transactions.len() as u64;
        }
        if tx_count > u64::from(u16::max_value()) {
            return None;
        }

        let prec = asset::MAX_PRECISION;
        let gold = GOLD_FEE_MIN.mul(&GOLD_FEE_NET_MULT.pow(tx_count as u16, prec)?, prec)?;
        let silver = SILVER_FEE_MIN.mul(&SILVER_FEE_NET_MULT.pow(tx_count as u16, prec)?, prec)?;

        Some(Balance { gold, silver })
    }

    pub fn get_balance(&self, hash: &ScriptHash) -> Balance {
        self.indexer.get_balance(hash).unwrap_or_default()
    }

    pub fn get_balance_with_txs(&self, hash: &ScriptHash, txs: &[TxVariant]) -> Option<Balance> {
        let mut bal = self.indexer.get_balance(hash).unwrap_or_default();
        for tx in txs {
            match tx {
                TxVariant::RewardTx(tx) => {
                    if &tx.to == hash {
                        for reward in &tx.rewards {
                            bal.add(&reward)?;
                        }
                    }
                }
                TxVariant::BondTx(tx) => {
                    if &tx.staker == hash {
                        bal.sub(&tx.fee)?;
                        bal.sub(&tx.bond_fee)?;
                        bal.sub(&tx.stake_amt)?;
                    }
                }
                TxVariant::TransferTx(tx) => {
                    if &tx.from == hash {
                        bal.sub(&tx.fee)?;
                        bal.sub(&tx.amount)?;
                    } else if &tx.to == hash {
                        bal.add(&tx.amount)?;
                    }
                }
            }
        }

        Some(bal)
    }

    pub fn insert_block(&self, block: SignedBlock) -> Result<(), String> {
        self.verify_block(&block, &self.get_chain_head())?;
        for tx in &block.transactions {
            self.index_tx(tx);
        }
        self.store.lock().insert(block);

        Ok(())
    }

    fn verify_block(&self, block: &SignedBlock, prev_block: &SignedBlock) -> Result<(), String> {
        if prev_block.height + 1 != block.height {
            return Err("invalid block height".to_owned());
        } else if !block.verify_tx_merkle_root() {
            return Err("invalid merkle root".to_owned());
        } else if !block.verify_previous_hash(prev_block) {
            return Err("invalid previous hash".to_owned());
        }

        if self.indexer.get_bond(&block.sig_pair.pub_key).is_none() {
            return Err("bond not found".to_owned());
        } else if !block.sig_pair.verify(block.calc_hash().as_ref()) {
            return Err("invalid bond signature".to_owned());
        }

        let len = block.transactions.len();
        for i in 0..len {
            let tx = &block.transactions[i];
            let txs = &block.transactions[0..i];
            if let Err(s) = self.verify_tx(tx, txs) {
                return Err(format!("tx verification failed: {}", s));
            }
        }

        Ok(())
    }

    pub fn verify_tx(&self, tx: &TxVariant, additional_txs: &[TxVariant]) -> Result<(), String> {
        macro_rules! check_amt {
            ($asset:expr, $name:expr) => {
                if $asset.amount < 0 {
                    return Err(format!("{} must be greater than 0", $name));
                }
            };
        }

        macro_rules! check_suf_bal {
            ($asset:expr) => {
                if $asset.amount < 0 {
                    return Err("insufficient balance".to_owned());
                }
            };
        }

        check_amt!(tx.fee, "fee");
        match tx {
            TxVariant::RewardTx(tx) => {
                if !tx.signature_pairs.is_empty() {
                    return Err("reward transaction must not be signed".to_owned());
                }
            }
            TxVariant::BondTx(tx) => {
                if !(tx.bond_fee.symbol == AssetSymbol::GOLD
                    && tx.stake_amt.symbol == AssetSymbol::GOLD
                    && tx.fee.symbol == AssetSymbol::GOLD)
                {
                    return Err("fees and stake amount must be in gold".to_owned());
                }
                check_amt!(&tx.bond_fee, "bond_fee");
                check_amt!(&tx.stake_amt, "stake_amt");

                if tx.bond_fee.lt(&constants::BOND_FEE).unwrap() {
                    return Err("bond_fee is too small".to_owned());
                }

                let mut bal = self
                    .get_balance_with_txs(&tx.staker, additional_txs)
                    .ok_or_else(|| "failed to get balance")?;
                bal.sub(&tx.fee)
                    .ok_or("failed to subtract fee")?
                    .sub(&tx.bond_fee)
                    .ok_or("failed to subtract bond_fee")?
                    .sub(&tx.stake_amt)
                    .ok_or("failed to subtract stake_amt")?;
                check_suf_bal!(bal.gold);

                let pairs = &tx.signature_pairs;
                if pairs.len() != 2 {
                    return Err("must be signed by minter and staker".to_owned());
                }

                let staker: ScriptHash = (&pairs[1].pub_key).into();
                if !(pairs[0].pub_key == tx.minter && staker == tx.staker) {
                    return Err("sigpair minter and staker mismatch".to_owned());
                }
                if !tx.verify_all() {
                    return Err("signature verification failed".to_owned());
                }
            }
            TxVariant::TransferTx(transfer) => {
                if transfer.fee.symbol != transfer.amount.symbol {
                    return Err("symbol mismatch between fee and amount".to_owned());
                } else if transfer.from != ScriptHash::from(&transfer.script) {
                    return Err("from and script hash mismatch".to_owned());
                }

                let success = ScriptEngine::checked_new(tx, &transfer.script)
                    .ok_or_else(|| "failed to initialize script engine")?
                    .eval()
                    .map_err(|e| format!("{}: {:?}", e.pos, e.err))?;
                if !success {
                    return Err("script returned false".to_owned());
                }

                let mut bal = self
                    .get_balance_with_txs(&transfer.from, additional_txs)
                    .ok_or_else(|| "failed to get balance")?;
                bal.sub(&transfer.fee)
                    .ok_or("failed to subtract fee")?
                    .sub(&transfer.amount)
                    .ok_or("failed to subtract amount")?;
                check_suf_bal!(&bal.gold);
                check_suf_bal!(&bal.silver);
            }
        }
        Ok(())
    }

    fn index_tx(&self, tx: &TxVariant) {
        match tx {
            TxVariant::RewardTx(tx) => {
                let mut bal = self.get_balance(&tx.to);
                let mut supply = self.indexer.get_token_supply();
                for r in &tx.rewards {
                    bal.add(r).unwrap();
                    supply.add(r).unwrap();
                }
                self.indexer.set_balance(&tx.to, &bal);
                self.indexer.set_token_supply(&supply);
            }
            TxVariant::BondTx(tx) => {
                let mut bal = self.get_balance(&tx.staker);
                bal.sub(&tx.fee)
                    .unwrap()
                    .sub(&tx.bond_fee)
                    .unwrap()
                    .sub(&tx.stake_amt)
                    .unwrap();
                self.indexer.set_balance(&tx.staker, &bal);
                self.indexer.set_bond(tx);

                let mut supply = self.indexer.get_token_supply();
                supply.sub(&tx.bond_fee).unwrap();
                self.indexer.set_token_supply(&supply);
            }
            TxVariant::TransferTx(tx) => {
                let mut from_bal = self.get_balance(&tx.from);
                let mut to_bal = self.get_balance(&tx.to);

                from_bal.sub(&tx.fee).unwrap().sub(&tx.amount).unwrap();
                to_bal.add(&tx.amount).unwrap();

                self.indexer.set_balance(&tx.from, &from_bal);
                self.indexer.set_balance(&tx.to, &to_bal);
            }
        }
    }

    ///
    /// Create and store a generated genesis block. By default the provided
    /// `minter_key` will be the genesis minter and will stake with a small
    /// amount of GOLD tokens.
    ///
    pub fn create_genesis_block(&self, minter_key: &KeyPair) {
        use sodiumoxide::crypto::hash::sha256::Digest;

        info!("=> Generating new block chain");
        let staker_key = KeyPair::gen_keypair();
        info!("=> Staker private key: {}", staker_key.1.to_wif());
        info!("=> Staker public key: {}", staker_key.0.to_wif());

        let timestamp = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs() as u32;

        let bond_tx = BondTx {
            base: Tx {
                tx_type: TxType::BOND,
                fee: Asset::from_str("0 GOLD").unwrap(),
                timestamp,
                signature_pairs: Vec::new(),
            },
            minter: minter_key.0.clone(),
            staker: staker_key.0.clone().into(),
            bond_fee: EMPTY_GOLD,
            stake_amt: Asset::from_str("1 GOLD").unwrap(),
        };

        let transactions = {
            let mut vec = Vec::with_capacity(2);
            vec.push(TxVariant::RewardTx(RewardTx {
                base: Tx {
                    tx_type: TxType::REWARD,
                    fee: Asset::from_str("0 GOLD").unwrap(),
                    timestamp,
                    signature_pairs: Vec::new(),
                },
                to: staker_key.0.into(),
                rewards: vec![Asset::from_str("1 GOLD").unwrap()],
            }));
            vec.push(TxVariant::BondTx(bond_tx.clone()));
            vec
        };

        let block = (Block {
            height: 0,
            previous_hash: Digest::from_slice(&[0u8; 32]).unwrap(),
            tx_merkle_root: Digest::from_slice(&[0u8; 32]).unwrap(),
            timestamp: timestamp as u32,
            transactions,
        })
        .sign(&minter_key);

        self.store.lock().insert_genesis(block);
        self.indexer.set_bond(&bond_tx);
    }
}
<commit_msg>Divide the tx_count to get an average<commit_after>use log::info;
use parking_lot::Mutex;
use std::path::*;
use std::str::FromStr;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};

pub mod block;
pub mod index;
pub mod store;

pub use self::block::*;
pub use self::index::Indexer;
pub use self::store::BlockStore;

use crate::asset::{self, Asset, AssetSymbol, Balance, EMPTY_GOLD};
use crate::constants;
use crate::crypto::*;
use crate::script::*;
use crate::tx::*;

pub struct Blockchain {
    indexer: Arc<Indexer>,
    store: Mutex<BlockStore>,
}

#[derive(Clone, Debug)]
pub struct Properties {
    pub height: u64,
    pub token_supply: Balance,
    pub network_fee: Balance,
}

impl Blockchain {
    ///
    /// Creates a new `Blockchain` with an associated indexer and backing
    /// storage is automatically created based on the given `path`.
    ///
    pub fn new(path: &Path) -> Blockchain {
        let indexer = Arc::new(Indexer::new(&Path::join(path, "index")));
        let store = BlockStore::new(&Path::join(path, "blklog"), Arc::clone(&indexer));
        Blockchain {
            indexer,
            store: Mutex::new(store),
        }
    }

    pub fn get_properties(&self) -> Properties {
        Properties {
            height: self.get_chain_height(),
            token_supply: self.indexer.get_token_supply(),
            network_fee: self
                .get_network_fee()
                .expect("unexpected error retrieving network fee"),
        }
    }

    #[inline(always)]
    pub fn get_bond(&self, minter: &PublicKey) -> Option<BondTx> {
        self.indexer.get_bond(minter)
    }

    #[inline(always)]
    pub fn get_chain_height(&self) -> u64 {
        self.indexer.get_chain_height()
    }

    pub fn get_chain_head(&self) -> Arc<SignedBlock> {
        let store = self.store.lock();
        let height = store.get_chain_height();
        store.get(height).expect("Failed to get blockchain head")
    }

    pub fn get_block(&self, height: u64) -> Option<Arc<SignedBlock>> {
        let store = self.store.lock();
        store.get(height)
    }

    pub fn get_total_fee(&self, hash: &ScriptHash) -> Option<Balance> {
        let net_fee = self.get_network_fee()?;
        let addr_fee = self.get_address_fee(hash)?;
        Some(Balance {
            gold: net_fee.gold.add(&addr_fee.gold)?,
            silver: net_fee.silver.add(&addr_fee.silver)?,
        })
    }

    pub fn get_address_fee(&self, hash: &ScriptHash) -> Option<Balance> {
        use crate::constants::*;

        let mut tx_count = 1;
        let head = self.get_chain_height();
        for (delta, i) in (0..=head).rev().enumerate() {
            let block = self.get_block(i).unwrap();
            for tx in &block.transactions {
                let has_match = match tx {
                    TxVariant::RewardTx(_) => false,
                    TxVariant::BondTx(tx) => &tx.staker == hash,
                    TxVariant::TransferTx(tx) => &tx.from == hash,
                };
                if has_match {
                    tx_count += 1;
                }
            }
            if delta + 1 == FEE_RESET_WINDOW {
                break;
            }
        }

        let prec = asset::MAX_PRECISION;
        let gold = GOLD_FEE_MIN.mul(&GOLD_FEE_MULT.pow(tx_count as u16, prec)?, prec)?;
        let silver = SILVER_FEE_MIN.mul(&SILVER_FEE_MULT.pow(tx_count as u16, prec)?, prec)?;
        Some(Balance { gold, silver })
    }

    pub fn get_network_fee(&self) -> Option<Balance> {
        // The network fee adjusts every 5 blocks so that users have a bigger time
        // frame to confirm the fee they want to spend without suddenly changing.
        use crate::constants::*;
        let max_height = self.get_chain_height();
        let max_height = max_height - (max_height % 5);
        let min_height = if max_height > NETWORK_FEE_AVG_WINDOW {
            max_height - NETWORK_FEE_AVG_WINDOW
        } else {
            0
        };

        let mut tx_count: u64 = 1;
        for i in min_height..=max_height {
            tx_count += self.get_block(i).unwrap().transactions.len() as u64;
        }
        tx_count /= NETWORK_FEE_AVG_WINDOW;
        if tx_count > u64::from(u16::max_value()) {
            return None;
        }

        let prec = asset::MAX_PRECISION;
        let gold = GOLD_FEE_MIN.mul(&GOLD_FEE_NET_MULT.pow(tx_count as u16, prec)?, prec)?;
        let silver = SILVER_FEE_MIN.mul(&SILVER_FEE_NET_MULT.pow(tx_count as u16, prec)?, prec)?;

        Some(Balance { gold, silver })
    }

    pub fn get_balance(&self, hash: &ScriptHash) -> Balance {
        self.indexer.get_balance(hash).unwrap_or_default()
    }

    pub fn get_balance_with_txs(&self, hash: &ScriptHash, txs: &[TxVariant]) -> Option<Balance> {
        let mut bal = self.indexer.get_balance(hash).unwrap_or_default();
        for tx in txs {
            match tx {
                TxVariant::RewardTx(tx) => {
                    if &tx.to == hash {
                        for reward in &tx.rewards {
                            bal.add(&reward)?;
                        }
                    }
                }
                TxVariant::BondTx(tx) => {
                    if &tx.staker == hash {
                        bal.sub(&tx.fee)?;
                        bal.sub(&tx.bond_fee)?;
                        bal.sub(&tx.stake_amt)?;
                    }
                }
                TxVariant::TransferTx(tx) => {
                    if &tx.from == hash {
                        bal.sub(&tx.fee)?;
                        bal.sub(&tx.amount)?;
                    } else if &tx.to == hash {
                        bal.add(&tx.amount)?;
                    }
                }
            }
        }

        Some(bal)
    }

    pub fn insert_block(&self, block: SignedBlock) -> Result<(), String> {
        self.verify_block(&block, &self.get_chain_head())?;
        for tx in &block.transactions {
            self.index_tx(tx);
        }
        self.store.lock().insert(block);

        Ok(())
    }

    fn verify_block(&self, block: &SignedBlock, prev_block: &SignedBlock) -> Result<(), String> {
        if prev_block.height + 1 != block.height {
            return Err("invalid block height".to_owned());
        } else if !block.verify_tx_merkle_root() {
            return Err("invalid merkle root".to_owned());
        } else if !block.verify_previous_hash(prev_block) {
            return Err("invalid previous hash".to_owned());
        }

        if self.indexer.get_bond(&block.sig_pair.pub_key).is_none() {
            return Err("bond not found".to_owned());
        } else if !block.sig_pair.verify(block.calc_hash().as_ref()) {
            return Err("invalid bond signature".to_owned());
        }

        let len = block.transactions.len();
        for i in 0..len {
            let tx = &block.transactions[i];
            let txs = &block.transactions[0..i];
            if let Err(s) = self.verify_tx(tx, txs) {
                return Err(format!("tx verification failed: {}", s));
            }
        }

        Ok(())
    }

    pub fn verify_tx(&self, tx: &TxVariant, additional_txs: &[TxVariant]) -> Result<(), String> {
        macro_rules! check_amt {
            ($asset:expr, $name:expr) => {
                if $asset.amount < 0 {
                    return Err(format!("{} must be greater than 0", $name));
                }
            };
        }

        macro_rules! check_suf_bal {
            ($asset:expr) => {
                if $asset.amount < 0 {
                    return Err("insufficient balance".to_owned());
                }
            };
        }

        check_amt!(tx.fee, "fee");
        match tx {
            TxVariant::RewardTx(tx) => {
                if !tx.signature_pairs.is_empty() {
                    return Err("reward transaction must not be signed".to_owned());
                }
            }
            TxVariant::BondTx(tx) => {
                if !(tx.bond_fee.symbol == AssetSymbol::GOLD
                    && tx.stake_amt.symbol == AssetSymbol::GOLD
                    && tx.fee.symbol == AssetSymbol::GOLD)
                {
                    return Err("fees and stake amount must be in gold".to_owned());
                }
                check_amt!(&tx.bond_fee, "bond_fee");
                check_amt!(&tx.stake_amt, "stake_amt");

                if tx.bond_fee.lt(&constants::BOND_FEE).unwrap() {
                    return Err("bond_fee is too small".to_owned());
                }

                let mut bal = self
                    .get_balance_with_txs(&tx.staker, additional_txs)
                    .ok_or_else(|| "failed to get balance")?;
                bal.sub(&tx.fee)
                    .ok_or("failed to subtract fee")?
                    .sub(&tx.bond_fee)
                    .ok_or("failed to subtract bond_fee")?
                    .sub(&tx.stake_amt)
                    .ok_or("failed to subtract stake_amt")?;
                check_suf_bal!(bal.gold);

                let pairs = &tx.signature_pairs;
                if pairs.len() != 2 {
                    return Err("must be signed by minter and staker".to_owned());
                }

                let staker: ScriptHash = (&pairs[1].pub_key).into();
                if !(pairs[0].pub_key == tx.minter && staker == tx.staker) {
                    return Err("sigpair minter and staker mismatch".to_owned());
                }
                if !tx.verify_all() {
                    return Err("signature verification failed".to_owned());
                }
            }
            TxVariant::TransferTx(transfer) => {
                if transfer.fee.symbol != transfer.amount.symbol {
                    return Err("symbol mismatch between fee and amount".to_owned());
                } else if transfer.from != ScriptHash::from(&transfer.script) {
                    return Err("from and script hash mismatch".to_owned());
                }

                let success = ScriptEngine::checked_new(tx, &transfer.script)
                    .ok_or_else(|| "failed to initialize script engine")?
                    .eval()
                    .map_err(|e| format!("{}: {:?}", e.pos, e.err))?;
                if !success {
                    return Err("script returned false".to_owned());
                }

                let mut bal = self
                    .get_balance_with_txs(&transfer.from, additional_txs)
                    .ok_or_else(|| "failed to get balance")?;
                bal.sub(&transfer.fee)
                    .ok_or("failed to subtract fee")?
                    .sub(&transfer.amount)
                    .ok_or("failed to subtract amount")?;
                check_suf_bal!(&bal.gold);
                check_suf_bal!(&bal.silver);
            }
        }
        Ok(())
    }

    fn index_tx(&self, tx: &TxVariant) {
        match tx {
            TxVariant::RewardTx(tx) => {
                let mut bal = self.get_balance(&tx.to);
                let mut supply = self.indexer.get_token_supply();
                for r in &tx.rewards {
                    bal.add(r).unwrap();
                    supply.add(r).unwrap();
                }
                self.indexer.set_balance(&tx.to, &bal);
                self.indexer.set_token_supply(&supply);
            }
            TxVariant::BondTx(tx) => {
                let mut bal = self.get_balance(&tx.staker);
                bal.sub(&tx.fee)
                    .unwrap()
                    .sub(&tx.bond_fee)
                    .unwrap()
                    .sub(&tx.stake_amt)
                    .unwrap();
                self.indexer.set_balance(&tx.staker, &bal);
                self.indexer.set_bond(tx);

                let mut supply = self.indexer.get_token_supply();
                supply.sub(&tx.bond_fee).unwrap();
                self.indexer.set_token_supply(&supply);
            }
            TxVariant::TransferTx(tx) => {
                let mut from_bal = self.get_balance(&tx.from);
                let mut to_bal = self.get_balance(&tx.to);

                from_bal.sub(&tx.fee).unwrap().sub(&tx.amount).unwrap();
                to_bal.add(&tx.amount).unwrap();

                self.indexer.set_balance(&tx.from, &from_bal);
                self.indexer.set_balance(&tx.to, &to_bal);
            }
        }
    }

    ///
    /// Create and store a generated genesis block. By default the provided
    /// `minter_key` will be the genesis minter and will stake with a small
    /// amount of GOLD tokens.
    ///
    pub fn create_genesis_block(&self, minter_key: &KeyPair) {
        use sodiumoxide::crypto::hash::sha256::Digest;

        info!("=> Generating new block chain");
        let staker_key = KeyPair::gen_keypair();
        info!("=> Staker private key: {}", staker_key.1.to_wif());
        info!("=> Staker public key: {}", staker_key.0.to_wif());

        let timestamp = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs() as u32;

        let bond_tx = BondTx {
            base: Tx {
                tx_type: TxType::BOND,
                fee: Asset::from_str("0 GOLD").unwrap(),
                timestamp,
                signature_pairs: Vec::new(),
            },
            minter: minter_key.0.clone(),
            staker: staker_key.0.clone().into(),
            bond_fee: EMPTY_GOLD,
            stake_amt: Asset::from_str("1 GOLD").unwrap(),
        };

        let transactions = {
            let mut vec = Vec::with_capacity(2);
            vec.push(TxVariant::RewardTx(RewardTx {
                base: Tx {
                    tx_type: TxType::REWARD,
                    fee: Asset::from_str("0 GOLD").unwrap(),
                    timestamp,
                    signature_pairs: Vec::new(),
                },
                to: staker_key.0.into(),
                rewards: vec![Asset::from_str("1 GOLD").unwrap()],
            }));
            vec.push(TxVariant::BondTx(bond_tx.clone()));
            vec
        };

        let block = (Block {
            height: 0,
            previous_hash: Digest::from_slice(&[0u8; 32]).unwrap(),
            tx_merkle_root: Digest::from_slice(&[0u8; 32]).unwrap(),
            timestamp: timestamp as u32,
            transactions,
        })
        .sign(&minter_key);

        self.store.lock().insert_genesis(block);
        self.indexer.set_bond(&bond_tx);
    }
}
<|endoftext|>


<commit_before>use crate::platform::*;
use crate::types::*;
use crate::winrust::hstring::*;
use crate::winrust::*;
use std::fmt;
use std::{convert::TryFrom, io};

pub struct LanguageData {
    pub tag: String,
    pub name: String,
    pub english_name: String,
    pub localised_name: String,
    pub script_name: String,
}

impl fmt::Display for LanguageData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "Tag:           {}", self.tag)?;
        writeln!(f, "Name:          {}", self.name)?;
        writeln!(f, "English Name:  {}", self.english_name)?;
        writeln!(f, "Native Name:   {}", self.localised_name)?;
        writeln!(f, "Script:        {}", self.script_name)?;

        Ok(())
    }
}

pub fn get_language_names(tag: &str) -> Option<LanguageData> {
    log::debug!("get_language_names({:?})", &tag);
    let mut a = [0u16; 256];
    let mut b = [0u16; 256];
    let mut c = [0u16; 256];
    let mut d = [0u16; 256];

    let ret = unsafe {
        sys::winlangdb::GetLanguageNames(
            to_wide_string(tag).as_ptr(),
            a.as_mut_ptr(),
            b.as_mut_ptr(),
            c.as_mut_ptr(),
            d.as_mut_ptr(),
        )
    };

    if ret != 0 {
        log::error!(
            "Error getting language names: {:?}",
            io::Error::last_os_error()
        );
        return None;
    }

    Some(LanguageData {
        tag: tag.to_owned(),
        name: from_wide_string(&a).unwrap(),
        english_name: from_wide_string(&b).unwrap(),
        localised_name: from_wide_string(&c).unwrap(),
        script_name: from_wide_string(&d).unwrap(),
    })
}

pub fn set_user_languages(tags: &[String]) -> Result<(), io::Error> {
    log::debug!("set_user_languages({:?})", tags);
    let joined = format!("{}", tags.join(":"));
    log::trace!("Joined: {:?}", &joined);
    let handle = HString::from(joined);
    // let semi = ";".encode_utf16().collect::<Vec<_>>()[0];
    let ret = unsafe { sys::winlangdb::SetUserLanguages(':' as u16, *handle) };

    if ret != 0 {
        let err = io::Error::last_os_error();
        log::error!("Error setting user languages: {:?}", err);

        return Err(err);
    }

    Ok(())
}

pub fn transform_input_methods(methods: InputList, tag: &str) -> InputList {
    let hmethods = HString::from(String::from(methods));
    let htag = HString::from(tag);
    let out = unsafe {
        let mut out = HString::null();
        sys::winlangdb::TransformInputMethodsForLanguage(*hmethods, *htag, &mut *out);
        out
    };
    InputList::try_from(String::from(out)).unwrap()
}

pub fn default_input_method(tag: &str) -> InputList {
    let htag = HString::from(tag);
    let out = unsafe {
        let mut out = HString::null();
        sys::winlangdb::GetDefaultInputMethodForLanguage(*htag, &mut *out);
        out
    };
    InputList::try_from(String::from(out)).unwrap()
}
<commit_msg>Commit my masterpiece<commit_after>use crate::platform::*;
use crate::types::*;
use crate::winrust::hstring::*;
use crate::winrust::*;
use std::fmt;
use std::{convert::TryFrom, io};

pub struct LanguageData {
    pub tag: String,
    pub name: String,
    pub english_name: String,
    pub localised_name: String,
    pub script_name: String,
}

impl fmt::Display for LanguageData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "Tag:           {}", self.tag)?;
        writeln!(f, "Name:          {}", self.name)?;
        writeln!(f, "English Name:  {}", self.english_name)?;
        writeln!(f, "Native Name:   {}", self.localised_name)?;
        writeln!(f, "Script:        {}", self.script_name)?;

        Ok(())
    }
}

pub fn get_language_names(tag: &str) -> Option<LanguageData> {
    log::debug!("get_language_names({:?})", &tag);
    let mut a = [0u16; 256];
    let mut b = [0u16; 256];
    let mut c = [0u16; 256];
    let mut d = [0u16; 256];

    let ret = unsafe {
        sys::winlangdb::GetLanguageNames(
            to_wide_string(tag).as_ptr(),
            a.as_mut_ptr(),
            b.as_mut_ptr(),
            c.as_mut_ptr(),
            d.as_mut_ptr(),
        )
    };

    if ret != 0 {
        log::error!(
            "Error getting language names: {:?}",
            io::Error::last_os_error()
        );
        return None;
    }

    Some(LanguageData {
        tag: tag.to_owned(),
        name: from_wide_string(&a).unwrap(),
        english_name: from_wide_string(&b).unwrap(),
        localised_name: from_wide_string(&c).unwrap(),
        script_name: from_wide_string(&d).unwrap(),
    })
}

pub fn set_user_languages(tags: &[String]) -> Result<(), io::Error> {
    if tags.is_empty() {
        panic!("Tags must not be empty");
    }

    log::debug!("set_user_languages({:?})", tags);

    // We duplicate the first item because 32-bit binaries on 64-bit Windows fail to set the first item.
    // DO NOT REMOVE WITHOUT SETTING ASIDE TWO DAYS TO REALISE YOU HAVE MADE A HORRIBLE ERROR.
    let joined = format!("{};{}", &tags[0], tags.join(";"));
    log::trace!("Joined: {:?}", &joined);
    let handle = HString::from(joined);
    let ret = unsafe { sys::winlangdb::SetUserLanguages(';' as u16, *handle) };

    if ret != 0 {
        let err = io::Error::last_os_error();
        log::error!("Error setting user languages: {:?}", err);

        return Err(err);
    }

    Ok(())
}

pub fn transform_input_methods(methods: InputList, tag: &str) -> InputList {
    let hmethods = HString::from(String::from(methods));
    let htag = HString::from(tag);
    let out = unsafe {
        let mut out = HString::null();
        sys::winlangdb::TransformInputMethodsForLanguage(*hmethods, *htag, &mut *out);
        out
    };
    InputList::try_from(String::from(out)).unwrap()
}

pub fn default_input_method(tag: &str) -> InputList {
    let htag = HString::from(tag);
    let out = unsafe {
        let mut out = HString::null();
        sys::winlangdb::GetDefaultInputMethodForLanguage(*htag, &mut *out);
        out
    };
    InputList::try_from(String::from(out)).unwrap()
}
<|endoftext|>


<commit_before>use super::*;

// TODO: Define these.
struct user;
struct tracks;
struct playlist;

// Copy comments from spotify docs here.
pub trait Callbacks<T> {
    fn tracks_added(pl: &playlist, track: &tracks, num_tracks: isize, position: isize, userdata: &T);
    fn tracks_removed(pl: &playlist, tracks: &isize, num_tracks: isize, userdata: &T);
    fn tracks_moved(pl: &playlist, tracks: [isize], num_tracks: isize, new_position: isize, userdata: &T);
    fn playlist_renamed(pl: &playlist, userdata: &T);
    fn playlist_state_changed(pl: &playlist, userdata: &T);
    fn playlist_update_in_progress(pl: &playlist, done: bool, userdata: &T);
    fn playlist_metadata_updated(pl: &playlist, userdata: &T);
    fn track_created_changed(pl: &playlist, position: isize, user: &user, when: isize, userdata: &T);
    fn track_seen_changed(pl: &playlist, position: isize, seen: bool, userdata: &T);
    fn description_changed(pl: &playlist, desc: &str, userdata: &T);
    fn image_changed(pl: &playlist, image: [u8], userdata: &T);
    fn track_message_changed(pl: &playlist, position: isize,  message: &str, userdata: &T);
    fn subscribers_changed(pl: &playlist, userdata: &T);
}
<commit_msg>Added documentation for playlist_callback<commit_after>use super::*;

// TODO: Define these.
struct user;
struct tracks;
struct playlist;

/// Playlist callbacks
///
/// Used to get notifications when playlists are updated. If some callbacks should not be of
/// interest, set them to NULL.
pub trait Callbacks<T> {

    /// Called when one or more tracks have been added to a playlist
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    tracks      Array of pointers to track objects
    ///     [in]    num_tracks  Number of entries in tracks
    ///     [in]    position    Position in the playlist for the first track.
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn tracks_added(pl: &playlist, track: &tracks, num_tracks: isize, position: isize, userdata: &T);

    /// Called when one or more tracks have been removed from a playlist
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    tracks      Array of positions representing the tracks that were removed
    ///     [in]    num_tracks  Number of entries in tracks
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn tracks_removed(pl: &playlist, tracks: &isize, num_tracks: isize, userdata: &T);

    /// Called when one or more tracks have been moved within a playlist
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    tracks      Array of positions representing the tracks that were moved
    ///     [in]    num_tracks  Number of entries in tracks
    ///     [in]    position    New position in the playlist for the first track.
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn tracks_moved(pl: &playlist, tracks: [isize], num_tracks: isize, new_position: isize, userdata: &T);

    /// Called when a playlist has been renamed. sp_playlist_name() can be used to find out the new name
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    userdata    Userdata passed to laylist_add_callbacks()
    fn playlist_renamed(pl: &playlist, userdata: &T);

    /// Called when state changed for a playlist.
    ///
    /// There are three states that trigger this callback:
    ///
    ///  - Collaboration for this playlist has been turned on or off
    ///  - The playlist started having pending changes, or all pending changes have now been committed
    ///  - The playlist started loading, or finished loading
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn playlist_state_changed(pl: &playlist, userdata: &T);

    /// Called when a playlist is updating or is done updating
    ///
    /// This is called before and after a series of changes are applied to the playlist. It allows
    /// e.g. the user interface to defer updating until the entire operation is complete.
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    done        True iff the update is completed
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn playlist_update_in_progress(pl: &playlist, done: bool, userdata: &T);

    /// Called when metadata for one or more tracks in a playlist has been updated.
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn playlist_metadata_updated(pl: &playlist, userdata: &T);

    /// Called when create time and/or creator for a playlist entry changes
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    position    Position in playlist
    ///     [in]    user        User object
    ///     [in]    time        When entry was created, seconds since the unix epoch.
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn track_created_changed(pl: &playlist, position: isize, user: &user, when: isize, userdata: &T);

    /// Called when seen attribute for a playlist entry changes.
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    position    Position in playlist
    ///     [in]    seen        Set if entry it marked as seen
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn track_seen_changed(pl: &playlist, position: isize, seen: bool, userdata: &T);

    /// Called when playlist description has changed
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    desc        New description
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn description_changed(pl: &playlist, desc: &str, userdata: &T);

    /// Called when playlist image has changed
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    image       New image
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn image_changed(pl: &playlist, image: [u8], userdata: &T);

    /// Called when message attribute for a playlist entry changes.
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    position    Position in playlist
    ///     [in]    message     UTF-8 encoded message
    ///     [in]    userdata    Userdata passed to playlist_add_callbacks()
    fn track_message_changed(pl: &playlist, position: isize,  message: &str, userdata: &T);

    /// Called when playlist subscribers changes (count or list of names)
    ///
    /// Parameters:
    ///     [in]    pl          Playlist object
    ///     [in]    userdata    Userdata passed to sp_playlist_add_callbacks()
    fn subscribers_changed(pl: &playlist, userdata: &T);
}
<|endoftext|>


<commit_before>use std::sync::atomic::{AtomicPtr, Ordering};
use std::ptr;

unsafe impl<T: Send> Send for AtomicOption<T> {}
unsafe impl<T: Send> Sync for AtomicOption<T> {}

#[derive(Debug)]
pub struct AtomicOption<T> {
    inner: AtomicPtr<T>,
}

impl<T> AtomicOption<T> {
    pub fn new() -> AtomicOption<T> {
        AtomicOption { inner: AtomicPtr::new(ptr::null_mut()) }
    }

    fn swap_inner(&self, ptr: *mut T, order: Ordering) -> Option<Box<T>> {
        let old = self.inner.swap(ptr, order);
        if old.is_null() {
            None
        } else {
            Some(unsafe { Box::from_raw(old) })
        }
    }

    // allows re-use of allocation
    pub fn swap_box(&self, t: Box<T>, order: Ordering) -> Option<Box<T>> {
        self.swap_inner(Box::into_raw(t), order)
    }

    pub fn swap(&self, t: T, order: Ordering) -> Option<T> {
        self.swap_box(Box::new(t), order).map(|old| *old)
    }

    pub fn take(&self, order: Ordering) -> Option<T> {
        self.swap_inner(ptr::null_mut(), order).map(|old| *old)
    }
}
<commit_msg>Fix memory leak in AtomicOption. Closes #142.<commit_after>use std::sync::atomic::{AtomicPtr, Ordering};
use std::ptr;

unsafe impl<T: Send> Send for AtomicOption<T> {}
unsafe impl<T: Send> Sync for AtomicOption<T> {}

#[derive(Debug)]
pub struct AtomicOption<T> {
    inner: AtomicPtr<T>,
}

impl<T> Drop for AtomicOption<T> {
    fn drop(&mut self) {
        let inner = self.inner.load(Ordering::Relaxed);
        if !inner.is_null() {
            unsafe {
                Box::from_raw(inner);
            }
        }
    }
}

impl<T> AtomicOption<T> {
    pub fn new() -> AtomicOption<T> {
        AtomicOption { inner: AtomicPtr::new(ptr::null_mut()) }
    }

    fn swap_inner(&self, ptr: *mut T, order: Ordering) -> Option<Box<T>> {
        let old = self.inner.swap(ptr, order);
        if old.is_null() {
            None
        } else {
            Some(unsafe { Box::from_raw(old) })
        }
    }

    // allows re-use of allocation
    pub fn swap_box(&self, t: Box<T>, order: Ordering) -> Option<Box<T>> {
        self.swap_inner(Box::into_raw(t), order)
    }

    pub fn swap(&self, t: T, order: Ordering) -> Option<T> {
        self.swap_box(Box::new(t), order).map(|old| *old)
    }

    pub fn take(&self, order: Ordering) -> Option<T> {
        self.swap_inner(ptr::null_mut(), order).map(|old| *old)
    }
}
<|endoftext|>


<commit_before>use std::{io::Read, net::SocketAddr};

use conduit::{Method, Request};
use conduit_hyper::semver;

type RequestMutRef<'a> = &'a mut (dyn Request + 'a);

// Can't derive Debug because of Request.
#[allow(missing_debug_implementations)]
pub struct RequestProxy<'a> {
    other: RequestMutRef<'a>,
    path: Option<&'a str>,
    method: Option<conduit::Method>,
}

impl<'a> RequestProxy<'a> {
    pub(crate) fn rewrite_path(req: RequestMutRef<'a>, path: &'a str) -> Self {
        RequestProxy {
            other: req,
            path: Some(path),
            method: None, // Defer to original request
        }
    }

    pub(crate) fn rewrite_method(req: RequestMutRef<'a>, method: Method) -> Self {
        RequestProxy {
            other: req,
            path: None, // Defer to original request
            method: Some(method),
        }
    }
}

impl<'a> Request for RequestProxy<'a> {
    // Use local value if available, defer to the original request
    fn method(&self) -> conduit::Method {
        self.method.clone().unwrap_or_else(|| self.other.method())
    }

    fn path(&self) -> &str {
        self.path.unwrap_or_else(|| self.other.path())
    }

    // Pass-through
    fn http_version(&self) -> semver::Version {
        self.other.http_version()
    }
    fn conduit_version(&self) -> semver::Version {
        self.other.conduit_version()
    }
    fn scheme(&self) -> conduit::Scheme {
        self.other.scheme()
    }
    fn host(&self) -> conduit::Host<'_> {
        self.other.host()
    }
    fn virtual_root(&self) -> Option<&str> {
        self.other.virtual_root()
    }
    fn query_string(&self) -> Option<&str> {
        self.other.query_string()
    }
    fn remote_addr(&self) -> SocketAddr {
        self.other.remote_addr()
    }
    fn content_length(&self) -> Option<u64> {
        self.other.content_length()
    }
    fn headers(&self) -> &dyn conduit::Headers {
        self.other.headers()
    }
    fn body(&mut self) -> &mut dyn Read {
        self.other.body()
    }
    fn extensions(&self) -> &conduit::Extensions {
        self.other.extensions()
    }
    fn mut_extensions(&mut self) -> &mut conduit::Extensions {
        self.other.mut_extensions()
    }
}
<commit_msg>Add some docs for RequestProxy<commit_after>//! A helper that wraps a request and can overwrite either the path or the method.

use std::{io::Read, net::SocketAddr};

use conduit::{Method, Request};
use conduit_hyper::semver;

type RequestMutRef<'a> = &'a mut (dyn Request + 'a);

// Can't derive Debug because of Request.
#[allow(missing_debug_implementations)]
pub struct RequestProxy<'a> {
    other: RequestMutRef<'a>,
    path: Option<&'a str>,
    method: Option<conduit::Method>,
}

impl<'a> RequestProxy<'a> {
    /// Wrap a request and overwrite the path with the provided value.
    pub(crate) fn rewrite_path(req: RequestMutRef<'a>, path: &'a str) -> Self {
        RequestProxy {
            other: req,
            path: Some(path),
            method: None, // Defer to original request
        }
    }

    /// Wrap a request and overwrite the method with the provided value.
    pub(crate) fn rewrite_method(req: RequestMutRef<'a>, method: Method) -> Self {
        RequestProxy {
            other: req,
            path: None, // Defer to original request
            method: Some(method),
        }
    }
}

impl<'a> Request for RequestProxy<'a> {
    // Use local value if available, defer to the original request
    fn method(&self) -> conduit::Method {
        self.method.clone().unwrap_or_else(|| self.other.method())
    }

    fn path(&self) -> &str {
        self.path.unwrap_or_else(|| self.other.path())
    }

    // Pass-through
    fn http_version(&self) -> semver::Version {
        self.other.http_version()
    }
    fn conduit_version(&self) -> semver::Version {
        self.other.conduit_version()
    }
    fn scheme(&self) -> conduit::Scheme {
        self.other.scheme()
    }
    fn host(&self) -> conduit::Host<'_> {
        self.other.host()
    }
    fn virtual_root(&self) -> Option<&str> {
        self.other.virtual_root()
    }
    fn query_string(&self) -> Option<&str> {
        self.other.query_string()
    }
    fn remote_addr(&self) -> SocketAddr {
        self.other.remote_addr()
    }
    fn content_length(&self) -> Option<u64> {
        self.other.content_length()
    }
    fn headers(&self) -> &dyn conduit::Headers {
        self.other.headers()
    }
    fn body(&mut self) -> &mut dyn Read {
        self.other.body()
    }
    fn extensions(&self) -> &conduit::Extensions {
        self.other.extensions()
    }
    fn mut_extensions(&mut self) -> &mut conduit::Extensions {
        self.other.mut_extensions()
    }
}
<|endoftext|>