<commit_before>use core::{cmp, slice};
use ransid::{Console, Event};
use spin::Mutex;

use memory::Frame;
use paging::{ActivePageTable, PhysicalAddress, entry};

#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) {
    asm!("cld
        rep movsq"
        :
        : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
        : "cc", "memory"
        : "intel", "volatile");
}

#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
unsafe fn fast_set(dst: *mut u32, src: u32, len: usize) {
    asm!("cld
        rep stosd"
        :
        : "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len)
        : "cc", "memory"
        : "intel", "volatile");
}

#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) {
    asm!("cld
        rep stosq"
        :
        : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len)
        : "cc", "memory"
        : "intel", "volatile");
}

/// The info of the VBE mode
#[derive(Copy, Clone, Default, Debug)]
#[repr(packed)]
pub struct VBEModeInfo {
    attributes: u16,
    win_a: u8,
    win_b: u8,
    granularity: u16,
    winsize: u16,
    segment_a: u16,
    segment_b: u16,
    winfuncptr: u32,
    bytesperscanline: u16,
    pub xresolution: u16,
    pub yresolution: u16,
    xcharsize: u8,
    ycharsize: u8,
    numberofplanes: u8,
    bitsperpixel: u8,
    numberofbanks: u8,
    memorymodel: u8,
    banksize: u8,
    numberofimagepages: u8,
    unused: u8,
    redmasksize: u8,
    redfieldposition: u8,
    greenmasksize: u8,
    greenfieldposition: u8,
    bluemasksize: u8,
    bluefieldposition: u8,
    rsvdmasksize: u8,
    rsvdfieldposition: u8,
    directcolormodeinfo: u8,
    physbaseptr: u32,
    offscreenmemoryoffset: u32,
    offscreenmemsize: u16,
}

pub static CONSOLE: Mutex<Option<Console>> = Mutex::new(None);

pub static DISPLAY: Mutex<Option<Display>> = Mutex::new(None);

static FONT: &'static [u8] = include_bytes!("../../../../res/unifont.font");

pub unsafe fn init(active_table: &mut ActivePageTable) {
    active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);

    let mode_info = &*(0x5200 as *const VBEModeInfo);
    if mode_info.physbaseptr > 0 {
        let width = mode_info.xresolution as usize;
        let height = mode_info.yresolution as usize;
        let onscreen = mode_info.physbaseptr as usize;
        let size = width * height;

        {
            let start_frame = Frame::containing_address(PhysicalAddress::new(onscreen));
            let end_frame = Frame::containing_address(PhysicalAddress::new(onscreen + size * 4 - 1));
            for frame in Frame::range_inclusive(start_frame, end_frame) {
                active_table.identity_map(frame, /*actually sets PAT for write combining*/ entry::HUGE_PAGE | entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
            }
        }

        fast_set64(onscreen as *mut u64, 0, size/2);

        let offscreen = ::allocator::__rust_allocate(size * 4, 8);
        fast_set64(offscreen as *mut u64, 0, size/2);

        *CONSOLE.lock() = Some(Console::new(width/8, height/16));
        *DISPLAY.lock() = Some(Display::new(width, height,
            slice::from_raw_parts_mut(onscreen as *mut u32, size),
            slice::from_raw_parts_mut(offscreen as *mut u32, size)
        ));
    }
}

pub unsafe fn init_ap(active_table: &mut ActivePageTable) {
    active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);

    let mode_info = &*(0x5200 as *const VBEModeInfo);
    if mode_info.physbaseptr > 0 {
        let width = mode_info.xresolution as usize;
        let height = mode_info.yresolution as usize;
        let start = mode_info.physbaseptr as usize;
        let size = width * height;

        {
            let start_frame = Frame::containing_address(PhysicalAddress::new(start));
            let end_frame = Frame::containing_address(PhysicalAddress::new(start + size * 4 - 1));
            for frame in Frame::range_inclusive(start_frame, end_frame) {
                active_table.identity_map(frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
            }
        }
    }
}

/// A display
pub struct Display {
    pub width: usize,
    pub height: usize,
    pub onscreen: &'static mut [u32],
    pub offscreen: &'static mut [u32],
}

impl Display {
    fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display {
        Display {
            width: width,
            height: height,
            onscreen: onscreen,
            offscreen: offscreen,
        }
    }

    /// Draw a rectangle
    fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
        let start_y = cmp::min(self.height - 1, y);
        let end_y = cmp::min(self.height, y + h);

        let start_x = cmp::min(self.width - 1, x);
        let len = cmp::min(self.width, x + w) - start_x;

        let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
        let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;

        let stride = self.width * 4;

        let offset = y * stride + start_x * 4;
        offscreen_ptr += offset;
        onscreen_ptr += offset;

        let mut rows = end_y - start_y;
        while rows > 0 {
            unsafe {
                fast_set(offscreen_ptr as *mut u32, color, len);
                fast_set(onscreen_ptr as *mut u32, color, len);
            }
            offscreen_ptr += stride;
            onscreen_ptr += stride;
            rows -= 1;
        }
    }

    /// Draw a character
    fn char(&mut self, x: usize, y: usize, character: char, color: u32) {
        if x + 8 <= self.width && y + 16 <= self.height {
            let mut font_i = 16 * (character as usize);
            let font_end = font_i + 16;
            if font_end <= FONT.len() {
                let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
                let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;

                let stride = self.width * 4;

                let offset = y * stride + x * 4;
                offscreen_ptr += offset;
                onscreen_ptr += offset;

                while font_i < font_end {
                    let mut row_data = FONT[font_i];
                    let mut col = 8;
                    while col > 0 {
                        col -= 1;
                        if row_data & 1 == 1 {
                            unsafe {
                                *((offscreen_ptr + col * 4) as *mut u32) = color;
                            }
                        }
                        row_data = row_data >> 1;
                    }

                    unsafe {
                        fast_copy64(onscreen_ptr as *mut u64, offscreen_ptr as *const u64, 4);
                    }

                    offscreen_ptr += stride;
                    onscreen_ptr += stride;
                    font_i += 1;
                }
            }
        }
    }

    /// Scroll display
    pub fn scroll(&mut self, rows: usize, color: u32) {
        let data = (color as u64) << 32 | color as u64;

        let width = self.width/2;
        let height = self.height;
        if rows > 0 && rows < height {
            let off1 = rows * width;
            let off2 = height * width - off1;
            unsafe {
                let data_ptr = self.offscreen.as_mut_ptr() as *mut u64;
                fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2);
                fast_set64(data_ptr.offset(off2 as isize), data, off1);

                fast_copy64(self.onscreen.as_mut_ptr() as *mut u64, data_ptr, off1 + off2);
            }
        }
    }

    /// Handle ransid event
    pub fn event(&mut self, event: Event) {
        match event {
            Event::Char { x, y, c, color, .. } => {
                self.char(x * 8, y * 16, c, color.data);
            },
            Event::Rect { x, y, w, h, color } => {
                self.rect(x * 8, y * 16, w * 8, h * 16, color.data);
            },
            Event::Scroll { rows, color } => {
                self.scroll(rows * 16, color.data);
            }
        }
    }
}
<commit_msg>Set write combining for AP<commit_after>use core::{cmp, slice};
use ransid::{Console, Event};
use spin::Mutex;

use memory::Frame;
use paging::{ActivePageTable, PhysicalAddress, entry};

#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) {
    asm!("cld
        rep movsq"
        :
        : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
        : "cc", "memory"
        : "intel", "volatile");
}

#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
unsafe fn fast_set(dst: *mut u32, src: u32, len: usize) {
    asm!("cld
        rep stosd"
        :
        : "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len)
        : "cc", "memory"
        : "intel", "volatile");
}

#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) {
    asm!("cld
        rep stosq"
        :
        : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len)
        : "cc", "memory"
        : "intel", "volatile");
}

/// The info of the VBE mode
#[derive(Copy, Clone, Default, Debug)]
#[repr(packed)]
pub struct VBEModeInfo {
    attributes: u16,
    win_a: u8,
    win_b: u8,
    granularity: u16,
    winsize: u16,
    segment_a: u16,
    segment_b: u16,
    winfuncptr: u32,
    bytesperscanline: u16,
    pub xresolution: u16,
    pub yresolution: u16,
    xcharsize: u8,
    ycharsize: u8,
    numberofplanes: u8,
    bitsperpixel: u8,
    numberofbanks: u8,
    memorymodel: u8,
    banksize: u8,
    numberofimagepages: u8,
    unused: u8,
    redmasksize: u8,
    redfieldposition: u8,
    greenmasksize: u8,
    greenfieldposition: u8,
    bluemasksize: u8,
    bluefieldposition: u8,
    rsvdmasksize: u8,
    rsvdfieldposition: u8,
    directcolormodeinfo: u8,
    physbaseptr: u32,
    offscreenmemoryoffset: u32,
    offscreenmemsize: u16,
}

pub static CONSOLE: Mutex<Option<Console>> = Mutex::new(None);

pub static DISPLAY: Mutex<Option<Display>> = Mutex::new(None);

static FONT: &'static [u8] = include_bytes!("../../../../res/unifont.font");

pub unsafe fn init(active_table: &mut ActivePageTable) {
    active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);

    let mode_info = &*(0x5200 as *const VBEModeInfo);
    if mode_info.physbaseptr > 0 {
        let width = mode_info.xresolution as usize;
        let height = mode_info.yresolution as usize;
        let onscreen = mode_info.physbaseptr as usize;
        let size = width * height;

        {
            let start_frame = Frame::containing_address(PhysicalAddress::new(onscreen));
            let end_frame = Frame::containing_address(PhysicalAddress::new(onscreen + size * 4 - 1));
            for frame in Frame::range_inclusive(start_frame, end_frame) {
                active_table.identity_map(frame, /*actually sets PAT for write combining*/ entry::HUGE_PAGE | entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
            }
        }

        fast_set64(onscreen as *mut u64, 0, size/2);

        let offscreen = ::allocator::__rust_allocate(size * 4, 4096);
        fast_set64(offscreen as *mut u64, 0, size/2);

        *DISPLAY.lock() = Some(Display::new(width, height,
            slice::from_raw_parts_mut(onscreen as *mut u32, size),
            slice::from_raw_parts_mut(offscreen as *mut u32, size)
        ));
        *CONSOLE.lock() = Some(Console::new(width/8, height/16));
    }
}

pub unsafe fn init_ap(active_table: &mut ActivePageTable) {
    active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);

    let mode_info = &*(0x5200 as *const VBEModeInfo);
    if mode_info.physbaseptr > 0 {
        let width = mode_info.xresolution as usize;
        let height = mode_info.yresolution as usize;
        let start = mode_info.physbaseptr as usize;
        let size = width * height;

        {
            let start_frame = Frame::containing_address(PhysicalAddress::new(start));
            let end_frame = Frame::containing_address(PhysicalAddress::new(start + size * 4 - 1));
            for frame in Frame::range_inclusive(start_frame, end_frame) {
                active_table.identity_map(frame, /*actually sets PAT for write combining*/ entry::HUGE_PAGE | entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
            }
        }
    }
}

/// A display
pub struct Display {
    pub width: usize,
    pub height: usize,
    pub onscreen: &'static mut [u32],
    pub offscreen: &'static mut [u32],
}

impl Display {
    fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display {
        Display {
            width: width,
            height: height,
            onscreen: onscreen,
            offscreen: offscreen,
        }
    }

    /// Draw a rectangle
    fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
        let start_y = cmp::min(self.height - 1, y);
        let end_y = cmp::min(self.height, y + h);

        let start_x = cmp::min(self.width - 1, x);
        let len = cmp::min(self.width, x + w) - start_x;

        let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
        let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;

        let stride = self.width * 4;

        let offset = y * stride + start_x * 4;
        offscreen_ptr += offset;
        onscreen_ptr += offset;

        let mut rows = end_y - start_y;
        while rows > 0 {
            unsafe {
                fast_set(offscreen_ptr as *mut u32, color, len);
                fast_set(onscreen_ptr as *mut u32, color, len);
            }
            offscreen_ptr += stride;
            onscreen_ptr += stride;
            rows -= 1;
        }
    }

    /// Draw a character
    fn char(&mut self, x: usize, y: usize, character: char, color: u32) {
        if x + 8 <= self.width && y + 16 <= self.height {
            let mut font_i = 16 * (character as usize);
            let font_end = font_i + 16;
            if font_end <= FONT.len() {
                let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
                let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;

                let stride = self.width * 4;

                let offset = y * stride + x * 4;
                offscreen_ptr += offset;
                onscreen_ptr += offset;

                while font_i < font_end {
                    let mut row_data = FONT[font_i];
                    let mut col = 8;
                    while col > 0 {
                        col -= 1;
                        if row_data & 1 == 1 {
                            unsafe {
                                *((offscreen_ptr + col * 4) as *mut u32) = color;
                            }
                        }
                        row_data = row_data >> 1;
                    }

                    unsafe {
                        fast_copy64(onscreen_ptr as *mut u64, offscreen_ptr as *const u64, 4);
                    }

                    offscreen_ptr += stride;
                    onscreen_ptr += stride;
                    font_i += 1;
                }
            }
        }
    }

    /// Scroll display
    pub fn scroll(&mut self, rows: usize, color: u32) {
        let data = (color as u64) << 32 | color as u64;

        let width = self.width/2;
        let height = self.height;
        if rows > 0 && rows < height {
            let off1 = rows * width;
            let off2 = height * width - off1;
            unsafe {
                let data_ptr = self.offscreen.as_mut_ptr() as *mut u64;
                fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2);
                fast_set64(data_ptr.offset(off2 as isize), data, off1);

                fast_copy64(self.onscreen.as_mut_ptr() as *mut u64, data_ptr, off1 + off2);
            }
        }
    }

    /// Handle ransid event
    pub fn event(&mut self, event: Event) {
        match event {
            Event::Char { x, y, c, color, .. } => {
                self.char(x * 8, y * 16, c, color.data);
            },
            Event::Rect { x, y, w, h, color } => {
                self.rect(x * 8, y * 16, w * 8, h * 16, color.data);
            },
            Event::Scroll { rows, color } => {
                self.scroll(rows * 16, color.data);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::time::Duration;
use std::sync::Arc;

use futures::{Future, future};

use tokio_service::Service;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_proto::TcpClient;
use tokio_proto::multiplex::{ClientService};
use tokio_middleware::Timeout;
use tokio_timer::Timer;

use tcp::proto::BytesClientProto;
use tcp::shortcut;
use bifrost_hasher::hash_str;
use super::STANDALONE_ADDRESS;
use DISABLE_SHORTCUT;

use utils::async_locks::Mutex;

pub struct ClientCore {
    inner: ClientService<TcpStream, BytesClientProto>,
}

pub struct Client {
    client: Option<(Timeout<ClientCore>, Core)>,
    pub server_id: u64,
}

impl Service for ClientCore {

    type Request = Vec<u8>;
    type Response = Vec<u8>;
    type Error = io::Error;
    // Again for simplicity, we are just going to box a future
    type Future = Box<Future<Item = Self::Response, Error = io::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        Box::new(self.inner.call(req))
    }
}

impl Client {

    pub fn connect_with_timeout_async (address: String, timeout: Duration)
        -> Box<Future<Item = Client, Error = io::Error>>
    {
        let server_id = hash_str(&address);
        if !DISABLE_SHORTCUT && shortcut::is_local(server_id) {
            return box future::ok(Client {
                client: None,
                server_id
            })
        } else {
            if address.eq(&STANDALONE_ADDRESS) {
                return box future::err(io::Error::new(io::ErrorKind::Other, "STANDALONE server is not found"))
            }
            let mut core = match Core::new() {
                Ok(c) => c,
                Err(e) => return box future::err(e)
            };
            let socket_address = address.parse().unwrap();
            return box TcpClient::new(BytesClientProto)
                .connect(&socket_address, &core.handle())
                .map(move |c| {
                    Some((Timeout::new(
                        ClientCore {
                            inner: c,
                        },
                        Timer::default(),
                        timeout
                    ), core))
                })
                .map(move |client| {
                    Client {
                        client,
                        server_id,
                    }
                })
        }
    }
    pub fn connect_async (address: String)
        -> impl Future<Item = Client, Error = io::Error>
    {
        Client::connect_with_timeout_async(address, Duration::from_secs(5))
    }
    pub fn send(&mut self, msg: Vec<u8>) -> io::Result<Vec<u8>> {
        let future = self.send_async(msg);
        if let Some((_,ref mut core)) = self.client {
            core.run(future)
        } else {
            future.wait()
        }
    }
    pub fn send_async(&self, msg: Vec<u8>) -> impl Future<Item = Vec<u8>, Error = io::Error>
    {
        if let Some((ref client, _)) = self.client {
            box client.call(msg)
        } else {
            shortcut::call(self.server_id, msg)
        }
    }
}

unsafe impl Send for Client {}<commit_msg>remove sync tpc client function<commit_after>use std::io;
use std::time::Duration;
use std::sync::Arc;

use futures::{Future, future};

use tokio_service::Service;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_proto::TcpClient;
use tokio_proto::multiplex::{ClientService};
use tokio_middleware::Timeout;
use tokio_timer::Timer;

use tcp::proto::BytesClientProto;
use tcp::shortcut;
use bifrost_hasher::hash_str;
use super::STANDALONE_ADDRESS;
use DISABLE_SHORTCUT;

use utils::async_locks::Mutex;

pub struct ClientCore {
    inner: ClientService<TcpStream, BytesClientProto>,
}

pub struct Client {
    client: Option<Timeout<ClientCore>>,
    pub server_id: u64,
}

impl Service for ClientCore {

    type Request = Vec<u8>;
    type Response = Vec<u8>;
    type Error = io::Error;
    // Again for simplicity, we are just going to box a future
    type Future = Box<Future<Item = Self::Response, Error = io::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        Box::new(self.inner.call(req))
    }
}

impl Client {

    pub fn connect_with_timeout_async (address: String, timeout: Duration)
        -> Box<Future<Item = Client, Error = io::Error>>
    {
        let server_id = hash_str(&address);
        if !DISABLE_SHORTCUT && shortcut::is_local(server_id) {
            return box future::ok(Client {
                client: None,
                server_id
            })
        } else {
            if address.eq(&STANDALONE_ADDRESS) {
                return box future::err(io::Error::new(io::ErrorKind::Other, "STANDALONE server is not found"))
            }
            let mut core = match Core::new() {
                Ok(c) => c,
                Err(e) => return box future::err(e)
            };
            let socket_address = address.parse().unwrap();
            return box TcpClient::new(BytesClientProto)
                .connect(&socket_address, &core.handle())
                .map(move |c| {
                    Some(Timeout::new(
                        ClientCore {
                            inner: c,
                        },
                        Timer::default(),
                        timeout
                    ))
                })
                .map(move |client| {
                    Client {
                        client,
                        server_id,
                    }
                })
        }
    }
    pub fn connect_async (address: String)
        -> impl Future<Item = Client, Error = io::Error>
    {
        Client::connect_with_timeout_async(address, Duration::from_secs(5))
    }
    pub fn send_async(&self, msg: Vec<u8>) -> impl Future<Item = Vec<u8>, Error = io::Error>
    {
        if let Some(ref client) = self.client {
            box client.call(msg)
        } else {
            shortcut::call(self.server_id, msg)
        }
    }
}

unsafe impl Send for Client {}<|endoftext|>


<commit_before>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{
    debug_delay, warn, AtomicBool, AtomicUsize, Lazy, OneShot, Relaxed, SeqCst,
};

const MAX_THREADS: usize = 128;
const MIN_THREADS: usize = 2;

static STANDBY_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            let res = self.cv.wait_until(&mut queue, cutoff);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_one();
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);

fn init_queue() -> Queue {
    maybe_spawn_new_thread();
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work() {
    let wait_limit = Duration::from_secs(1);

    while STANDBY_THREAD_COUNT.load(SeqCst) < MIN_THREADS {
        debug_delay();
        STANDBY_THREAD_COUNT.fetch_add(1, SeqCst);

        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        debug_delay();
        if STANDBY_THREAD_COUNT.fetch_sub(1, SeqCst) <= MIN_THREADS {
            maybe_spawn_new_thread();
        }

        if let Some(task) = task_res {
            (task)();
        }

        debug_delay();
        while let Some(task) = QUEUE.try_recv() {
            (task)();
            debug_delay();
        }

        debug_delay();
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(SeqCst);
    debug_delay();
    let standby_workers = STANDBY_THREAD_COUNT.load(SeqCst);
    if standby_workers >= MIN_THREADS || total_workers >= MAX_THREADS {
        return;
    }

    let spawn_res =
        thread::Builder::new().name("sled-io".to_string()).spawn(|| {
            debug_delay();
            TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
            perform_work();
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
        });

    if let Err(e) = spawn_res {
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}. \
                 Currently have {} running IO threads",
                e, total_workers
            )
        });
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    QUEUE.send(Box::new(task));

    maybe_spawn_new_thread();

    promise
}
<commit_msg>Use fewer threads on windows<commit_after>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{
    debug_delay, warn, AtomicBool, AtomicUsize, Lazy, OneShot, Relaxed, SeqCst,
};

#[cfg(windows)]
const MAX_THREADS: usize = 16;

#[cfg(not(windows))]
const MAX_THREADS: usize = 128;

const MIN_THREADS: usize = 2;

static STANDBY_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            let res = self.cv.wait_until(&mut queue, cutoff);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_one();
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);

fn init_queue() -> Queue {
    maybe_spawn_new_thread();
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work() {
    let wait_limit = Duration::from_secs(1);

    while STANDBY_THREAD_COUNT.load(SeqCst) < MIN_THREADS {
        debug_delay();
        STANDBY_THREAD_COUNT.fetch_add(1, SeqCst);

        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        debug_delay();
        if STANDBY_THREAD_COUNT.fetch_sub(1, SeqCst) <= MIN_THREADS {
            maybe_spawn_new_thread();
        }

        if let Some(task) = task_res {
            (task)();
        }

        debug_delay();
        while let Some(task) = QUEUE.try_recv() {
            (task)();
            debug_delay();
        }

        debug_delay();
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(SeqCst);
    debug_delay();
    let standby_workers = STANDBY_THREAD_COUNT.load(SeqCst);
    if standby_workers >= MIN_THREADS || total_workers >= MAX_THREADS {
        return;
    }

    let spawn_res =
        thread::Builder::new().name("sled-io".to_string()).spawn(|| {
            debug_delay();
            TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
            perform_work();
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
        });

    if let Err(e) = spawn_res {
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}. \
                 Currently have {} running IO threads",
                e, total_workers
            )
        });
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    QUEUE.send(Box::new(task));

    maybe_spawn_new_thread();

    promise
}
<|endoftext|>


<commit_before>// Functionality that is shared between the cxx_build::bridge entry point and
// the cxxbridge CLI command.

mod builtin;
mod check;
pub(super) mod error;
mod file;
pub(super) mod fs;
mod ifndef;
pub(super) mod include;
mod namespace_organizer;
pub(super) mod out;
mod write;

pub(super) use self::error::Error;
use self::error::{format_err, Result};
use self::file::File;
use self::include::Include;
use crate::syntax::report::Errors;
use crate::syntax::{self, Types};
use std::path::Path;

/// Options for C++ code generation.
///
/// We expect options to be added over time, so this is a non-exhaustive struct.
/// To instantiate one you need to crate a default value and mutate those fields
/// that you want to modify.
///
/// ```
/// # use cxx_gen::Opt;
/// #
/// let impl_annotations = r#"__attribute__((visibility("default")))"#.to_owned();
///
/// let mut opt = Opt::default();
/// opt.cxx_impl_annotations = Some(impl_annotations);
/// ```
#[non_exhaustive]
pub struct Opt {
    /// Any additional headers to #include. The cxxbridge tool does not parse or
    /// even require the given paths to exist; they simply go into the generated
    /// C++ code as #include lines.
    pub include: Vec<Include>,
    /// Optional annotation for implementations of C++ function wrappers that
    /// may be exposed to Rust. You may for example need to provide
    /// `__declspec(dllexport)` or `__attribute__((visibility("default")))` if
    /// Rust code from one shared object or executable depends on these C++
    /// functions in another.
    pub cxx_impl_annotations: Option<String>,

    pub(super) gen_header: bool,
    pub(super) gen_implementation: bool,
    pub(super) allow_dot_includes: bool,
}

/// Results of code generation.
#[derive(Default)]
pub struct GeneratedCode {
    /// The bytes of a C++ header file.
    pub header: Vec<u8>,
    /// The bytes of a C++ implementation file (e.g. .cc, cpp etc.)
    pub implementation: Vec<u8>,
}

impl Default for Opt {
    fn default() -> Self {
        Opt {
            include: Vec::new(),
            cxx_impl_annotations: None,
            gen_header: true,
            gen_implementation: true,
            allow_dot_includes: true,
        }
    }
}

pub(super) fn generate_from_path(path: &Path, opt: &Opt) -> GeneratedCode {
    let source = match read_to_string(path) {
        Ok(source) => source,
        Err(err) => format_err(path, "", err),
    };
    match generate_from_string(&source, opt) {
        Ok(out) => out,
        Err(err) => format_err(path, &source, err),
    }
}

fn read_to_string(path: &Path) -> Result<String> {
    let bytes = if path == Path::new("-") {
        fs::read_stdin()
    } else {
        fs::read(path)
    }?;
    match String::from_utf8(bytes) {
        Ok(string) => Ok(string),
        Err(err) => Err(Error::Utf8(path.to_owned(), err.utf8_error())),
    }
}

fn generate_from_string(source: &str, opt: &Opt) -> Result<GeneratedCode> {
    let mut source = source;
    if source.starts_with("#!") && !source.starts_with("#![") {
        let shebang_end = source.find('\n').unwrap_or(source.len());
        source = &source[shebang_end..];
    }
    proc_macro2::fallback::force();
    let syntax: File = syn::parse_str(source)?;
    generate(syntax, opt)
}

pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
    let ref mut errors = Errors::new();
    let bridge = syntax
        .modules
        .into_iter()
        .next()
        .ok_or(Error::NoBridgeMod)?;
    let ref namespace = bridge.namespace;
    let trusted = bridge.unsafety.is_some();
    let ref apis = syntax::parse_items(errors, bridge.content, trusted, namespace);
    let ref types = Types::collect(errors, apis);
    check::precheck(errors, apis, opt);
    errors.propagate()?;
    check::typecheck(errors, apis, types);
    errors.propagate()?;
    // Some callers may wish to generate both header and implementation from the
    // same token stream to avoid parsing twice. Others only need to generate
    // one or the other.
    Ok(GeneratedCode {
        header: if opt.gen_header {
            write::gen(apis, types, opt, true).content()
        } else {
            Vec::new()
        },
        implementation: if opt.gen_implementation {
            write::gen(apis, types, opt, false).content()
        } else {
            Vec::new()
        },
    })
}
<commit_msg>Collect apis from multiple cxx::bridge in the same file<commit_after>// Functionality that is shared between the cxx_build::bridge entry point and
// the cxxbridge CLI command.

mod builtin;
mod check;
pub(super) mod error;
mod file;
pub(super) mod fs;
mod ifndef;
pub(super) mod include;
mod namespace_organizer;
pub(super) mod out;
mod write;

pub(super) use self::error::Error;
use self::error::{format_err, Result};
use self::file::File;
use self::include::Include;
use crate::syntax::report::Errors;
use crate::syntax::{self, Types};
use std::path::Path;

/// Options for C++ code generation.
///
/// We expect options to be added over time, so this is a non-exhaustive struct.
/// To instantiate one you need to crate a default value and mutate those fields
/// that you want to modify.
///
/// ```
/// # use cxx_gen::Opt;
/// #
/// let impl_annotations = r#"__attribute__((visibility("default")))"#.to_owned();
///
/// let mut opt = Opt::default();
/// opt.cxx_impl_annotations = Some(impl_annotations);
/// ```
#[non_exhaustive]
pub struct Opt {
    /// Any additional headers to #include. The cxxbridge tool does not parse or
    /// even require the given paths to exist; they simply go into the generated
    /// C++ code as #include lines.
    pub include: Vec<Include>,
    /// Optional annotation for implementations of C++ function wrappers that
    /// may be exposed to Rust. You may for example need to provide
    /// `__declspec(dllexport)` or `__attribute__((visibility("default")))` if
    /// Rust code from one shared object or executable depends on these C++
    /// functions in another.
    pub cxx_impl_annotations: Option<String>,

    pub(super) gen_header: bool,
    pub(super) gen_implementation: bool,
    pub(super) allow_dot_includes: bool,
}

/// Results of code generation.
#[derive(Default)]
pub struct GeneratedCode {
    /// The bytes of a C++ header file.
    pub header: Vec<u8>,
    /// The bytes of a C++ implementation file (e.g. .cc, cpp etc.)
    pub implementation: Vec<u8>,
}

impl Default for Opt {
    fn default() -> Self {
        Opt {
            include: Vec::new(),
            cxx_impl_annotations: None,
            gen_header: true,
            gen_implementation: true,
            allow_dot_includes: true,
        }
    }
}

pub(super) fn generate_from_path(path: &Path, opt: &Opt) -> GeneratedCode {
    let source = match read_to_string(path) {
        Ok(source) => source,
        Err(err) => format_err(path, "", err),
    };
    match generate_from_string(&source, opt) {
        Ok(out) => out,
        Err(err) => format_err(path, &source, err),
    }
}

fn read_to_string(path: &Path) -> Result<String> {
    let bytes = if path == Path::new("-") {
        fs::read_stdin()
    } else {
        fs::read(path)
    }?;
    match String::from_utf8(bytes) {
        Ok(string) => Ok(string),
        Err(err) => Err(Error::Utf8(path.to_owned(), err.utf8_error())),
    }
}

fn generate_from_string(source: &str, opt: &Opt) -> Result<GeneratedCode> {
    let mut source = source;
    if source.starts_with("#!") && !source.starts_with("#![") {
        let shebang_end = source.find('\n').unwrap_or(source.len());
        source = &source[shebang_end..];
    }
    proc_macro2::fallback::force();
    let syntax: File = syn::parse_str(source)?;
    generate(syntax, opt)
}

pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
    if syntax.modules.is_empty() {
        return Err(Error::NoBridgeMod);
    }

    let ref mut apis = Vec::new();
    let ref mut errors = Errors::new();
    for bridge in syntax.modules {
        let ref namespace = bridge.namespace;
        let trusted = bridge.unsafety.is_some();
        apis.extend(syntax::parse_items(errors, bridge.content, trusted, namespace));
    }

    let ref types = Types::collect(errors, apis);
    check::precheck(errors, apis, opt);
    errors.propagate()?;
    check::typecheck(errors, apis, types);
    errors.propagate()?;

    // Some callers may wish to generate both header and implementation from the
    // same token stream to avoid parsing twice. Others only need to generate
    // one or the other.
    Ok(GeneratedCode {
        header: if opt.gen_header {
            write::gen(apis, types, opt, true).content()
        } else {
            Vec::new()
        },
        implementation: if opt.gen_implementation {
            write::gen(apis, types, opt, false).content()
        } else {
            Vec::new()
        },
    })
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(clippy::assertions_on_constants)]

use std::fs::{self, DirEntry};
use std::path::Path;

#[test]
fn test_missing_tests() {
    let missing_files = explore_directory(Path::new("./tests"));
    if !missing_files.is_empty() {
        assert!(
            false,
            "Didn't see a test file for the following files:\n\n{}\n",
            missing_files
                .iter()
                .map(|s| format!("\t{}", s))
                .collect::<Vec<_>>()
                .join("\n")
        );
    }
}

/*
Test for missing files.

Since rs files are alphabetically before stderr/stdout, we can sort by the full name
and iter in that order. If we've seen the file stem for the first time and it's not
a rust file, it means the rust file has to be missing.
*/
fn explore_directory(dir: &Path) -> Vec<String> {
    let mut missing_files: Vec<String> = Vec::new();
    let mut current_file = String::new();
    let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
    files.sort_by_key(std::fs::DirEntry::path);
    for entry in &files {
        let path = entry.path();
        if path.is_dir() {
            missing_files.extend(explore_directory(&path));
        } else {
            let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string();
            if let Some(ext) = path.extension() {
                match ext.to_str().unwrap() {
                    "rs" => current_file = file_stem.clone(),
                    "stderr" | "stdout" => {
                        if file_stem != current_file {
                            missing_files.push(path.to_str().unwrap().to_string());
                        }
                    },
                    _ => continue,
                };
            }
        }
    }
    missing_files
}
<commit_msg>Account for revisions in missing-test-files<commit_after>#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(clippy::assertions_on_constants)]
#![feature(path_file_prefix)]

use std::cmp::Ordering;
use std::ffi::OsStr;
use std::fs::{self, DirEntry};
use std::path::Path;

#[test]
fn test_missing_tests() {
    let missing_files = explore_directory(Path::new("./tests"));
    if !missing_files.is_empty() {
        assert!(
            false,
            "Didn't see a test file for the following files:\n\n{}\n",
            missing_files
                .iter()
                .map(|s| format!("\t{}", s))
                .collect::<Vec<_>>()
                .join("\n")
        );
    }
}

// Test for missing files.
fn explore_directory(dir: &Path) -> Vec<String> {
    let mut missing_files: Vec<String> = Vec::new();
    let mut current_file = String::new();
    let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
    files.sort_by(|x, y| {
        match x.path().file_prefix().cmp(&y.path().file_prefix()) {
            Ordering::Equal => (),
            ord => return ord,
        }
        // Sort rs files before the others if they share the same prefix. So when we see
        // the file prefix for the first time and it's not a rust file, it means the rust
        // file has to be missing.
        match (
            x.path().extension().and_then(OsStr::to_str),
            y.path().extension().and_then(OsStr::to_str),
        ) {
            (Some("rs"), _) => Ordering::Less,
            (_, Some("rs")) => Ordering::Greater,
            _ => Ordering::Equal,
        }
    });
    for entry in &files {
        let path = entry.path();
        if path.is_dir() {
            missing_files.extend(explore_directory(&path));
        } else {
            let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string();
            if let Some(ext) = path.extension() {
                match ext.to_str().unwrap() {
                    "rs" => current_file = file_prefix.clone(),
                    "stderr" | "stdout" => {
                        if file_prefix != current_file {
                            missing_files.push(path.to_str().unwrap().to_string());
                        }
                    },
                    _ => continue,
                };
            }
        }
    }
    missing_files
}
<|endoftext|>


<commit_before>use crate::error::Error;
use lldb::*;
use log::*;
use std::env;
use std::ffi::CStr;
use std::mem;
use std::os::raw::{c_char, c_int, c_long, c_void};

pub trait EventSink {
    fn display_html(&self, html: String, title: Option<String>, position: Option<i32>, reveal: bool);
}

#[allow(unions_with_drop_fields)]
#[repr(C)]
union ValueResult {
    value: SBValue,
    error: SBError,
}

#[allow(unions_with_drop_fields)]
#[repr(C)]
union BoolResult {
    value: bool,
    error: SBError,
}

pub struct PythonInterface {
    initialized: bool,
    event_sink: Box<dyn EventSink + Send>,
    evaluate_ptr: Option<
        extern "C" fn(
            result: *mut ValueResult,
            expr: *const c_char,
            expr_len: usize,
            is_simple_expr: bool,
            context: SBExecutionContext,
        ) -> i32,
    >,
    evaluate_as_bool_ptr: Option<
        extern "C" fn(
            result: *mut BoolResult,
            expr: *const c_char,
            expr_len: usize,
            is_simple_expr: bool,
            context: SBExecutionContext,
        ) -> i32,
    >,
    modules_loaded_ptr: Option<extern "C" fn(modules: *const SBModule, modules_len: usize) -> i32>,
    shutdown_ptr: Option<extern "C" fn() -> i32>,
}

impl PythonInterface {
    pub fn new(
        interpreter: SBCommandInterpreter,
        event_sink: Box<dyn EventSink + Send>,
    ) -> Result<Box<PythonInterface>, Error> {
        let current_exe = env::current_exe()?;
        let mut command_result = SBCommandReturnObject::new();

        // Import debugger.py into script interpreter's namespace.
        // This also adds our bin directory to sys.path, so we can import the rest of the modules below.
        let init_script = current_exe.with_file_name("debugger.py");
        let command = format!("command script import '{}'", init_script.to_str().unwrap());
        interpreter.handle_command(&command, &mut command_result, false);
        if !command_result.succeeded() {
            return Err(Error::Internal(format!("{:?}", command_result)));
        }

        let mut interface = Box::new(PythonInterface {
            initialized: false,
            shutdown_ptr: None,
            evaluate_ptr: None,
            evaluate_as_bool_ptr: None,
            modules_loaded_ptr: None,
            event_sink,
        });

        unsafe extern "C" fn init_callback(
            interface: *mut PythonInterface,
            shutdown_ptr: *const c_void,
            evaluate_ptr: *const c_void,
            evaluate_as_bool_ptr: *const c_void,
            modules_loaded_ptr: *const c_void,
        ) {
            (*interface).shutdown_ptr = Some(mem::transmute(shutdown_ptr));
            (*interface).evaluate_ptr = Some(mem::transmute(evaluate_ptr));
            (*interface).evaluate_as_bool_ptr = Some(mem::transmute(evaluate_as_bool_ptr));
            (*interface).modules_loaded_ptr = Some(mem::transmute(modules_loaded_ptr));
            (*interface).initialized = true;
        }

        unsafe extern "C" fn display_html_callback(
            interface: *mut PythonInterface,
            html: *const c_char,
            title: *const c_char,
            position: c_int,
            reveal: c_int,
        ) {
            if html.is_null() {
                return;
            }
            let html = CStr::from_ptr(html).to_str().unwrap().to_string();
            let title = if title.is_null() {
                None
            } else {
                Some(CStr::from_ptr(title).to_str().unwrap().to_string())
            };
            let position = Some(position as i32);
            let reveal = reveal != 0;
            (*interface).event_sink.display_html(html, title, position, reveal);
        }

        let command = format!(
            "script import codelldb; codelldb.initialize({:p}, {:p}, {:p})",
            init_callback as *const c_void, display_html_callback as *const c_void, interface
        );
        interpreter.handle_command(&command, &mut command_result, false);
        if !command_result.succeeded() {
            return Err(Error::Internal(format!("{:?}", command_result)));
        }

        // Make sure Python side has called us back.
        if !interface.initialized {
            return Err(Error::Internal("Could not initialize Python environment.".into()));
        }

        let rust_formatters = current_exe.with_file_name("rust.py");
        let command = format!("command script import '{}'", rust_formatters.to_str().unwrap()); /*###*/
        interpreter.handle_command(&command, &mut command_result, false);
        if !command_result.succeeded() {
            error!("{:?}", command_result); // But carry on - Rust formatters are not critical to have.
        }

        Ok(interface)
    }

    pub fn evaluate(&self, expr: &str, is_simple_expr: bool, context: &SBExecutionContext) -> Result<SBValue, String> {
        unsafe {
            let expt_ptr = expr.as_ptr() as *const c_char;
            let expr_size = expr.len();
            let mut result = mem::MaybeUninit::<ValueResult>::uninit();
            let status =
                (self.evaluate_ptr.unwrap())(result.as_mut_ptr(), expt_ptr, expr_size, is_simple_expr, context.clone());
            if status > 0 {
                Ok(result.assume_init().value)
            } else if status < 0 {
                Err(result.assume_init().error.to_string())
            } else {
                Err("Evaluation failed".into())
            }
        }
    }

    pub fn evaluate_as_bool(
        &self,
        expr: &str,
        is_simple_expr: bool,
        context: &SBExecutionContext,
    ) -> Result<bool, String> {
        unsafe {
            let expt_ptr = expr.as_ptr() as *const c_char;
            let expr_size = expr.len();
            let mut result = mem::MaybeUninit::<BoolResult>::uninit();
            let status = (self.evaluate_as_bool_ptr.unwrap())(
                result.as_mut_ptr(),
                expt_ptr,
                expr_size,
                is_simple_expr,
                context.clone(),
            );
            if status > 0 {
                Ok(result.assume_init().value)
            } else if status < 0 {
                Err(result.assume_init().error.to_string())
            } else {
                Err("Evaluation failed".into())
            }
        }
    }

    pub fn modules_loaded(&self, modules: &mut dyn Iterator<Item = &SBModule>) {
        let modules = modules.cloned().collect::<Vec<SBModule>>();
        (self.modules_loaded_ptr.unwrap())(modules.as_ptr(), modules.len());
    }
}

impl Drop for PythonInterface {
    fn drop(&mut self) {
        if self.initialized {
            unsafe { (self.shutdown_ptr.unwrap())() };
        }
    }
}

#[test]
fn test_sizeof() {
    // codelldb.py makes assumptions about sizes of these types:
    assert_eq!(mem::size_of::<SBError>(), 8);
    assert_eq!(mem::size_of::<SBExecutionContext>(), 16);
    assert_eq!(mem::size_of::<SBValue>(), 16);
    assert_eq!(mem::size_of::<SBModule>(), 16);
}
<commit_msg>Replace #[allow(unions_with_drop_fields)] with MaybeUninit.<commit_after>use crate::error::Error;
use lldb::*;
use log::*;
use std::env;
use std::ffi::CStr;
use std::mem;
use std::os::raw::{c_char, c_int, c_long, c_void};

pub trait EventSink {
    fn display_html(&self, html: String, title: Option<String>, position: Option<i32>, reveal: bool);
}

#[repr(C)]
union ValueResult {
    value: mem::MaybeUninit<SBValue>,
    error: mem::MaybeUninit<SBError>,
}

#[repr(C)]
union BoolResult {
    value: bool,
    error: mem::MaybeUninit<SBError>,
}

pub struct PythonInterface {
    initialized: bool,
    event_sink: Box<dyn EventSink + Send>,
    evaluate_ptr: Option<
        extern "C" fn(
            result: *mut ValueResult,
            expr: *const c_char,
            expr_len: usize,
            is_simple_expr: bool,
            context: SBExecutionContext,
        ) -> i32,
    >,
    evaluate_as_bool_ptr: Option<
        extern "C" fn(
            result: *mut BoolResult,
            expr: *const c_char,
            expr_len: usize,
            is_simple_expr: bool,
            context: SBExecutionContext,
        ) -> i32,
    >,
    modules_loaded_ptr: Option<extern "C" fn(modules: *const SBModule, modules_len: usize) -> i32>,
    shutdown_ptr: Option<extern "C" fn() -> i32>,
}

impl PythonInterface {
    pub fn new(
        interpreter: SBCommandInterpreter,
        event_sink: Box<dyn EventSink + Send>,
    ) -> Result<Box<PythonInterface>, Error> {
        let current_exe = env::current_exe()?;
        let mut command_result = SBCommandReturnObject::new();

        // Import debugger.py into script interpreter's namespace.
        // This also adds our bin directory to sys.path, so we can import the rest of the modules below.
        let init_script = current_exe.with_file_name("debugger.py");
        let command = format!("command script import '{}'", init_script.to_str().unwrap());
        interpreter.handle_command(&command, &mut command_result, false);
        if !command_result.succeeded() {
            return Err(Error::Internal(format!("{:?}", command_result)));
        }

        let mut interface = Box::new(PythonInterface {
            initialized: false,
            shutdown_ptr: None,
            evaluate_ptr: None,
            evaluate_as_bool_ptr: None,
            modules_loaded_ptr: None,
            event_sink,
        });

        unsafe extern "C" fn init_callback(
            interface: *mut PythonInterface,
            shutdown_ptr: *const c_void,
            evaluate_ptr: *const c_void,
            evaluate_as_bool_ptr: *const c_void,
            modules_loaded_ptr: *const c_void,
        ) {
            (*interface).shutdown_ptr = Some(mem::transmute(shutdown_ptr));
            (*interface).evaluate_ptr = Some(mem::transmute(evaluate_ptr));
            (*interface).evaluate_as_bool_ptr = Some(mem::transmute(evaluate_as_bool_ptr));
            (*interface).modules_loaded_ptr = Some(mem::transmute(modules_loaded_ptr));
            (*interface).initialized = true;
        }

        unsafe extern "C" fn display_html_callback(
            interface: *mut PythonInterface,
            html: *const c_char,
            title: *const c_char,
            position: c_int,
            reveal: c_int,
        ) {
            if html.is_null() {
                return;
            }
            let html = CStr::from_ptr(html).to_str().unwrap().to_string();
            let title = if title.is_null() {
                None
            } else {
                Some(CStr::from_ptr(title).to_str().unwrap().to_string())
            };
            let position = Some(position as i32);
            let reveal = reveal != 0;
            (*interface).event_sink.display_html(html, title, position, reveal);
        }

        let command = format!(
            "script import codelldb; codelldb.initialize({:p}, {:p}, {:p})",
            init_callback as *const c_void, display_html_callback as *const c_void, interface
        );
        interpreter.handle_command(&command, &mut command_result, false);
        if !command_result.succeeded() {
            return Err(Error::Internal(format!("{:?}", command_result)));
        }

        // Make sure Python side has called us back.
        if !interface.initialized {
            return Err(Error::Internal("Could not initialize Python environment.".into()));
        }

        let rust_formatters = current_exe.with_file_name("rust.py");
        let command = format!("command script import '{}'", rust_formatters.to_str().unwrap()); /*###*/
        interpreter.handle_command(&command, &mut command_result, false);
        if !command_result.succeeded() {
            error!("{:?}", command_result); // But carry on - Rust formatters are not critical to have.
        }

        Ok(interface)
    }

    pub fn evaluate(&self, expr: &str, is_simple_expr: bool, context: &SBExecutionContext) -> Result<SBValue, String> {
        unsafe {
            let expt_ptr = expr.as_ptr() as *const c_char;
            let expr_size = expr.len();
            let mut result = ValueResult {
                value: mem::MaybeUninit::uninit(),
            };
            let status =
                (self.evaluate_ptr.unwrap())(&mut result, expt_ptr, expr_size, is_simple_expr, context.clone());
            if status > 0 {
                Ok(result.value.assume_init())
            } else if status < 0 {
                Err(result.error.assume_init().to_string())
            } else {
                Err("Evaluation failed".into())
            }
        }
    }

    pub fn evaluate_as_bool(
        &self,
        expr: &str,
        is_simple_expr: bool,
        context: &SBExecutionContext,
    ) -> Result<bool, String> {
        unsafe {
            let expt_ptr = expr.as_ptr() as *const c_char;
            let expr_size = expr.len();
            let mut result = BoolResult {
                value: false,
            };
            let status =
                (self.evaluate_as_bool_ptr.unwrap())(&mut result, expt_ptr, expr_size, is_simple_expr, context.clone());
            if status > 0 {
                Ok(result.value)
            } else if status < 0 {
                Err(result.error.assume_init().to_string())
            } else {
                Err("Evaluation failed".into())
            }
        }
    }

    pub fn modules_loaded(&self, modules: &mut dyn Iterator<Item = &SBModule>) {
        let modules = modules.cloned().collect::<Vec<SBModule>>();
        (self.modules_loaded_ptr.unwrap())(modules.as_ptr(), modules.len());
    }
}

impl Drop for PythonInterface {
    fn drop(&mut self) {
        if self.initialized {
            unsafe { (self.shutdown_ptr.unwrap())() };
        }
    }
}

#[test]
fn test_sizeof() {
    // codelldb.py makes assumptions about sizes of these types:
    assert_eq!(mem::size_of::<SBError>(), 8);
    assert_eq!(mem::size_of::<SBExecutionContext>(), 16);
    assert_eq!(mem::size_of::<SBValue>(), 16);
    assert_eq!(mem::size_of::<SBModule>(), 16);
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/equal-row-and-column-pairs/
pub fn equal_pairs(grid: Vec<Vec<i32>>) -> i32 {
    todo!()
}

fn main() {
    println!(
        "{}",
        equal_pairs(vec![vec![3, 2, 1], vec![1, 7, 6], vec![2, 7, 7]])
    ); // 1
    println!(
        "{}",
        equal_pairs(vec![
            vec![3, 1, 2, 2],
            vec![1, 4, 4, 5],
            vec![2, 4, 2, 2],
            vec![2, 4, 2, 2]
        ])
    ); // 3
}
<commit_msg>Solve problem 2352<commit_after>use std::collections::HashMap;

// https://leetcode.com/problems/equal-row-and-column-pairs/
pub fn equal_pairs(grid: Vec<Vec<i32>>) -> i32 {
    let mut answer = 0;
    let mut map: HashMap<String, i32> = HashMap::new();
    let n = grid.len();
    for col in 0..n {
        let mut v: Vec<String> = vec![];
        for row in 0..n {
            v.push(grid[row][col].to_string());
        }
        let string = v.join(",");
        match map.get(&string) {
            Some(count) => map.insert(string, count + 1),
            None => map.insert(string, 1),
        };
    }
    for row in 0..n {
        let string = grid[row]
            .iter()
            .map(|a| a.to_string())
            .collect::<Vec<String>>()
            .join(",");
        match map.get(&string) {
            Some(count) => answer += count,
            None => (),
        }
    }
    answer
}

fn main() {
    println!(
        "{}",
        equal_pairs(vec![vec![3, 2, 1], vec![1, 7, 6], vec![2, 7, 7]])
    ); // 1
    println!(
        "{}",
        equal_pairs(vec![
            vec![3, 1, 2, 2],
            vec![1, 4, 4, 5],
            vec![2, 4, 2, 2],
            vec![2, 4, 2, 2]
        ])
    ); // 3
    println!("{}", equal_pairs(vec![vec![11, 1], vec![1, 11]])); // 2
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/time-needed-to-rearrange-a-binary-string/
pub fn seconds_to_remove_occurrences(s: String) -> i32 {
    todo!()
}

fn main() {
    println!("{}", seconds_to_remove_occurrences("0110101".to_string())); // 4
    println!("{}", seconds_to_remove_occurrences("11100".to_string())); // 0
}
<commit_msg>Update problem 2380<commit_after>// https://leetcode.com/problems/time-needed-to-rearrange-a-binary-string/
pub fn seconds_to_remove_occurrences(s: String) -> i32 {
    let mut answer = 0;
    let mut chars: Vec<char> = s.chars().collect();
    let mut i = 0;
    while i < chars.len() - 1 {
        if chars[i] == '0' && chars[i + 1] == '1' {
            chars.swap(i, i + 1);
            answer += 1;
        }
        i += 1;
    }
    answer
}

fn main() {
    println!("{}", seconds_to_remove_occurrences("0110101".to_string())); // 4
    println!("{}", seconds_to_remove_occurrences("11100".to_string())); // 0
    println!(
        "{}",
        seconds_to_remove_occurrences("1000111001010010010101010101".to_string())
    ); // 15
}
<|endoftext|>


<commit_before>extern crate time;

use Result;
use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};

const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%f";

impl ToSql for time::Timespec {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        let time_string = time::at_utc(*self)
            .strftime(SQLITE_DATETIME_FMT)
            .unwrap()
            .to_string();
        Ok(ToSqlOutput::from(time_string))
    }
}

impl FromSql for time::Timespec {
    fn column_result(value: ValueRef) -> FromSqlResult<Self> {
        value
            .as_str()
            .and_then(|s| match time::strptime(s, SQLITE_DATETIME_FMT) {
                          Ok(tm) => Ok(tm.to_timespec()),
                          Err(err) => Err(FromSqlError::Other(Box::new(err))),
                      })
    }
}

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

    fn checked_memory_handle() -> Connection {
        let db = Connection::open_in_memory().unwrap();
        db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT)")
            .unwrap();
        db
    }

    #[test]
    fn test_timespec() {
        let db = checked_memory_handle();

        let ts = time::Timespec {
            sec: 10_000,
            nsec: 0,
        };
        db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts])
            .unwrap();

        let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0))
            .unwrap();
        assert_eq!(from, ts);
    }
}
<commit_msg>fixed %F instead of %F:%s<commit_after>extern crate time;

use Result;
use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};

const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S:%f";

impl ToSql for time::Timespec {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        let time_string = time::at_utc(*self)
            .strftime(SQLITE_DATETIME_FMT)
            .unwrap()
            .to_string();
        Ok(ToSqlOutput::from(time_string))
    }
}

impl FromSql for time::Timespec {
    fn column_result(value: ValueRef) -> FromSqlResult<Self> {
        value
            .as_str()
            .and_then(|s| match time::strptime(s, SQLITE_DATETIME_FMT) {
                          Ok(tm) => Ok(tm.to_timespec()),
                          Err(err) => Err(FromSqlError::Other(Box::new(err))),
                      })
    }
}

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

    fn checked_memory_handle() -> Connection {
        let db = Connection::open_in_memory().unwrap();
        db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT)")
            .unwrap();
        db
    }

    #[test]
    fn test_timespec() {
        let db = checked_memory_handle();

        let ts = time::Timespec {
            sec: 10_000,
            nsec: 0,
        };
        db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts])
            .unwrap();

        let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0))
            .unwrap();
        assert_eq!(from, ts);
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate petgraph;
extern crate test;

use petgraph::graph::Graph;

#[bench]
fn bench_inser(b: &mut test::Bencher) {
    let mut og = Graph::new();
    let fst = og.add_node(0i32);
    for x in 1..125 {
        let n = og.add_node(x);
        og.add_edge(fst, n, ());
    }
    b.iter(|| {
        og.add_node(1)
    })
}

#[bench]
fn bench_remove(b: &mut test::Bencher) {
    // removal is very slow in a big graph.
    // and this one doesn't even have many nodes.
    let mut og = Graph::new();
    let fst = og.add_node(0i32);
    let mut prev = fst;
    for x in 1..1250 {
        let n = og.add_node(x);
        og.add_edge(prev, n, ());
        prev = n;
    }
    //println!("{}", og);
    b.iter(|| {
        for _ in 0 .. 100 {
            og.remove_node(fst);
        }
    })
}
<commit_msg>Add benchmark for add_edge<commit_after>#![feature(test)]

extern crate petgraph;
extern crate test;

use petgraph::graph::Graph;

#[bench]
fn bench_inser(b: &mut test::Bencher) {
    let mut og = Graph::new();
    let fst = og.add_node(0i32);
    for x in 1..125 {
        let n = og.add_node(x);
        og.add_edge(fst, n, ());
    }
    b.iter(|| {
        og.add_node(1)
    })
}

#[bench]
fn bench_add_edge(b: &mut test::Bencher) {
    let mut og = Graph::new();
    for _ in 0..100 {
        og.add_node(());
    }

    b.iter(|| {
        for (a, b) in og.node_indices().zip(og.node_indices().skip(1)) {
            og.add_edge(a, b, ());
        }
        og.clear_edges();
    })
}

#[bench]
fn bench_remove(b: &mut test::Bencher) {
    // removal is very slow in a big graph.
    // and this one doesn't even have many nodes.
    let mut og = Graph::new();
    let fst = og.add_node(0i32);
    let mut prev = fst;
    for x in 1..1250 {
        let n = og.add_node(x);
        og.add_edge(prev, n, ());
        prev = n;
    }
    //println!("{}", og);
    b.iter(|| {
        for _ in 0 .. 100 {
            og.remove_node(fst);
        }
    })
}
<|endoftext|>


<commit_before>// -*- rust-indent-offset: 2 -*-
// More compact, just for slides.

use std::iter::Iterator;

/// Convenient type synonym for a common pattern of usage.
/// More generally, Vec could be replaced by a Semigroup (Add).
pub type Validation<T, E> = Result<T, Vec<E>>;

#[inline]
pub fn single<T, E>(result: Result<T, E>) -> Validation<T, E> {
  result.map_err(|e| vec![e])
}

/// Combine successful results with `f`, but accumulate errors.
/// Important: any error causes the whole result to be an error!
pub fn add_with<V, T, U, E>(result1: Validation<V, E>,
                            result2: Validation<T, E>,
                            f: |V, T| -> U) -> Validation<U, E> {
  match (result1, result2) {
    (Ok(v),       Ok(t))   => Ok(f(v, t)),
    (Ok(_),       Err(e2)) => Err(e2),
    (Err(e1),     Ok(_))   => Err(e1),
    (Err(mut e1), Err(e2)) => Err({ e1.extend(e2.into_iter()); e1 })
  }
}

/// Combine a stream of Result to a Validation, accumulating successes.
pub fn combine_results<T,
                       E,
                       I>(iter: I)
  -> Validation<Vec<T>, E> where
  I: Iterator<Item = Result<T, E>>
{
  iter.map(single)
      .fold(Ok(vec![]),
            |v, t|
            add_with(v, t,
                     |mut x, y| {
                       x.push(y);
                       x
                     }))
}
<commit_msg>Have to fix for new unboxed closures.<commit_after>// -*- rust-indent-offset: 2 -*-
// More compact, just for slides.

use std::iter::Iterator;

/// Convenient type synonym for a common pattern of usage.
/// More generally, Vec could be replaced by a Semigroup (Add).
pub type Validation<T, E> = Result<T, Vec<E>>;

#[inline]
pub fn single<T, E>(result: Result<T, E>) -> Validation<T, E> {
  result.map_err(|e| vec![e])
}

/// Combine successful results with `f`, but accumulate errors.
/// Important: any error causes the whole result to be an error!
pub fn add_with<V, T, U, E, F>(result1: Validation<V, E>,
                            result2: Validation<T, E>,
                            mut f: F) -> Validation<U, E>
  where F: FnMut(V, T) -> U
{
  match (result1, result2) {
    (Ok(v),       Ok(t))   => Ok(f(v, t)),
    (Ok(_),       Err(e2)) => Err(e2),
    (Err(e1),     Ok(_))   => Err(e1),
    (Err(mut e1), Err(e2)) => Err({ e1.extend(e2.into_iter()); e1 })
  }
}

/// Combine a stream of Result to a Validation, accumulating successes.
pub fn combine_results<T,
                       E,
                       I>(iter: I)
  -> Validation<Vec<T>, E> where
  I: Iterator<Item = Result<T, E>>
{
  iter.map(single)
      .fold(Ok(vec![]),
            |v, t|
            add_with(v, t,
                     |mut x, y| {
                       x.push(y);
                       x
                     }))
}
<|endoftext|>


<commit_before>//! Source code browser

use std::collections::BTreeMap;
use std::cmp::Ordering;
use super::MetaData;
use super::page::Page;
use super::pool::Pool;
use super::file::File as DbFile;
use iron::prelude::*;
use router::Router;
use rustc_serialize::json::{Json, ToJson};
use postgres::Connection;

#[derive(PartialEq, PartialOrd)]
enum FileType {
    Dir,
    Text,
    Binary,
    RustSource,
}

#[derive(PartialEq, PartialOrd)]
struct File {
    name: String,
    file_type: FileType,
}

struct FileList {
    metadata: MetaData,
    files: Vec<File>,
}

impl ToJson for FileList {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();

        m.insert("metadata".to_string(), self.metadata.to_json());

        let mut file_vec: Vec<Json> = Vec::new();

        for file in &self.files {
            let mut file_m: BTreeMap<String, Json> = BTreeMap::new();
            file_m.insert("name".to_string(), file.name.to_json());

            file_m.insert(match file.file_type {
                              FileType::Dir => "file_type_dir".to_string(),
                              FileType::Text => "file_type_text".to_string(),
                              FileType::Binary => "file_type_binary".to_string(),
                              FileType::RustSource => "file_type_rust_source".to_string(),
                          },
                          true.to_json());

            file_vec.push(file_m.to_json());
        }

        m.insert("files".to_string(), file_vec.to_json());
        m.to_json()
    }
}

impl FileList {
    /// Gets FileList from a request path
    ///
    /// All paths stored in database have this format:
    ///
    /// ```text
    /// [
    ///   ["text/plain",".gitignore"],
    ///   ["text/x-c","src/reseeding.rs"],
    ///   ["text/x-c","src/lib.rs"],
    ///   ["text/x-c","README.md"],
    ///   ...
    /// ]
    /// ```
    ///
    /// This function is only returning FileList for requested directory. If is empty,
    /// it will return list of files (and dirs) for root directory. req_path must be a
    /// directory or empty for root directory.
    pub fn from_path(conn: &Connection,
                     name: &str,
                     version: &str,
                     req_path: &str)
                     -> Option<FileList> {

        let rows = conn.query("SELECT crates.name,
                                      releases.version,
                                      releases.description,
                                      releases.target_name,
                                      releases.rustdoc_status,
                                      releases.files
                               FROM releases
                               LEFT OUTER JOIN crates ON crates.id = releases.crate_id
                               WHERE crates.name = $1 AND releases.version = $2",
                   &[&name, &version])
            .unwrap();

        if rows.len() == 0 {
            return None;
        }

        let files: Json = rows.get(0).get_opt(5).unwrap().ok()?;

        let mut file_list: Vec<File> = Vec::new();

        files.as_array().map(|files| {
            for file in files {
                file.as_array().map(|file| {
                    let mime = file[0].as_string().unwrap();
                    let path = file[1].as_string().unwrap();

                    // skip .cargo-ok generated by cargo
                    if path == ".cargo-ok" {
                        return;
                    }

                    // look only files for req_path
                    if path.starts_with(&req_path) {
                        // remove req_path from path to reach files in this directory
                        let path = path.replace(&req_path, "");
                        let path_splited: Vec<&str> = path.split("/").collect();

                        // if path have '/' it is a directory
                        let ftype = if path_splited.len() > 1 {
                            FileType::Dir
                        } else if mime.starts_with("text") &&
                                              path_splited[0].ends_with(".rs") {
                            FileType::RustSource
                        } else if mime.starts_with("text") {
                            FileType::Text
                        } else {
                            FileType::Binary
                        };

                        let file = File {
                            name: path_splited[0].to_owned(),
                            file_type: ftype,
                        };

                        // avoid adding duplicates, a directory may occur more than once
                        if !file_list.contains(&file) {
                            file_list.push(file);
                        }
                    }
                });
            }
        });

        if file_list.is_empty() {
            return None;
        }

        file_list.sort_by(|a, b| {
            // directories must be listed first
            if a.file_type == FileType::Dir && b.file_type != FileType::Dir {
                Ordering::Less
            } else if a.file_type != FileType::Dir && b.file_type == FileType::Dir {
                Ordering::Greater
            } else {
                a.name.to_lowercase().cmp(&b.name.to_lowercase())
            }
        });

        Some(FileList {
            metadata: MetaData {
                name: rows.get(0).get(0),
                version: rows.get(0).get(1),
                description: rows.get(0).get(2),
                target_name: rows.get(0).get(3),
                rustdoc_status: rows.get(0).get(4),
            },
            files: file_list,
        })
    }
}

pub fn source_browser_handler(req: &mut Request) -> IronResult<Response> {
    let router = extension!(req, Router);
    let name = cexpect!(router.find("name"));
    let version = cexpect!(router.find("version"));

    // get path (req_path) for FileList::from_path and actual path for super::file::File::from_path
    let (req_path, file_path) = {
        let mut req_path = req.url.path();
        // remove first elements from path which is /crate/:name/:version/source
        for _ in 0..4 {
            req_path.remove(0);
        }
        let file_path = format!("sources/{}/{}/{}", name, version, req_path.join("/"));

        // FileList::from_path is only working for directories
        // remove file name if it's not a directory
        req_path.last_mut().map(|last| {
            if !last.is_empty() {
                *last = "";
            }
        });

        // remove crate name and version from req_path
        let path = req_path.join("/").replace(&format!("{}/{}/", name, version), "");

        (path, file_path)
    };

    let conn = extension!(req, Pool);

    // try to get actual file first
    // skip if request is a directory
    let file = if !file_path.ends_with("/") {
        DbFile::from_path(&conn, &file_path)
    } else {
        None
    };

    let (content, is_rust_source) = if let Some(file) = file {
        // serve the file with DatabaseFileHandler if file isn't text and not empty
        if !file.0.mime.starts_with("text") && !file.is_empty() {
            return Ok(file.serve());
        } else if file.0.mime.starts_with("text") && !file.is_empty() {
            (String::from_utf8(file.0.content).ok(), file.0.path.ends_with(".rs"))
        } else {
            (None, false)
        }
    } else {
        (None, false)
    };

    let list = FileList::from_path(&conn, &name, &version, &req_path);

    let page = Page::new(list)
        .set_bool("show_parent_link", !req_path.is_empty())
        .set_true("javascript_highlightjs")
        .set_true("show_package_navigation")
        .set_true("package_source_tab");

    if let Some(content) = content {
        page.set("file_content", &content)
            .set_bool("file_content_rust_source", is_rust_source)
            .to_resp("source")
    } else {
        page.to_resp("source")
    }
}
<commit_msg>show 404 when None is returned<commit_after>//! Source code browser

use std::collections::BTreeMap;
use std::cmp::Ordering;
use super::MetaData;
use super::page::Page;
use super::pool::Pool;
use super::file::File as DbFile;
use iron::prelude::*;
use router::Router;
use rustc_serialize::json::{Json, ToJson};
use postgres::Connection;

#[derive(PartialEq, PartialOrd)]
enum FileType {
    Dir,
    Text,
    Binary,
    RustSource,
}

#[derive(PartialEq, PartialOrd)]
struct File {
    name: String,
    file_type: FileType,
}

struct FileList {
    metadata: MetaData,
    files: Vec<File>,
}

impl ToJson for FileList {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();

        m.insert("metadata".to_string(), self.metadata.to_json());

        let mut file_vec: Vec<Json> = Vec::new();

        for file in &self.files {
            let mut file_m: BTreeMap<String, Json> = BTreeMap::new();
            file_m.insert("name".to_string(), file.name.to_json());

            file_m.insert(match file.file_type {
                              FileType::Dir => "file_type_dir".to_string(),
                              FileType::Text => "file_type_text".to_string(),
                              FileType::Binary => "file_type_binary".to_string(),
                              FileType::RustSource => "file_type_rust_source".to_string(),
                          },
                          true.to_json());

            file_vec.push(file_m.to_json());
        }

        m.insert("files".to_string(), file_vec.to_json());
        m.to_json()
    }
}

impl FileList {
    /// Gets FileList from a request path
    ///
    /// All paths stored in database have this format:
    ///
    /// ```text
    /// [
    ///   ["text/plain",".gitignore"],
    ///   ["text/x-c","src/reseeding.rs"],
    ///   ["text/x-c","src/lib.rs"],
    ///   ["text/x-c","README.md"],
    ///   ...
    /// ]
    /// ```
    ///
    /// This function is only returning FileList for requested directory. If is empty,
    /// it will return list of files (and dirs) for root directory. req_path must be a
    /// directory or empty for root directory.
    pub fn from_path(conn: &Connection,
                     name: &str,
                     version: &str,
                     req_path: &str)
                     -> Option<FileList> {

        let rows = conn.query("SELECT crates.name,
                                      releases.version,
                                      releases.description,
                                      releases.target_name,
                                      releases.rustdoc_status,
                                      releases.files
                               FROM releases
                               LEFT OUTER JOIN crates ON crates.id = releases.crate_id
                               WHERE crates.name = $1 AND releases.version = $2",
                   &[&name, &version])
            .unwrap();

        if rows.len() == 0 {
            return None;
        }

        let files: Json = rows.get(0).get_opt(5).unwrap().ok()?;

        let mut file_list: Vec<File> = Vec::new();

        files.as_array().map(|files| {
            for file in files {
                file.as_array().map(|file| {
                    let mime = file[0].as_string().unwrap();
                    let path = file[1].as_string().unwrap();

                    // skip .cargo-ok generated by cargo
                    if path == ".cargo-ok" {
                        return;
                    }

                    // look only files for req_path
                    if path.starts_with(&req_path) {
                        // remove req_path from path to reach files in this directory
                        let path = path.replace(&req_path, "");
                        let path_splited: Vec<&str> = path.split("/").collect();

                        // if path have '/' it is a directory
                        let ftype = if path_splited.len() > 1 {
                            FileType::Dir
                        } else if mime.starts_with("text") &&
                                              path_splited[0].ends_with(".rs") {
                            FileType::RustSource
                        } else if mime.starts_with("text") {
                            FileType::Text
                        } else {
                            FileType::Binary
                        };

                        let file = File {
                            name: path_splited[0].to_owned(),
                            file_type: ftype,
                        };

                        // avoid adding duplicates, a directory may occur more than once
                        if !file_list.contains(&file) {
                            file_list.push(file);
                        }
                    }
                });
            }
        });

        if file_list.is_empty() {
            return None;
        }

        file_list.sort_by(|a, b| {
            // directories must be listed first
            if a.file_type == FileType::Dir && b.file_type != FileType::Dir {
                Ordering::Less
            } else if a.file_type != FileType::Dir && b.file_type == FileType::Dir {
                Ordering::Greater
            } else {
                a.name.to_lowercase().cmp(&b.name.to_lowercase())
            }
        });

        Some(FileList {
            metadata: MetaData {
                name: rows.get(0).get(0),
                version: rows.get(0).get(1),
                description: rows.get(0).get(2),
                target_name: rows.get(0).get(3),
                rustdoc_status: rows.get(0).get(4),
            },
            files: file_list,
        })
    }
}

pub fn source_browser_handler(req: &mut Request) -> IronResult<Response> {
    let router = extension!(req, Router);
    let name = cexpect!(router.find("name"));
    let version = cexpect!(router.find("version"));

    // get path (req_path) for FileList::from_path and actual path for super::file::File::from_path
    let (req_path, file_path) = {
        let mut req_path = req.url.path();
        // remove first elements from path which is /crate/:name/:version/source
        for _ in 0..4 {
            req_path.remove(0);
        }
        let file_path = format!("sources/{}/{}/{}", name, version, req_path.join("/"));

        // FileList::from_path is only working for directories
        // remove file name if it's not a directory
        req_path.last_mut().map(|last| {
            if !last.is_empty() {
                *last = "";
            }
        });

        // remove crate name and version from req_path
        let path = req_path.join("/").replace(&format!("{}/{}/", name, version), "");

        (path, file_path)
    };

    let conn = extension!(req, Pool);

    // try to get actual file first
    // skip if request is a directory
    let file = if !file_path.ends_with("/") {
        DbFile::from_path(&conn, &file_path)
    } else {
        None
    };

    let (content, is_rust_source) = if let Some(file) = file {
        // serve the file with DatabaseFileHandler if file isn't text and not empty
        if !file.0.mime.starts_with("text") && !file.is_empty() {
            return Ok(file.serve());
        } else if file.0.mime.starts_with("text") && !file.is_empty() {
            (String::from_utf8(file.0.content).ok(), file.0.path.ends_with(".rs"))
        } else {
            (None, false)
        }
    } else {
        (None, false)
    };

    let list = FileList::from_path(&conn, &name, &version, &req_path);
    if list.is_none() {
        use iron::status;
        use super::error::Nope;
        return Err(IronError::new(Nope::NoResults, status::NotFound));
    }

    let page = Page::new(list)
        .set_bool("show_parent_link", !req_path.is_empty())
        .set_true("javascript_highlightjs")
        .set_true("show_package_navigation")
        .set_true("package_source_tab");

    if let Some(content) = content {
        page.set("file_content", &content)
            .set_bool("file_content_rust_source", is_rust_source)
            .to_resp("source")
    } else {
        page.to_resp("source")
    }
}
<|endoftext|>


<commit_before>use std::vec;
use std::slice;
use std::iter;
use std::cmp;

/// A **TrustedIterator** has exact size, always.
///
/// **Note:** TrustedIterator is *Experimental.*
pub unsafe trait TrustedIterator : ExactSizeIterator
{
    /* no methods */
}

unsafe impl TrustedIterator for ::std::ops::Range<usize> { }
unsafe impl TrustedIterator for ::std::ops::Range<u32> { }
unsafe impl TrustedIterator for ::std::ops::Range<i32> { }
unsafe impl TrustedIterator for ::std::ops::Range<u16> { }
unsafe impl TrustedIterator for ::std::ops::Range<i16> { }
unsafe impl TrustedIterator for ::std::ops::Range<u8> { }
unsafe impl TrustedIterator for ::std::ops::Range<i8> { }
unsafe impl<'a, T> TrustedIterator for slice::Iter<'a, T> { }
unsafe impl<'a, T> TrustedIterator for slice::IterMut<'a, T> { }
unsafe impl<T> TrustedIterator for vec::IntoIter<T> { }

unsafe impl<I> TrustedIterator for iter::Rev<I> where
    I: DoubleEndedIterator + TrustedIterator,
{ }
unsafe impl<I> TrustedIterator for iter::Take<I> where
    I: TrustedIterator,
{ }

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// **ZipTrusted** is an experimental version of **Zip**, and it can only use iterators that are
/// known to provide their exact size up front. The lockstep iteration can then compile to faster
/// code, ideally not checking more than once per lap for the end of iteration.
///
/// The iterator **ZipTrusted\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ## Example
///
/// ```
/// use itertools::ZipTrusted;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0, 0, 0];
/// let ys = [69, 107, 101];
///
/// for (i, a, b) in ZipTrusted::new((0..100, xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct ZipTrusted<T> {
    length: usize,
    t: T
}

trait SetLength {
    fn set_length(&mut self);
}

impl<T> ZipTrusted<T> where ZipTrusted<T>: SetLength
{
    /// Create a new **ZipTrusted** from a tuple of iterators.
    #[inline]
    pub fn new(t: T) -> ZipTrusted<T>
    {
        let mut iter = ZipTrusted {
            length: 0,
            t: t,
        };
        iter.set_length();
        iter
    }
}

macro_rules! impl_zip_trusted {
    ($($B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> SetLength for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            #[inline]
            fn set_length(&mut self)
            {
                let len = ::std::usize::MAX;
                let ($(ref $B,)*) = self.t;
                $(
                    let (l, h) = $B.size_hint();
                    let len = cmp::min(len, l);
                    debug_assert!(Some(l) == h);
                )*
                self.length = len;
            }
        }

        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            type Item = ($($B::Item,)*);

            fn next(&mut self) -> Option<Self::Item>
            {
                let ($(ref mut $B,)*) = self.t;

                if self.length == 0 {
                    return None
                }
                $(
                    let next_opt = $B.next();
                    let $B;
                    unsafe {
                        ::std::intrinsics::assume(match next_opt {
                            None => false,
                            Some(_) => true,
                        });
                        $B = match next_opt {
                            None => return None,
                            Some(elt) => elt
                        };
                    }
                )*
                self.length -= 1;
                Some(($($B,)*))
            }

            fn size_hint(&self) -> (usize, Option<usize>)
            {
                (self.length, Some(self.length))
            }
        }
    );
}

impl_zip_trusted!(A);
impl_zip_trusted!(A, B);
impl_zip_trusted!(A, B, C);
impl_zip_trusted!(A, B, C, D);
impl_zip_trusted!(A, B, C, D, E);
impl_zip_trusted!(A, B, C, D, E, F);
impl_zip_trusted!(A, B, C, D, E, F, G);
impl_zip_trusted!(A, B, C, D, E, F, G, H);
impl_zip_trusted!(A, B, C, D, E, F, G, H, I);

<commit_msg>Add ExactSizeIterator to ZipTrusted<commit_after>use std::vec;
use std::slice;
use std::iter;
use std::cmp;

/// A **TrustedIterator** has exact size, always.
///
/// **Note:** TrustedIterator is *Experimental.*
pub unsafe trait TrustedIterator : ExactSizeIterator
{
    /* no methods */
}

unsafe impl TrustedIterator for ::std::ops::Range<usize> { }
unsafe impl TrustedIterator for ::std::ops::Range<u32> { }
unsafe impl TrustedIterator for ::std::ops::Range<i32> { }
unsafe impl TrustedIterator for ::std::ops::Range<u16> { }
unsafe impl TrustedIterator for ::std::ops::Range<i16> { }
unsafe impl TrustedIterator for ::std::ops::Range<u8> { }
unsafe impl TrustedIterator for ::std::ops::Range<i8> { }
unsafe impl<'a, T> TrustedIterator for slice::Iter<'a, T> { }
unsafe impl<'a, T> TrustedIterator for slice::IterMut<'a, T> { }
unsafe impl<T> TrustedIterator for vec::IntoIter<T> { }

unsafe impl<I> TrustedIterator for iter::Rev<I> where
    I: DoubleEndedIterator + TrustedIterator,
{ }
unsafe impl<I> TrustedIterator for iter::Take<I> where
    I: TrustedIterator,
{ }

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// **ZipTrusted** is an experimental version of **Zip**, and it can only use iterators that are
/// known to provide their exact size up front. The lockstep iteration can then compile to faster
/// code, ideally not checking more than once per lap for the end of iteration.
///
/// The iterator **ZipTrusted\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ## Example
///
/// ```
/// use itertools::ZipTrusted;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0, 0, 0];
/// let ys = [69, 107, 101];
///
/// for (i, a, b) in ZipTrusted::new((0..100, xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct ZipTrusted<T> {
    length: usize,
    t: T
}

trait SetLength {
    fn set_length(&mut self);
}

impl<T> ZipTrusted<T> where ZipTrusted<T>: SetLength
{
    /// Create a new **ZipTrusted** from a tuple of iterators.
    #[inline]
    pub fn new(t: T) -> ZipTrusted<T>
    {
        let mut iter = ZipTrusted {
            length: 0,
            t: t,
        };
        iter.set_length();
        iter
    }
}

macro_rules! impl_zip_trusted {
    ($($B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> SetLength for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            #[inline]
            fn set_length(&mut self)
            {
                let len = ::std::usize::MAX;
                let ($(ref $B,)*) = self.t;
                $(
                    let (l, h) = $B.size_hint();
                    let len = cmp::min(len, l);
                    debug_assert!(Some(l) == h);
                )*
                self.length = len;
            }
        }

        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            type Item = ($($B::Item,)*);

            fn next(&mut self) -> Option<Self::Item>
            {
                let ($(ref mut $B,)*) = self.t;

                if self.length == 0 {
                    return None
                }
                $(
                    let next_opt = $B.next();
                    let $B;
                    unsafe {
                        ::std::intrinsics::assume(match next_opt {
                            None => false,
                            Some(_) => true,
                        });
                        $B = match next_opt {
                            None => return None,
                            Some(elt) => elt
                        };
                    }
                )*
                self.length -= 1;
                Some(($($B,)*))
            }

            fn size_hint(&self) -> (usize, Option<usize>)
            {
                (self.length, Some(self.length))
            }
        }

        #[allow(non_snake_case)]
        impl<$($B),*> ExactSizeIterator for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        { }
    );
}

impl_zip_trusted!(A);
impl_zip_trusted!(A, B);
impl_zip_trusted!(A, B, C);
impl_zip_trusted!(A, B, C, D);
impl_zip_trusted!(A, B, C, D, E);
impl_zip_trusted!(A, B, C, D, E, F);
impl_zip_trusted!(A, B, C, D, E, F, G);
impl_zip_trusted!(A, B, C, D, E, F, G, H);
impl_zip_trusted!(A, B, C, D, E, F, G, H, I);

<|endoftext|>