<commit_before>use crate::dpi::{LogicalPosition, LogicalSize};
use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
use crate::event::{Event, WindowEvent};
use crate::icon::Icon;
use crate::monitor::MonitorHandle as RootMH;
use crate::window::{CursorIcon, WindowAttributes, WindowId as RootWI};

use super::{backend, monitor, EventLoopWindowTarget};

use std::cell::RefCell;
use std::collections::vec_deque::IntoIter as VecDequeIter;
use std::collections::VecDeque;

pub struct Window {
    canvas: backend::Canvas,
    previous_pointer: RefCell<&'static str>,
    position: RefCell<LogicalPosition>,
}

impl Window {
    pub fn new<T>(
        target: &EventLoopWindowTarget<T>,
        attr: WindowAttributes,
        _: PlatformSpecificBuilderAttributes,
    ) -> Result<Self, RootOE> {
        let runner = target.runner.clone();

        let mut canvas = backend::Canvas::create(move || {
            runner.send_event(Event::WindowEvent {
                window_id: RootWI(Id),
                event: WindowEvent::RedrawRequested,
            })
        })?;

        target.register(&mut canvas);

        let window = Window {
            canvas,
            previous_pointer: RefCell::new("auto"),
            position: RefCell::new(LogicalPosition { x: 0.0, y: 0.0 }),
        };

        window.set_inner_size(attr.inner_size.unwrap_or(LogicalSize {
            width: 1024.0,
            height: 768.0,
        }));
        window.set_title(&attr.title);
        window.set_maximized(attr.maximized);
        window.set_visible(attr.visible);
        window.set_window_icon(attr.window_icon);

        Ok(window)
    }

    pub fn canvas(&self) -> &backend::Canvas {
        &self.canvas
    }

    pub fn set_title(&self, title: &str) {
        self.canvas.set_attribute("alt", title);
    }

    pub fn set_visible(&self, _visible: bool) {
        // Intentionally a no-op
    }

    pub fn request_redraw(&self) {
        self.canvas.request_redraw();
    }

    pub fn outer_position(&self) -> Result<LogicalPosition, NotSupportedError> {
        let (x, y) = self.canvas.position();

        Ok(LogicalPosition { x, y })
    }

    pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
        Ok(*self.position.borrow())
    }

    pub fn set_outer_position(&self, position: LogicalPosition) {
        *self.position.borrow_mut() = position;

        self.canvas.set_attribute("position", "fixed");
        self.canvas.set_attribute("left", &position.x.to_string());
        self.canvas.set_attribute("top", &position.y.to_string());
    }

    #[inline]
    pub fn inner_size(&self) -> LogicalSize {
        LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64,
        }
    }

    #[inline]
    pub fn outer_size(&self) -> LogicalSize {
        LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64,
        }
    }

    #[inline]
    pub fn set_inner_size(&self, size: LogicalSize) {
        self.canvas.set_size(size);
    }

    #[inline]
    pub fn set_min_inner_size(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_max_inner_size(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_resizable(&self, _resizable: bool) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f64 {
        1.0
    }

    #[inline]
    pub fn set_cursor_icon(&self, cursor: CursorIcon) {
        let text = match cursor {
            CursorIcon::Default => "auto",
            CursorIcon::Crosshair => "crosshair",
            CursorIcon::Hand => "pointer",
            CursorIcon::Arrow => "default",
            CursorIcon::Move => "move",
            CursorIcon::Text => "text",
            CursorIcon::Wait => "wait",
            CursorIcon::Help => "help",
            CursorIcon::Progress => "progress",

            CursorIcon::NotAllowed => "not-allowed",
            CursorIcon::ContextMenu => "context-menu",
            CursorIcon::Cell => "cell",
            CursorIcon::VerticalText => "vertical-text",
            CursorIcon::Alias => "alias",
            CursorIcon::Copy => "copy",
            CursorIcon::NoDrop => "no-drop",
            CursorIcon::Grab => "grab",
            CursorIcon::Grabbing => "grabbing",
            CursorIcon::AllScroll => "all-scroll",
            CursorIcon::ZoomIn => "zoom-in",
            CursorIcon::ZoomOut => "zoom-out",

            CursorIcon::EResize => "e-resize",
            CursorIcon::NResize => "n-resize",
            CursorIcon::NeResize => "ne-resize",
            CursorIcon::NwResize => "nw-resize",
            CursorIcon::SResize => "s-resize",
            CursorIcon::SeResize => "se-resize",
            CursorIcon::SwResize => "sw-resize",
            CursorIcon::WResize => "w-resize",
            CursorIcon::EwResize => "ew-resize",
            CursorIcon::NsResize => "ns-resize",
            CursorIcon::NeswResize => "nesw-resize",
            CursorIcon::NwseResize => "nwse-resize",
            CursorIcon::ColResize => "col-resize",
            CursorIcon::RowResize => "row-resize",
        };
        *self.previous_pointer.borrow_mut() = text;
        self.canvas.set_attribute("cursor", text);
    }

    #[inline]
    pub fn set_cursor_position(&self, _position: LogicalPosition) -> Result<(), ExternalError> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn set_cursor_grab(&self, _grab: bool) -> Result<(), ExternalError> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn set_cursor_visible(&self, visible: bool) {
        if !visible {
            self.canvas.set_attribute("cursor", "none");
        } else {
            self.canvas
                .set_attribute("cursor", *self.previous_pointer.borrow());
        }
    }

    #[inline]
    pub fn set_maximized(&self, _maximized: bool) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn fullscreen(&self) -> Option<RootMH> {
        // TODO: should there be a maximization / fullscreen API?
        None
    }

    #[inline]
    pub fn set_fullscreen(&self, _monitor: Option<RootMH>) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn set_decorations(&self, _decorations: bool) {
        // Intentionally a no-op, no canvas decorations
    }

    #[inline]
    pub fn set_always_on_top(&self, _always_on_top: bool) {
        // Intentionally a no-op, no window ordering
    }

    #[inline]
    pub fn set_window_icon(&self, _window_icon: Option<Icon>) {
        // Currently an intentional no-op
    }

    #[inline]
    pub fn set_ime_position(&self, _position: LogicalPosition) {
        // TODO: what is this?
    }

    #[inline]
    pub fn current_monitor(&self) -> RootMH {
        RootMH {
            inner: monitor::Handle,
        }
    }

    #[inline]
    pub fn available_monitors(&self) -> VecDequeIter<monitor::Handle> {
        VecDeque::new().into_iter()
    }

    #[inline]
    pub fn primary_monitor(&self) -> monitor::Handle {
        monitor::Handle
    }

    #[inline]
    pub fn id(&self) -> Id {
        // TODO ?
        unsafe { Id::dummy() }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Id;

impl Id {
    pub unsafe fn dummy() -> Id {
        Id
    }
}

#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlatformSpecificBuilderAttributes;
<commit_msg>Fix `set_cursor_icon`<commit_after>use crate::dpi::{LogicalPosition, LogicalSize};
use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
use crate::event::{Event, WindowEvent};
use crate::icon::Icon;
use crate::monitor::MonitorHandle as RootMH;
use crate::window::{CursorIcon, WindowAttributes, WindowId as RootWI};

use super::{backend, monitor, EventLoopWindowTarget};

use std::cell::RefCell;
use std::collections::vec_deque::IntoIter as VecDequeIter;
use std::collections::VecDeque;

pub struct Window {
    canvas: backend::Canvas,
    previous_pointer: RefCell<&'static str>,
    position: RefCell<LogicalPosition>,
}

impl Window {
    pub fn new<T>(
        target: &EventLoopWindowTarget<T>,
        attr: WindowAttributes,
        _: PlatformSpecificBuilderAttributes,
    ) -> Result<Self, RootOE> {
        let runner = target.runner.clone();

        let mut canvas = backend::Canvas::create(move || {
            runner.send_event(Event::WindowEvent {
                window_id: RootWI(Id),
                event: WindowEvent::RedrawRequested,
            })
        })?;

        target.register(&mut canvas);

        let window = Window {
            canvas,
            previous_pointer: RefCell::new("auto"),
            position: RefCell::new(LogicalPosition { x: 0.0, y: 0.0 }),
        };

        window.set_inner_size(attr.inner_size.unwrap_or(LogicalSize {
            width: 1024.0,
            height: 768.0,
        }));
        window.set_title(&attr.title);
        window.set_maximized(attr.maximized);
        window.set_visible(attr.visible);
        window.set_window_icon(attr.window_icon);

        Ok(window)
    }

    pub fn canvas(&self) -> &backend::Canvas {
        &self.canvas
    }

    pub fn set_title(&self, title: &str) {
        self.canvas.set_attribute("alt", title);
    }

    pub fn set_visible(&self, _visible: bool) {
        // Intentionally a no-op
    }

    pub fn request_redraw(&self) {
        self.canvas.request_redraw();
    }

    pub fn outer_position(&self) -> Result<LogicalPosition, NotSupportedError> {
        let (x, y) = self.canvas.position();

        Ok(LogicalPosition { x, y })
    }

    pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
        Ok(*self.position.borrow())
    }

    pub fn set_outer_position(&self, position: LogicalPosition) {
        *self.position.borrow_mut() = position;

        self.canvas.set_attribute("position", "fixed");
        self.canvas.set_attribute("left", &position.x.to_string());
        self.canvas.set_attribute("top", &position.y.to_string());
    }

    #[inline]
    pub fn inner_size(&self) -> LogicalSize {
        LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64,
        }
    }

    #[inline]
    pub fn outer_size(&self) -> LogicalSize {
        LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64,
        }
    }

    #[inline]
    pub fn set_inner_size(&self, size: LogicalSize) {
        self.canvas.set_size(size);
    }

    #[inline]
    pub fn set_min_inner_size(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_max_inner_size(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_resizable(&self, _resizable: bool) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f64 {
        1.0
    }

    #[inline]
    pub fn set_cursor_icon(&self, cursor: CursorIcon) {
        let text = match cursor {
            CursorIcon::Default => "auto",
            CursorIcon::Crosshair => "crosshair",
            CursorIcon::Hand => "pointer",
            CursorIcon::Arrow => "default",
            CursorIcon::Move => "move",
            CursorIcon::Text => "text",
            CursorIcon::Wait => "wait",
            CursorIcon::Help => "help",
            CursorIcon::Progress => "progress",

            CursorIcon::NotAllowed => "not-allowed",
            CursorIcon::ContextMenu => "context-menu",
            CursorIcon::Cell => "cell",
            CursorIcon::VerticalText => "vertical-text",
            CursorIcon::Alias => "alias",
            CursorIcon::Copy => "copy",
            CursorIcon::NoDrop => "no-drop",
            CursorIcon::Grab => "grab",
            CursorIcon::Grabbing => "grabbing",
            CursorIcon::AllScroll => "all-scroll",
            CursorIcon::ZoomIn => "zoom-in",
            CursorIcon::ZoomOut => "zoom-out",

            CursorIcon::EResize => "e-resize",
            CursorIcon::NResize => "n-resize",
            CursorIcon::NeResize => "ne-resize",
            CursorIcon::NwResize => "nw-resize",
            CursorIcon::SResize => "s-resize",
            CursorIcon::SeResize => "se-resize",
            CursorIcon::SwResize => "sw-resize",
            CursorIcon::WResize => "w-resize",
            CursorIcon::EwResize => "ew-resize",
            CursorIcon::NsResize => "ns-resize",
            CursorIcon::NeswResize => "nesw-resize",
            CursorIcon::NwseResize => "nwse-resize",
            CursorIcon::ColResize => "col-resize",
            CursorIcon::RowResize => "row-resize",
        };
        *self.previous_pointer.borrow_mut() = text;
        self.canvas
            .set_attribute("style", &format!("cursor: {}", text));
    }

    #[inline]
    pub fn set_cursor_position(&self, _position: LogicalPosition) -> Result<(), ExternalError> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn set_cursor_grab(&self, _grab: bool) -> Result<(), ExternalError> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn set_cursor_visible(&self, visible: bool) {
        if !visible {
            self.canvas.set_attribute("cursor", "none");
        } else {
            self.canvas
                .set_attribute("cursor", *self.previous_pointer.borrow());
        }
    }

    #[inline]
    pub fn set_maximized(&self, _maximized: bool) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn fullscreen(&self) -> Option<RootMH> {
        // TODO: should there be a maximization / fullscreen API?
        None
    }

    #[inline]
    pub fn set_fullscreen(&self, _monitor: Option<RootMH>) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn set_decorations(&self, _decorations: bool) {
        // Intentionally a no-op, no canvas decorations
    }

    #[inline]
    pub fn set_always_on_top(&self, _always_on_top: bool) {
        // Intentionally a no-op, no window ordering
    }

    #[inline]
    pub fn set_window_icon(&self, _window_icon: Option<Icon>) {
        // Currently an intentional no-op
    }

    #[inline]
    pub fn set_ime_position(&self, _position: LogicalPosition) {
        // TODO: what is this?
    }

    #[inline]
    pub fn current_monitor(&self) -> RootMH {
        RootMH {
            inner: monitor::Handle,
        }
    }

    #[inline]
    pub fn available_monitors(&self) -> VecDequeIter<monitor::Handle> {
        VecDeque::new().into_iter()
    }

    #[inline]
    pub fn primary_monitor(&self) -> monitor::Handle {
        monitor::Handle
    }

    #[inline]
    pub fn id(&self) -> Id {
        // TODO ?
        unsafe { Id::dummy() }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Id;

impl Id {
    pub unsafe fn dummy() -> Id {
        Id
    }
}

#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlatformSpecificBuilderAttributes;
<|endoftext|>


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

#![no_std]
#![no_main]

use core::{mem::MaybeUninit, panic::PanicInfo};
use sev_guest::{cpuid::CpuidPage, secrets::SecretsPage};
use x86_64::instructions::{hlt, port::PortWriteOnly};

mod asm;
mod serial;

#[link_section = ".cpuid"]
static CPUID: MaybeUninit<CpuidPage> = MaybeUninit::uninit();

#[link_section = ".secrets"]
static SECRETS: MaybeUninit<SecretsPage> = MaybeUninit::uninit();

#[no_mangle]
pub extern "C" fn rust64_start() -> ! {
    serial::init_logging();
    log::info!("Hello World!");

    // Safety: these data structures are placed in valid memory so we won't page fault when
    // accessing them and the CPU is supposed to initialize them when running under SEV-SNP. If
    // we're not running under SEV-SNP, we will read garbage from uninialized memory.
    let cpuid: &CpuidPage = unsafe { CPUID.assume_init_ref() };
    let secrets: &SecretsPage = unsafe { SECRETS.assume_init_ref() };

    log::info!("CPUID page: {:?}", cpuid);
    log::info!("Secrets page: {:?}", secrets);
    panic!();
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    // Shut down the machine via the i8042 controller.
    unsafe {
        let mut port = PortWriteOnly::new(0x64);
        port.write(0xFE_u8);
    }

    loop {
        hlt();
    }
}
<commit_msg>Use int3 instead of i8049<commit_after>//
// Copyright 2022 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#![no_std]
#![no_main]

use core::{mem::MaybeUninit, panic::PanicInfo};
use sev_guest::{cpuid::CpuidPage, secrets::SecretsPage};
use x86_64::instructions::{hlt, interrupts::int3};

mod asm;
mod serial;

#[link_section = ".cpuid"]
static CPUID: MaybeUninit<CpuidPage> = MaybeUninit::uninit();

#[link_section = ".secrets"]
static SECRETS: MaybeUninit<SecretsPage> = MaybeUninit::uninit();

#[no_mangle]
pub extern "C" fn rust64_start() -> ! {
    serial::init_logging();
    log::info!("Hello World!");

    // Safety: these data structures are placed in valid memory so we won't page fault when
    // accessing them and the CPU is supposed to initialize them when running under SEV-SNP. If
    // we're not running under SEV-SNP, we will read garbage from uninialized memory.
    let cpuid: &CpuidPage = unsafe { CPUID.assume_init_ref() };
    let secrets: &SecretsPage = unsafe { SECRETS.assume_init_ref() };

    log::info!("CPUID page: {:?}", cpuid);
    log::info!("Secrets page: {:?}", secrets);
    panic!();
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    // Trigger a breakpoint exception. As we don't have a #BP handler, this will triple fault and
    // terminate the program.
    int3();

    loop {
        hlt();
    }
}
<|endoftext|>


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

//! Capablities of the virtio video decoder device.

use std::collections::BTreeMap;

use crate::virtio::video::control::*;
use crate::virtio::video::format::*;

#[derive(Clone)]
pub struct Capability {
    in_fmts: Vec<FormatDesc>,
    out_fmts: Vec<FormatDesc>,

    // Stores supporterd profiles and levels for each format.
    profiles: BTreeMap<Format, Vec<Profile>>,
    levels: BTreeMap<Format, Vec<Level>>,
}

impl Capability {
    // Make this method pub(super) so backends can create capabilities.
    pub(super) fn new(
        in_fmts: Vec<FormatDesc>,
        out_fmts: Vec<FormatDesc>,
        profiles: BTreeMap<Format, Vec<Profile>>,
        levels: BTreeMap<Format, Vec<Level>>,
    ) -> Self {
        Self {
            in_fmts,
            out_fmts,
            profiles,
            levels,
        }
    }

    pub fn input_formats(&self) -> &Vec<FormatDesc> {
        &self.in_fmts
    }

    pub fn output_formats(&self) -> &Vec<FormatDesc> {
        &self.out_fmts
    }

    pub fn query_control(&self, t: &QueryCtrlType) -> Option<QueryCtrlResponse> {
        use QueryCtrlType::*;
        match *t {
            Profile(fmt) => {
                let profiles = self.profiles.get(&fmt)?;
                Some(QueryCtrlResponse::Profile(
                    profiles.iter().copied().collect(),
                ))
            }
            Level(fmt) => {
                let levels = self.levels.get(&fmt)?;
                Some(QueryCtrlResponse::Level(levels.iter().copied().collect()))
            }
        }
    }
}
<commit_msg>virtio-video: use to_vec() to copy &Vec<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Capablities of the virtio video decoder device.

use std::collections::BTreeMap;

use crate::virtio::video::control::*;
use crate::virtio::video::format::*;

#[derive(Clone)]
pub struct Capability {
    in_fmts: Vec<FormatDesc>,
    out_fmts: Vec<FormatDesc>,

    // Stores supporterd profiles and levels for each format.
    profiles: BTreeMap<Format, Vec<Profile>>,
    levels: BTreeMap<Format, Vec<Level>>,
}

impl Capability {
    // Make this method pub(super) so backends can create capabilities.
    pub(super) fn new(
        in_fmts: Vec<FormatDesc>,
        out_fmts: Vec<FormatDesc>,
        profiles: BTreeMap<Format, Vec<Profile>>,
        levels: BTreeMap<Format, Vec<Level>>,
    ) -> Self {
        Self {
            in_fmts,
            out_fmts,
            profiles,
            levels,
        }
    }

    pub fn input_formats(&self) -> &Vec<FormatDesc> {
        &self.in_fmts
    }

    pub fn output_formats(&self) -> &Vec<FormatDesc> {
        &self.out_fmts
    }

    pub fn query_control(&self, t: &QueryCtrlType) -> Option<QueryCtrlResponse> {
        use QueryCtrlType::*;
        match *t {
            Profile(fmt) => {
                let profiles = self.profiles.get(&fmt)?;
                Some(QueryCtrlResponse::Profile(profiles.to_vec()))
            }
            Level(fmt) => {
                let levels = self.levels.get(&fmt)?;
                Some(QueryCtrlResponse::Level(levels.to_vec()))
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt::Display;
use std::fs::{DirEntry, File};
use std::io::Read;
use std::path::{Path, PathBuf};

use diesel::backend::Backend;
use diesel::connection::BoxableConnection;
use diesel::migration::{
    self, Migration, MigrationMetadata, MigrationName, MigrationSource, MigrationVersion,
};
use migrations_internals::TomlMetadata;

use crate::errors::{MigrationError, RunMigrationsError};

/// A migration source based on a migration directory in the file system
///
/// A valid migration directroy contains a sub folder per migration.
/// Each migration folder contains a `up.sql` file containing the migration itself
/// and a `down.sql` file containing the nessesary SQL to revert the migration.
/// Additionaly each folder can contain a `metadata.toml` file controling how the
/// individual migration should be handled by the migration harness.
///
/// To embed an existing migration folder into the final binary see
/// [`embed_migrations!`](crate::embed_migrations!).
///
/// ## Example
///
/// ```text
/// # Directory Structure
/// - 20151219180527_create_users
///     - up.sql
///     - down.sql
/// - 20160107082941_create_posts
///     - up.sql
///     - down.sql
/// ```
///
/// ```sql
/// -- 20151219180527_create_users/up.sql
/// CREATE TABLE users (
///   id SERIAL PRIMARY KEY,
///   name VARCHAR NOT NULL,
///   hair_color VARCHAR
/// );
/// ```
///
/// ```sql
/// -- 20151219180527_create_users/down.sql
/// DROP TABLE users;
/// ```
///
/// ```sql
/// -- 20160107082941_create_posts/up.sql
/// CREATE TABLE posts (
///   id SERIAL PRIMARY KEY,
///   user_id INTEGER NOT NULL,
///   title VARCHAR NOT NULL,
///   body TEXT
/// );
/// ```
///
/// ```sql
/// -- 20160107082941_create_posts/down.sql
/// DROP TABLE posts;
/// ```
///
/// ```toml
/// # 20160107082941_create_posts/metadata.toml
///
/// # specifices if a migration is executed inside a
/// # transaction or not. This configuration is optional
/// # by default all migrations are run in transactions.
/// #
/// # For certain types of migrations, like creating an
/// # index onto a existing column, it is required
/// # to set this to false
/// run_in_transaction = true
/// ```
#[derive(Clone)]
pub struct FileBasedMigrations {
    base_path: PathBuf,
}

impl FileBasedMigrations {
    /// Create a new file based migration source based on a specific path
    ///
    /// This methods fails if the path passed as argument is no valid migration directory
    pub fn from_path(path: impl AsRef<Path>) -> Result<Self, MigrationError> {
        for dir in migrations_directories(path.as_ref())? {
            let path = dir?.path();
            if !migrations_internals::valid_sql_migration_directory(&path) {
                return Err(MigrationError::UnknownMigrationFormat(path));
            }
        }
        Ok(Self {
            base_path: path.as_ref().to_path_buf(),
        })
    }

    /// Create a new file based migration source by searching the migration diretcory
    ///
    /// This method looks in the current and all parent directories for a folder named
    /// `migrations`
    ///
    /// This method fails if no valid migration directory is found
    pub fn find_migrations_directory() -> Result<Self, MigrationError> {
        Self::find_migrations_directory_in_path(&std::env::current_dir()?)
    }

    /// Create a new file based migration source by searching a give path for the migration
    /// directory
    ///
    /// This method looks in the passed directory and all parent directories for a folder
    /// named `migrations`
    ///
    /// This method fails if no valid migration directory is found
    pub fn find_migrations_directory_in_path(
        path: impl AsRef<Path>,
    ) -> Result<Self, MigrationError> {
        let migrations_directory = search_for_migrations_directory(path.as_ref())?;
        Self::from_path(&migrations_directory)
    }

    #[doc(hidden)]
    pub fn path(&self) -> &Path {
        &self.base_path
    }
}

fn search_for_migrations_directory(path: &Path) -> Result<PathBuf, MigrationError> {
    migrations_internals::search_for_migrations_directory(path)
        .ok_or_else(|| MigrationError::MigrationDirectoryNotFound(path.to_path_buf()))
}

fn migrations_directories(
    path: &'_ Path,
) -> Result<impl Iterator<Item = Result<DirEntry, MigrationError>> + '_, MigrationError> {
    Ok(migrations_internals::migrations_directories(path)?.map(move |e| e.map_err(Into::into)))
}

fn migrations_in_directory<DB: Backend>(
    path: &'_ Path,
) -> Result<impl Iterator<Item = Result<SqlFileMigration, MigrationError>> + '_, MigrationError> {
    Ok(migrations_directories(path)?.map(|entry| SqlFileMigration::from_path(&entry?.path())))
}

impl<DB: Backend> MigrationSource<DB> for FileBasedMigrations {
    fn migrations(&self) -> migration::Result<Vec<Box<dyn Migration<DB>>>> {
        migrations_in_directory::<DB>(&self.base_path)?
            .map(|r| Ok(Box::new(r?) as Box<dyn Migration<DB>>))
            .collect()
    }
}

struct SqlFileMigration {
    base_path: PathBuf,
    metadata: TomlMetadataWrapper,
    name: DieselMigrationName,
}

impl SqlFileMigration {
    fn from_path(path: &Path) -> Result<Self, MigrationError> {
        if migrations_internals::valid_sql_migration_directory(path) {
            let metadata = TomlMetadataWrapper(
                TomlMetadata::read_from_file(&path.join("metadata.toml")).unwrap_or_default(),
            );
            Ok(Self {
                base_path: path.to_path_buf(),
                metadata,
                name: DieselMigrationName::from_path(path)?,
            })
        } else {
            Err(MigrationError::UnknownMigrationFormat(path.to_path_buf()))
        }
    }
}

impl<DB: Backend> Migration<DB> for SqlFileMigration {
    fn run(&self, conn: &mut dyn BoxableConnection<DB>) -> migration::Result<()> {
        Ok(run_sql_from_file(
            conn,
            &self.base_path.join("up.sql"),
            &self.name,
        )?)
    }

    fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> migration::Result<()> {
        let down_path = self.base_path.join("down.sql");
        if !matches!(down_path.metadata(), Err(e) if e.kind() == std::io::ErrorKind::NotFound) {
            Ok(run_sql_from_file(conn, &down_path, &self.name)?)
        } else {
            Err(MigrationError::NoMigrationRevertFile.into())
        }
    }

    fn metadata(&self) -> &dyn MigrationMetadata {
        &self.metadata
    }

    fn name(&self) -> &dyn MigrationName {
        &self.name
    }
}

#[derive(Debug, PartialEq)]
pub struct DieselMigrationName {
    name: String,
    version: MigrationVersion<'static>,
}

impl Clone for DieselMigrationName {
    fn clone(&self) -> Self {
        Self {
            name: self.name.clone(),
            version: self.version.as_owned(),
        }
    }
}

impl DieselMigrationName {
    fn from_path(path: &Path) -> Result<Self, MigrationError> {
        let name = path
            .file_name()
            .ok_or_else(|| MigrationError::UnknownMigrationFormat(path.to_path_buf()))?
            .to_string_lossy();
        Self::from_name(&name)
    }

    pub(crate) fn from_name(name: &str) -> Result<Self, MigrationError> {
        let version = migrations_internals::version_from_string(name)
            .ok_or_else(|| MigrationError::UnknownMigrationFormat(PathBuf::from(name)))?;
        Ok(Self {
            name: name.to_owned(),
            version: MigrationVersion::from(version),
        })
    }
}

impl MigrationName for DieselMigrationName {
    fn version(&self) -> MigrationVersion {
        self.version.as_owned()
    }
}

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

#[derive(Default)]
#[doc(hidden)]
pub struct TomlMetadataWrapper(TomlMetadata);

impl TomlMetadataWrapper {
    #[doc(hidden)]
    pub const fn new(run_in_transaction: bool) -> Self {
        Self(TomlMetadata::new(run_in_transaction))
    }
}

impl MigrationMetadata for TomlMetadataWrapper {
    fn run_in_transaction(&self) -> bool {
        self.0.run_in_transaction
    }
}

fn run_sql_from_file<DB: Backend>(
    conn: &mut dyn BoxableConnection<DB>,
    path: &Path,
    name: &DieselMigrationName,
) -> Result<(), RunMigrationsError> {
    let map_io_err = |e| RunMigrationsError::MigrationError(name.clone(), MigrationError::from(e));

    let mut sql = String::new();
    let mut file = File::open(path).map_err(map_io_err)?;
    file.read_to_string(&mut sql).map_err(map_io_err)?;

    if sql.is_empty() {
        return Err(RunMigrationsError::EmptyMigration(name.clone()));
    }

    conn.batch_execute(&sql)
        .map_err(|e| RunMigrationsError::QueryError(name.clone(), e))?;
    Ok(())
}

#[cfg(test)]
mod tests {
    extern crate tempfile;

    use super::*;

    use self::tempfile::Builder;
    use std::fs;

    #[test]
    fn migration_directory_not_found_if_no_migration_dir_exists() {
        let dir = Builder::new().prefix("diesel").tempdir().unwrap();

        assert_eq!(
            Err(MigrationError::MigrationDirectoryNotFound(
                dir.path().into()
            )),
            search_for_migrations_directory(dir.path())
        );
    }

    #[test]
    fn migration_directory_defaults_to_pwd_slash_migrations() {
        let dir = Builder::new().prefix("diesel").tempdir().unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");

        fs::create_dir(&migrations_path).unwrap();

        assert_eq!(
            Ok(migrations_path),
            search_for_migrations_directory(&temp_path)
        );
    }

    #[test]
    fn migration_directory_checks_parents() {
        let dir = Builder::new().prefix("diesel").tempdir().unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");
        let child_path = temp_path.join("child");

        fs::create_dir(&child_path).unwrap();
        fs::create_dir(&migrations_path).unwrap();

        assert_eq!(
            Ok(migrations_path),
            search_for_migrations_directory(&child_path)
        );
    }

    #[cfg(feature = "sqlite")]
    type Backend = diesel::sqlite::Sqlite;

    #[cfg(feature = "postgres")]
    type Backend = diesel::pg::Pg;

    #[cfg(feature = "mysql")]
    type Backend = diesel::mysql::Mysql;

    #[test]
    fn migration_paths_in_directory_ignores_files() {
        let dir = Builder::new().prefix("diesel").tempdir().unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");
        let file_path = migrations_path.join("README.md");

        fs::create_dir(&migrations_path).unwrap();
        fs::File::create(&file_path).unwrap();

        let migrations = migrations_in_directory::<Backend>(&migrations_path)
            .unwrap()
            .collect::<Result<Vec<_>, _>>()
            .unwrap();

        assert_eq!(0, migrations.len());
    }

    #[test]
    fn migration_paths_in_directory_ignores_dot_directories() {
        let dir = Builder::new().prefix("diesel").tempdir().unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");
        let dot_path = migrations_path.join(".hidden_dir");

        fs::create_dir(&migrations_path).unwrap();
        fs::create_dir(&dot_path).unwrap();

        let migrations = migrations_in_directory::<Backend>(&migrations_path)
            .unwrap()
            .collect::<Result<Vec<_>, _>>()
            .unwrap();

        assert_eq!(0, migrations.len());
    }
}
<commit_msg>Fix clippy<commit_after>use std::fmt::Display;
use std::fs::{DirEntry, File};
use std::io::Read;
use std::path::{Path, PathBuf};

use diesel::backend::Backend;
use diesel::connection::BoxableConnection;
use diesel::migration::{
    self, Migration, MigrationMetadata, MigrationName, MigrationSource, MigrationVersion,
};
use migrations_internals::TomlMetadata;

use crate::errors::{MigrationError, RunMigrationsError};

/// A migration source based on a migration directory in the file system
///
/// A valid migration directroy contains a sub folder per migration.
/// Each migration folder contains a `up.sql` file containing the migration itself
/// and a `down.sql` file containing the nessesary SQL to revert the migration.
/// Additionaly each folder can contain a `metadata.toml` file controling how the
/// individual migration should be handled by the migration harness.
///
/// To embed an existing migration folder into the final binary see
/// [`embed_migrations!`](crate::embed_migrations!).
///
/// ## Example
///
/// ```text
/// # Directory Structure
/// - 20151219180527_create_users
///     - up.sql
///     - down.sql
/// - 20160107082941_create_posts
///     - up.sql
///     - down.sql
/// ```
///
/// ```sql
/// -- 20151219180527_create_users/up.sql
/// CREATE TABLE users (
///   id SERIAL PRIMARY KEY,
///   name VARCHAR NOT NULL,
///   hair_color VARCHAR
/// );
/// ```
///
/// ```sql
/// -- 20151219180527_create_users/down.sql
/// DROP TABLE users;
/// ```
///
/// ```sql
/// -- 20160107082941_create_posts/up.sql
/// CREATE TABLE posts (
///   id SERIAL PRIMARY KEY,
///   user_id INTEGER NOT NULL,
///   title VARCHAR NOT NULL,
///   body TEXT
/// );
/// ```
///
/// ```sql
/// -- 20160107082941_create_posts/down.sql
/// DROP TABLE posts;
/// ```
///
/// ```toml
/// # 20160107082941_create_posts/metadata.toml
///
/// # specifices if a migration is executed inside a
/// # transaction or not. This configuration is optional
/// # by default all migrations are run in transactions.
/// #
/// # For certain types of migrations, like creating an
/// # index onto a existing column, it is required
/// # to set this to false
/// run_in_transaction = true
/// ```
#[derive(Clone)]
pub struct FileBasedMigrations {
    base_path: PathBuf,
}

impl FileBasedMigrations {
    /// Create a new file based migration source based on a specific path
    ///
    /// This methods fails if the path passed as argument is no valid migration directory
    pub fn from_path(path: impl AsRef<Path>) -> Result<Self, MigrationError> {
        for dir in migrations_directories(path.as_ref())? {
            let path = dir?.path();
            if !migrations_internals::valid_sql_migration_directory(&path) {
                return Err(MigrationError::UnknownMigrationFormat(path));
            }
        }
        Ok(Self {
            base_path: path.as_ref().to_path_buf(),
        })
    }

    /// Create a new file based migration source by searching the migration diretcory
    ///
    /// This method looks in the current and all parent directories for a folder named
    /// `migrations`
    ///
    /// This method fails if no valid migration directory is found
    pub fn find_migrations_directory() -> Result<Self, MigrationError> {
        Self::find_migrations_directory_in_path(&std::env::current_dir()?)
    }

    /// Create a new file based migration source by searching a give path for the migration
    /// directory
    ///
    /// This method looks in the passed directory and all parent directories for a folder
    /// named `migrations`
    ///
    /// This method fails if no valid migration directory is found
    pub fn find_migrations_directory_in_path(
        path: impl AsRef<Path>,
    ) -> Result<Self, MigrationError> {
        let migrations_directory = search_for_migrations_directory(path.as_ref())?;
        Self::from_path(&migrations_directory)
    }

    #[doc(hidden)]
    pub fn path(&self) -> &Path {
        &self.base_path
    }
}

fn search_for_migrations_directory(path: &Path) -> Result<PathBuf, MigrationError> {
    migrations_internals::search_for_migrations_directory(path)
        .ok_or_else(|| MigrationError::MigrationDirectoryNotFound(path.to_path_buf()))
}

fn migrations_directories(
    path: &'_ Path,
) -> Result<impl Iterator<Item = Result<DirEntry, MigrationError>> + '_, MigrationError> {
    Ok(migrations_internals::migrations_directories(path)?.map(move |e| e.map_err(Into::into)))
}

fn migrations_in_directory<DB: Backend>(
    path: &'_ Path,
) -> Result<impl Iterator<Item = Result<SqlFileMigration, MigrationError>> + '_, MigrationError> {
    Ok(migrations_directories(path)?.map(|entry| SqlFileMigration::from_path(&entry?.path())))
}

impl<DB: Backend> MigrationSource<DB> for FileBasedMigrations {
    fn migrations(&self) -> migration::Result<Vec<Box<dyn Migration<DB>>>> {
        migrations_in_directory::<DB>(&self.base_path)?
            .map(|r| Ok(Box::new(r?) as Box<dyn Migration<DB>>))
            .collect()
    }
}

struct SqlFileMigration {
    base_path: PathBuf,
    metadata: TomlMetadataWrapper,
    name: DieselMigrationName,
}

impl SqlFileMigration {
    fn from_path(path: &Path) -> Result<Self, MigrationError> {
        if migrations_internals::valid_sql_migration_directory(path) {
            let metadata = TomlMetadataWrapper(
                TomlMetadata::read_from_file(&path.join("metadata.toml")).unwrap_or_default(),
            );
            Ok(Self {
                base_path: path.to_path_buf(),
                metadata,
                name: DieselMigrationName::from_path(path)?,
            })
        } else {
            Err(MigrationError::UnknownMigrationFormat(path.to_path_buf()))
        }
    }
}

impl<DB: Backend> Migration<DB> for SqlFileMigration {
    fn run(&self, conn: &mut dyn BoxableConnection<DB>) -> migration::Result<()> {
        Ok(run_sql_from_file(
            conn,
            &self.base_path.join("up.sql"),
            &self.name,
        )?)
    }

    fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> migration::Result<()> {
        let down_path = self.base_path.join("down.sql");
        if matches!(down_path.metadata(), Err(e) if e.kind() == std::io::ErrorKind::NotFound) {
            Err(MigrationError::NoMigrationRevertFile.into())
        } else {
            Ok(run_sql_from_file(conn, &down_path, &self.name)?)
        }
    }

    fn metadata(&self) -> &dyn MigrationMetadata {
        &self.metadata
    }

    fn name(&self) -> &dyn MigrationName {
        &self.name
    }
}

#[derive(Debug, PartialEq)]
pub struct DieselMigrationName {
    name: String,
    version: MigrationVersion<'static>,
}

impl Clone for DieselMigrationName {
    fn clone(&self) -> Self {
        Self {
            name: self.name.clone(),
            version: self.version.as_owned(),
        }
    }
}

impl DieselMigrationName {
    fn from_path(path: &Path) -> Result<Self, MigrationError> {
        let name = path
            .file_name()
            .ok_or_else(|| MigrationError::UnknownMigrationFormat(path.to_path_buf()))?
            .to_string_lossy();
        Self::from_name(&name)
    }

    pub(crate) fn from_name(name: &str) -> Result<Self, MigrationError> {
        let version = migrations_internals::version_from_string(name)
            .ok_or_else(|| MigrationError::UnknownMigrationFormat(PathBuf::from(name)))?;
        Ok(Self {
            name: name.to_owned(),
            version: MigrationVersion::from(version),
        })
    }
}

impl MigrationName for DieselMigrationName {
    fn version(&self) -> MigrationVersion {
        self.version.as_owned()
    }
}

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

#[derive(Default)]
#[doc(hidden)]
pub struct TomlMetadataWrapper(TomlMetadata);

impl TomlMetadataWrapper {
    #[doc(hidden)]
    pub const fn new(run_in_transaction: bool) -> Self {
        Self(TomlMetadata::new(run_in_transaction))
    }
}

impl MigrationMetadata for TomlMetadataWrapper {
    fn run_in_transaction(&self) -> bool {
        self.0.run_in_transaction
    }
}

fn run_sql_from_file<DB: Backend>(
    conn: &mut dyn BoxableConnection<DB>,
    path: &Path,
    name: &DieselMigrationName,
) -> Result<(), RunMigrationsError> {
    let map_io_err = |e| RunMigrationsError::MigrationError(name.clone(), MigrationError::from(e));

    let mut sql = String::new();
    let mut file = File::open(path).map_err(map_io_err)?;
    file.read_to_string(&mut sql).map_err(map_io_err)?;

    if sql.is_empty() {
        return Err(RunMigrationsError::EmptyMigration(name.clone()));
    }

    conn.batch_execute(&sql)
        .map_err(|e| RunMigrationsError::QueryError(name.clone(), e))?;
    Ok(())
}

#[cfg(test)]
mod tests {
    extern crate tempfile;

    use super::*;

    use self::tempfile::Builder;
    use std::fs;

    #[test]
    fn migration_directory_not_found_if_no_migration_dir_exists() {
        let dir = Builder::new().prefix("diesel").tempdir().unwrap();

        assert_eq!(
            Err(MigrationError::MigrationDirectoryNotFound(
                dir.path().into()
            )),
            search_for_migrations_directory(dir.path())
        );
    }

    #[test]
    fn migration_directory_defaults_to_pwd_slash_migrations() {
        let dir = Builder::new().prefix("diesel").tempdir().unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");

        fs::create_dir(&migrations_path).unwrap();

        assert_eq!(
            Ok(migrations_path),
            search_for_migrations_directory(&temp_path)
        );
    }

    #[test]
    fn migration_directory_checks_parents() {
        let dir = Builder::new().prefix("diesel").tempdir().unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");
        let child_path = temp_path.join("child");

        fs::create_dir(&child_path).unwrap();
        fs::create_dir(&migrations_path).unwrap();

        assert_eq!(
            Ok(migrations_path),
            search_for_migrations_directory(&child_path)
        );
    }

    #[cfg(feature = "sqlite")]
    type Backend = diesel::sqlite::Sqlite;

    #[cfg(feature = "postgres")]
    type Backend = diesel::pg::Pg;

    #[cfg(feature = "mysql")]
    type Backend = diesel::mysql::Mysql;

    #[test]
    fn migration_paths_in_directory_ignores_files() {
        let dir = Builder::new().prefix("diesel").tempdir().unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");
        let file_path = migrations_path.join("README.md");

        fs::create_dir(&migrations_path).unwrap();
        fs::File::create(&file_path).unwrap();

        let migrations = migrations_in_directory::<Backend>(&migrations_path)
            .unwrap()
            .collect::<Result<Vec<_>, _>>()
            .unwrap();

        assert_eq!(0, migrations.len());
    }

    #[test]
    fn migration_paths_in_directory_ignores_dot_directories() {
        let dir = Builder::new().prefix("diesel").tempdir().unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");
        let dot_path = migrations_path.join(".hidden_dir");

        fs::create_dir(&migrations_path).unwrap();
        fs::create_dir(&dot_path).unwrap();

        let migrations = migrations_in_directory::<Backend>(&migrations_path)
            .unwrap()
            .collect::<Result<Vec<_>, _>>()
            .unwrap();

        assert_eq!(0, migrations.len());
    }
}
<|endoftext|>


<commit_before>use super::*;

pub struct Merge<'m, 'grammar: 'm> {
    table: &'m LaneTable<'grammar>,
    unify: &'m mut UnificationTable<StateSet>,
    states: &'m mut Vec<LR1State<'grammar>>,
}

impl<'m, 'grammar> Merge<'m, 'grammar> {
    pub fn new(
        table: &'m LaneTable<'grammar>,
        unify: &'m mut UnificationTable<StateSet>,
        states: &'m mut Vec<LR1State<'grammar>>,
    ) -> Self {
        Merge { table, unify, states }
    }

    pub fn start(&mut self, beachhead_state: StateIndex)
                 -> Result<(), StateIndex> {
        panic!("unimplemented")
    }
}

<commit_msg>some limited comments referring back to the README<commit_after>use super::*;

/// The "merge" phase of the algorithm is described in "Step 3c" of
/// [the README][r].  It consists of walking through the various
/// states in the lane table and merging them into sets of states that
/// have compatible context sets; if we encounter a state S that has a
/// successor T but where the context set of S is not compatible with
/// T, then we will clone T into a new T2 (and hopefully the context
/// set of S will be compatible with the reduced context of T2).
///
/// [r]: ../README.md
pub struct Merge<'m, 'grammar: 'm> {
    table: &'m LaneTable<'grammar>,
    unify: &'m mut UnificationTable<StateSet>,
    states: &'m mut Vec<LR1State<'grammar>>,
}

impl<'m, 'grammar> Merge<'m, 'grammar> {
    pub fn new(
        table: &'m LaneTable<'grammar>,
        unify: &'m mut UnificationTable<StateSet>,
        states: &'m mut Vec<LR1State<'grammar>>,
    ) -> Self {
        Merge { table, unify, states }
    }

    pub fn start(&mut self, beachhead_state: StateIndex)
                 -> Result<(), StateIndex> {
        panic!("unimplemented")
    }
}

<|endoftext|>


<commit_before>use url;
use std::collections;
use serde_json::{Value};
use phf;
use std::ops;

use super::helpers;
use super::scope;
use super::keywords;
use super::validators;

#[derive(Debug)]
pub struct WalkContext<'a> {
    pub url: &'a url::Url,
    pub fragment: Vec<String>,
    pub scopes: &'a mut collections::HashMap<String, Vec<String>>
}

impl<'a> WalkContext<'a> {
    pub fn escaped_fragment(&self) -> String {
        helpers::connect(self.fragment.iter().map(|s| s.as_ref()).collect::<Vec<&str>>().as_ref())
    }
}

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub enum SchemaError {
    WrongId,
    IdConflicts,
    NotAnObject,
    UrlParseError(url::ParseError),
    UnknownKey(String),
    Malformed {
        path: String,
        detail: String
    }
}

#[derive(Debug)]
pub struct ScopedSchema<'a> {
    scope: &'a scope::Scope,
    schema: &'a Schema
}

impl<'a> ops::Deref for ScopedSchema<'a> {
    type Target = Schema;

    fn deref(&self) -> &Schema {
        &self.schema
    }
}

impl<'a> ScopedSchema<'a> {
    pub fn new(scope: &'a scope::Scope, schema: &'a Schema) -> ScopedSchema<'a> {
        ScopedSchema {
            scope: scope,
            schema: schema
        }
    }

    pub fn validate(&self, data: &Value) -> validators::ValidationState {
        return self.schema.validate_in_scope(data, "", self.scope);
    }

    pub fn validate_in(&self, data: &Value, path: &str) -> validators::ValidationState {
        return self.schema.validate_in_scope(data, path, self.scope);
    }
}

#[derive(Debug)]
#[allow(dead_code)]
pub struct Schema {
    pub id: Option<url::Url>,
    schema: Option<url::Url>,
    original: Value,
    tree: collections::BTreeMap<String, Schema>,
    validators: validators::Validators,
    scopes: collections::HashMap<String, Vec<String>>
}

include!(concat!(env!("OUT_DIR"), "/codegen.rs"));

pub struct CompilationSettings<'a> {
    pub keywords: &'a keywords::KeywordMap,
    pub ban_unknown_keywords: bool
}

impl<'a> CompilationSettings<'a> {
    pub fn new(keywords: &'a keywords::KeywordMap, ban_unknown_keywords: bool) -> CompilationSettings<'a> {
        CompilationSettings {
            keywords: keywords,
            ban_unknown_keywords: ban_unknown_keywords,
        }
    }
}

impl Schema {
    fn compile(def: Value, external_id: Option<url::Url>, settings: CompilationSettings) -> Result<Schema, SchemaError> {
        let def = helpers::convert_boolean_schema(def);

        if !def.is_object() {
            return Err(SchemaError::NotAnObject)
        }

        let id = if external_id.is_some() {
            external_id.unwrap()
        } else {
            try!(helpers::parse_url_key("$id", &def)).clone().unwrap_or_else(|| helpers::generate_id())
        };

        let schema = try!(helpers::parse_url_key("$schema", &def));

        let (tree, mut scopes) = {
            let mut tree = collections::BTreeMap::new();
            let obj = def.as_object().unwrap();

            let mut scopes = collections::HashMap::new();

            for (key, value) in obj.iter() {
                if !value.is_object() && !value.is_array() && !value.is_boolean() { continue; }
                if FINAL_KEYS.contains(&key[..]) { continue; }

                let mut context = WalkContext {
                    url: &id,
                    fragment: vec![key.clone()],
                    scopes: &mut scopes
                };

                let scheme = try!(Schema::compile_sub(
                    value.clone(),
                    &mut context,
                    &settings,
                    !NON_SCHEMA_KEYS.contains(&key[..])
                ));

                tree.insert(helpers::encode(key), scheme);
            }

            (tree, scopes)
        };

        let validators = try!(Schema::compile_keywords(&def, &WalkContext {
            url: &id,
            fragment: vec![],
            scopes: &mut scopes,
        }, &settings));

        let schema = Schema {
            id: Some(id),
            schema: schema,
            original: def,
            tree: tree,
            validators: validators,
            scopes: scopes
        };

        Ok(schema)
    }

    fn compile_keywords(def: &Value, context: &WalkContext, settings: &CompilationSettings) -> Result<validators::Validators, SchemaError> {
        let mut validators = vec![];
        let mut keys: collections::HashSet<&str> = def.as_object().unwrap().keys().map(|key| key.as_ref()).collect();
        let mut not_consumed = collections::HashSet::new();

        loop {
            let key = keys.iter().next().cloned();
            if key.is_some() {
                let key = key.unwrap();
                match settings.keywords.get(&key) {
                    Some(keyword) => {
                        keyword.consume(&mut keys);

                        let is_exclusive_keyword = keyword.keyword.is_exclusive();

                        match try!(keyword.keyword.compile(def, context)) {
                            Some(validator) => {
                                if is_exclusive_keyword {
                                    validators = vec![validator];
                                } else {
                                    validators.push(validator);
                                }
                            },
                            None => ()
                        };

                        if is_exclusive_keyword {
                            break;
                        }
                    },
                    None => {
                        keys.remove(&key);
                        if settings.ban_unknown_keywords {
                            not_consumed.insert(key);
                        }
                    }
                }
            } else {
                break;
            }
        }

        if settings.ban_unknown_keywords && not_consumed.len() > 0 {
            for key in not_consumed.iter() {
                if !ALLOW_NON_CONSUMED_KEYS.contains(&key[..]) {
                    return Err(SchemaError::UnknownKey(key.to_string()))
                }
            }
        }

        Ok(validators)
    }

    fn compile_sub(def: Value, context: &mut WalkContext, keywords: &CompilationSettings, is_schema: bool) -> Result<Schema, SchemaError> {
        let def = helpers::convert_boolean_schema(def);

        let mut id = None;
        let mut schema = None;

        if is_schema {
            id = try!(helpers::parse_url_key_with_base("$id", &def, context.url));
            schema = try!(helpers::parse_url_key("$schema", &def));
        }

        let tree = {
            let mut tree = collections::BTreeMap::new();

            if def.is_object() {
                let obj = def.as_object().unwrap();
                let parent_key = &context.fragment[context.fragment.len() - 1];

                for (key, value) in obj.iter() {
                    if !value.is_object() && !value.is_array() && !value.is_boolean() { continue; }
                    if !PROPERTY_KEYS.contains(&parent_key[..]) && FINAL_KEYS.contains(&key[..]) { continue; }

                    let mut current_fragment = context.fragment.clone();
                    current_fragment.push(key.clone());

                    let is_schema = PROPERTY_KEYS.contains(&parent_key[..]) || !NON_SCHEMA_KEYS.contains(&key[..]);

                    let mut context = WalkContext {
                        url: id.as_ref().unwrap_or(context.url),
                        fragment: current_fragment,
                        scopes: context.scopes
                    };

                    let scheme = try!(Schema::compile_sub(
                        value.clone(),
                        &mut context,
                        keywords,
                        is_schema
                    ));

                    tree.insert(helpers::encode(key), scheme);
                }
            } else if def.is_array() {
                let array = def.as_array().unwrap();
                let parent_key = &context.fragment[context.fragment.len() - 1];

                for (idx, value) in array.iter().enumerate() {
                    let mut value = value.clone();

                    if BOOLEAN_SCHEMA_ARRAY_KEYS.contains(&parent_key[..]) {
                        value = helpers::convert_boolean_schema(value);
                    }

                    if !value.is_object() && !value.is_array() { continue; }

                    let mut current_fragment = context.fragment.clone();
                    current_fragment.push(idx.to_string().clone());

                    let mut context = WalkContext {
                        url: id.as_ref().unwrap_or(context.url),
                        fragment: current_fragment,
                        scopes: context.scopes
                    };

                    let scheme = try!(Schema::compile_sub(
                        value.clone(),
                        &mut context,
                        keywords,
                        true
                    ));

                    tree.insert(idx.to_string().clone(), scheme);
                }
            }

            tree
        };

        if id.is_some() {
            context.scopes.insert(id.clone().unwrap().into_string(), context.fragment.clone());
        }

        let validators = if is_schema && def.is_object() {
            try!(Schema::compile_keywords(&def, context, keywords))
        } else {
            vec![]
        };

        let schema = Schema {
            id: id,
            schema: schema,
            original: def,
            tree: tree,
            validators: validators,
            scopes: collections::HashMap::new()
        };

        Ok(schema)
    }

    pub fn resolve(&self, id: &str) -> Option<&Schema> {
        let path = self.scopes.get(id);
        path.map(|path| {
            let mut schema = self;
            for item in path.iter() {
                schema = schema.tree.get(item).unwrap()
            }
            schema
        })
    }

    pub fn resolve_fragment(&self, fragment: &str) -> Option<&Schema> {
        assert!(fragment.starts_with("/"), "Can't resolve id fragments");

        let parts = fragment[1..].split("/");
        let mut schema = self;
        for part in parts {
            match schema.tree.get(part) {
                Some(sch) => schema = sch,
                None => return None
            }
        }

        Some(schema)
    }
}

impl Schema {
    fn validate_in_scope(&self, data: &Value, path: &str, scope: &scope::Scope) -> validators::ValidationState {
        let mut state = validators::ValidationState::new();

        for validator in self.validators.iter() {
            state.append(validator.validate(data, path, scope))
        }

        state
    }
}

pub fn compile(def: Value, external_id: Option<url::Url>, settings: CompilationSettings) -> Result<Schema, SchemaError> {
    Schema::compile(def, external_id, settings)
}

#[test]
fn schema_doesnt_compile_not_object() {
    assert!(Schema::compile(json!(0), None, CompilationSettings::new(&keywords::default(), true)).is_err());
}

#[test]
fn schema_compiles_boolean_schema() {
    assert!(Schema::compile(json!(true), None, CompilationSettings::new(&keywords::default(), true)).is_ok());
}
<commit_msg>feat(json_schema): impl Error for SchemaError<commit_after>use url;
use std::collections;
use serde_json::{Value};
use phf;
use std::ops;

use super::helpers;
use super::scope;
use super::keywords;
use super::validators;
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};

#[derive(Debug)]
pub struct WalkContext<'a> {
    pub url: &'a url::Url,
    pub fragment: Vec<String>,
    pub scopes: &'a mut collections::HashMap<String, Vec<String>>
}

impl<'a> WalkContext<'a> {
    pub fn escaped_fragment(&self) -> String {
        helpers::connect(self.fragment.iter().map(|s| s.as_ref()).collect::<Vec<&str>>().as_ref())
    }
}

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub enum SchemaError {
    WrongId,
    IdConflicts,
    NotAnObject,
    UrlParseError(url::ParseError),
    UnknownKey(String),
    Malformed {
        path: String,
        detail: String
    }
}

impl Display for SchemaError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        match *self {
            SchemaError::WrongId => write!(f, "wrong id"),
            SchemaError::IdConflicts => write!(f, "id conflicts"),
            SchemaError::NotAnObject => write!(f, "not an object"),
            SchemaError::UrlParseError(ref e) => write!(f, "url parse error: {}", e),
            SchemaError::UnknownKey(ref k) => write!(f, "unknown key: {}", k),
            SchemaError::Malformed {
                ref path,
                ref detail,
            } => write!(f, "malformed path: `{}`, details: {}", path, detail),
        }
    }
}

impl Error for SchemaError {}

#[derive(Debug)]
pub struct ScopedSchema<'a> {
    scope: &'a scope::Scope,
    schema: &'a Schema
}

impl<'a> ops::Deref for ScopedSchema<'a> {
    type Target = Schema;

    fn deref(&self) -> &Schema {
        &self.schema
    }
}

impl<'a> ScopedSchema<'a> {
    pub fn new(scope: &'a scope::Scope, schema: &'a Schema) -> ScopedSchema<'a> {
        ScopedSchema {
            scope: scope,
            schema: schema
        }
    }

    pub fn validate(&self, data: &Value) -> validators::ValidationState {
        return self.schema.validate_in_scope(data, "", self.scope);
    }

    pub fn validate_in(&self, data: &Value, path: &str) -> validators::ValidationState {
        return self.schema.validate_in_scope(data, path, self.scope);
    }
}

#[derive(Debug)]
#[allow(dead_code)]
pub struct Schema {
    pub id: Option<url::Url>,
    schema: Option<url::Url>,
    original: Value,
    tree: collections::BTreeMap<String, Schema>,
    validators: validators::Validators,
    scopes: collections::HashMap<String, Vec<String>>
}

include!(concat!(env!("OUT_DIR"), "/codegen.rs"));

pub struct CompilationSettings<'a> {
    pub keywords: &'a keywords::KeywordMap,
    pub ban_unknown_keywords: bool
}

impl<'a> CompilationSettings<'a> {
    pub fn new(keywords: &'a keywords::KeywordMap, ban_unknown_keywords: bool) -> CompilationSettings<'a> {
        CompilationSettings {
            keywords: keywords,
            ban_unknown_keywords: ban_unknown_keywords,
        }
    }
}

impl Schema {
    fn compile(def: Value, external_id: Option<url::Url>, settings: CompilationSettings) -> Result<Schema, SchemaError> {
        let def = helpers::convert_boolean_schema(def);

        if !def.is_object() {
            return Err(SchemaError::NotAnObject)
        }

        let id = if external_id.is_some() {
            external_id.unwrap()
        } else {
            try!(helpers::parse_url_key("$id", &def)).clone().unwrap_or_else(|| helpers::generate_id())
        };

        let schema = try!(helpers::parse_url_key("$schema", &def));

        let (tree, mut scopes) = {
            let mut tree = collections::BTreeMap::new();
            let obj = def.as_object().unwrap();

            let mut scopes = collections::HashMap::new();

            for (key, value) in obj.iter() {
                if !value.is_object() && !value.is_array() && !value.is_boolean() { continue; }
                if FINAL_KEYS.contains(&key[..]) { continue; }

                let mut context = WalkContext {
                    url: &id,
                    fragment: vec![key.clone()],
                    scopes: &mut scopes
                };

                let scheme = try!(Schema::compile_sub(
                    value.clone(),
                    &mut context,
                    &settings,
                    !NON_SCHEMA_KEYS.contains(&key[..])
                ));

                tree.insert(helpers::encode(key), scheme);
            }

            (tree, scopes)
        };

        let validators = try!(Schema::compile_keywords(&def, &WalkContext {
            url: &id,
            fragment: vec![],
            scopes: &mut scopes,
        }, &settings));

        let schema = Schema {
            id: Some(id),
            schema: schema,
            original: def,
            tree: tree,
            validators: validators,
            scopes: scopes
        };

        Ok(schema)
    }

    fn compile_keywords(def: &Value, context: &WalkContext, settings: &CompilationSettings) -> Result<validators::Validators, SchemaError> {
        let mut validators = vec![];
        let mut keys: collections::HashSet<&str> = def.as_object().unwrap().keys().map(|key| key.as_ref()).collect();
        let mut not_consumed = collections::HashSet::new();

        loop {
            let key = keys.iter().next().cloned();
            if key.is_some() {
                let key = key.unwrap();
                match settings.keywords.get(&key) {
                    Some(keyword) => {
                        keyword.consume(&mut keys);

                        let is_exclusive_keyword = keyword.keyword.is_exclusive();

                        match try!(keyword.keyword.compile(def, context)) {
                            Some(validator) => {
                                if is_exclusive_keyword {
                                    validators = vec![validator];
                                } else {
                                    validators.push(validator);
                                }
                            },
                            None => ()
                        };

                        if is_exclusive_keyword {
                            break;
                        }
                    },
                    None => {
                        keys.remove(&key);
                        if settings.ban_unknown_keywords {
                            not_consumed.insert(key);
                        }
                    }
                }
            } else {
                break;
            }
        }

        if settings.ban_unknown_keywords && not_consumed.len() > 0 {
            for key in not_consumed.iter() {
                if !ALLOW_NON_CONSUMED_KEYS.contains(&key[..]) {
                    return Err(SchemaError::UnknownKey(key.to_string()))
                }
            }
        }

        Ok(validators)
    }

    fn compile_sub(def: Value, context: &mut WalkContext, keywords: &CompilationSettings, is_schema: bool) -> Result<Schema, SchemaError> {
        let def = helpers::convert_boolean_schema(def);

        let mut id = None;
        let mut schema = None;

        if is_schema {
            id = try!(helpers::parse_url_key_with_base("$id", &def, context.url));
            schema = try!(helpers::parse_url_key("$schema", &def));
        }

        let tree = {
            let mut tree = collections::BTreeMap::new();

            if def.is_object() {
                let obj = def.as_object().unwrap();
                let parent_key = &context.fragment[context.fragment.len() - 1];

                for (key, value) in obj.iter() {
                    if !value.is_object() && !value.is_array() && !value.is_boolean() { continue; }
                    if !PROPERTY_KEYS.contains(&parent_key[..]) && FINAL_KEYS.contains(&key[..]) { continue; }

                    let mut current_fragment = context.fragment.clone();
                    current_fragment.push(key.clone());

                    let is_schema = PROPERTY_KEYS.contains(&parent_key[..]) || !NON_SCHEMA_KEYS.contains(&key[..]);

                    let mut context = WalkContext {
                        url: id.as_ref().unwrap_or(context.url),
                        fragment: current_fragment,
                        scopes: context.scopes
                    };

                    let scheme = try!(Schema::compile_sub(
                        value.clone(),
                        &mut context,
                        keywords,
                        is_schema
                    ));

                    tree.insert(helpers::encode(key), scheme);
                }
            } else if def.is_array() {
                let array = def.as_array().unwrap();
                let parent_key = &context.fragment[context.fragment.len() - 1];

                for (idx, value) in array.iter().enumerate() {
                    let mut value = value.clone();

                    if BOOLEAN_SCHEMA_ARRAY_KEYS.contains(&parent_key[..]) {
                        value = helpers::convert_boolean_schema(value);
                    }

                    if !value.is_object() && !value.is_array() { continue; }

                    let mut current_fragment = context.fragment.clone();
                    current_fragment.push(idx.to_string().clone());

                    let mut context = WalkContext {
                        url: id.as_ref().unwrap_or(context.url),
                        fragment: current_fragment,
                        scopes: context.scopes
                    };

                    let scheme = try!(Schema::compile_sub(
                        value.clone(),
                        &mut context,
                        keywords,
                        true
                    ));

                    tree.insert(idx.to_string().clone(), scheme);
                }
            }

            tree
        };

        if id.is_some() {
            context.scopes.insert(id.clone().unwrap().into_string(), context.fragment.clone());
        }

        let validators = if is_schema && def.is_object() {
            try!(Schema::compile_keywords(&def, context, keywords))
        } else {
            vec![]
        };

        let schema = Schema {
            id: id,
            schema: schema,
            original: def,
            tree: tree,
            validators: validators,
            scopes: collections::HashMap::new()
        };

        Ok(schema)
    }

    pub fn resolve(&self, id: &str) -> Option<&Schema> {
        let path = self.scopes.get(id);
        path.map(|path| {
            let mut schema = self;
            for item in path.iter() {
                schema = schema.tree.get(item).unwrap()
            }
            schema
        })
    }

    pub fn resolve_fragment(&self, fragment: &str) -> Option<&Schema> {
        assert!(fragment.starts_with("/"), "Can't resolve id fragments");

        let parts = fragment[1..].split("/");
        let mut schema = self;
        for part in parts {
            match schema.tree.get(part) {
                Some(sch) => schema = sch,
                None => return None
            }
        }

        Some(schema)
    }
}

impl Schema {
    fn validate_in_scope(&self, data: &Value, path: &str, scope: &scope::Scope) -> validators::ValidationState {
        let mut state = validators::ValidationState::new();

        for validator in self.validators.iter() {
            state.append(validator.validate(data, path, scope))
        }

        state
    }
}

pub fn compile(def: Value, external_id: Option<url::Url>, settings: CompilationSettings) -> Result<Schema, SchemaError> {
    Schema::compile(def, external_id, settings)
}

#[test]
fn schema_doesnt_compile_not_object() {
    assert!(Schema::compile(json!(0), None, CompilationSettings::new(&keywords::default(), true)).is_err());
}

#[test]
fn schema_compiles_boolean_schema() {
    assert!(Schema::compile(json!(true), None, CompilationSettings::new(&keywords::default(), true)).is_ok());
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;
use collections::vec_deque::VecDeque;
use io::{AsyncRead,Promise};
use kobj::KObjRef;
use prelude::*;
use spin::Mutex;
use syscall::Result;

struct FlatMapShared {
    queue: Mutex<VecDeque<u8>>,
    buf_len: usize,
    collect: Box<Fn(Vec<u8>) -> Vec<u8>>,
    finished: Box<Fn(&mut Vec<u8>) -> Option<Vec<u8>>>
}

/// An adaptor which will modify the data produced by a reader.
pub struct FlatMap {
    shared: Arc<FlatMapShared>,
    input: KObjRef<AsyncRead>
}

fn read_async_inner(shared: Arc<FlatMapShared>, input: KObjRef<AsyncRead>, mut buf: Vec<u8>, len: usize) -> Promise<Result<Vec<u8>>> {
    {
        let mut queue = lock!(shared.queue);
        while buf.len() < len {
            if let Some(b) = queue.pop_front() {
                buf.push(b);
            } else {
                break;
            }
        }

        if let Some(remainder) = (shared.finished)(&mut buf) {
            queue.extend(remainder);
            return Promise::resolved(Ok(buf));
        }
        else if buf.len() >= len {
            return Promise::resolved(Ok(buf));
        }
    }

    input
        .read_async(vec![0; shared.buf_len])
        .then(move |result| {
            if let Ok(data) = result {
                let output = (shared.collect)(data);
                lock!(shared.queue).extend(output);
                read_async_inner(shared, input, buf, len)
            }
            else {
                Promise::resolved(result)
            }
        })
    .unwrap()
}

impl FlatMap {
    pub fn new<F: Fn(Vec<u8>) -> Vec<u8> + 'static, G: Fn(&mut Vec<u8>) -> Option<Vec<u8>> + 'static>(input: KObjRef<AsyncRead>, buf_len: usize, collect: F, finished: G) -> Self {
        FlatMap {
            shared: Arc::new(FlatMapShared {
                queue: Mutex::new(VecDeque::new()),
                buf_len: buf_len,
                collect: Box::new(collect),
                finished: Box::new(finished)
            }),
            input: input
        }
    }
}

impl AsyncRead for FlatMap {
    fn read_async(&self, mut buf: Vec<u8>) -> Promise<Result<Vec<u8>>> {
        let len = buf.len();
        buf.truncate(0);
        read_async_inner(self.shared.clone(), self.input.clone(), buf, len)
    }
}
<commit_msg>Return to the caller when any bytes are available<commit_after>use alloc::arc::Arc;
use collections::vec_deque::VecDeque;
use io::{AsyncRead,Promise};
use kobj::KObjRef;
use prelude::*;
use spin::Mutex;
use syscall::Result;

struct FlatMapShared {
    queue: Mutex<VecDeque<u8>>,
    buf_len: usize,
    collect: Box<Fn(Vec<u8>) -> Vec<u8>>,
    finished: Box<Fn(&mut Vec<u8>) -> Option<Vec<u8>>>
}

/// An adaptor which will modify the data produced by a reader.
pub struct FlatMap {
    shared: Arc<FlatMapShared>,
    input: KObjRef<AsyncRead>
}

fn read_async_inner(shared: Arc<FlatMapShared>, input: KObjRef<AsyncRead>, mut buf: Vec<u8>, len: usize) -> Promise<Result<Vec<u8>>> {
    {
        let mut queue = lock!(shared.queue);
        while buf.len() < len {
            if let Some(b) = queue.pop_front() {
                buf.push(b);
            } else {
                break;
            }
        }

        if let Some(remainder) = (shared.finished)(&mut buf) {
            queue.extend(remainder);
            return Promise::resolved(Ok(buf));
        }
        else if buf.len() > 0 || len == 0 {
            return Promise::resolved(Ok(buf));
        }
    }

    input
        .read_async(vec![0; shared.buf_len])
        .then(move |result| {
            if let Ok(data) = result {
                let output = (shared.collect)(data);
                lock!(shared.queue).extend(output);
                read_async_inner(shared, input, buf, len)
            }
            else {
                Promise::resolved(result)
            }
        })
    .unwrap()
}

impl FlatMap {
    pub fn new<F: Fn(Vec<u8>) -> Vec<u8> + 'static, G: Fn(&mut Vec<u8>) -> Option<Vec<u8>> + 'static>(input: KObjRef<AsyncRead>, buf_len: usize, collect: F, finished: G) -> Self {
        FlatMap {
            shared: Arc::new(FlatMapShared {
                queue: Mutex::new(VecDeque::new()),
                buf_len: buf_len,
                collect: Box::new(collect),
                finished: Box::new(finished)
            }),
            input: input
        }
    }
}

impl AsyncRead for FlatMap {
    fn read_async(&self, mut buf: Vec<u8>) -> Promise<Result<Vec<u8>>> {
        let len = buf.len();
        buf.truncate(0);
        read_async_inner(self.shared.clone(), self.input.clone(), buf, len)
    }
}
<|endoftext|>


<commit_before>use rustc_index::vec::IndexVec;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
use crate::ich::StableHashingContext;
use crate::mir::{BasicBlock, BasicBlockData, Body, LocalDecls, Location, Successors};
use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
use rustc_data_structures::graph::dominators::{dominators, Dominators};
use std::iter;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::vec::IntoIter;

#[derive(Clone, Debug)]
pub struct Cache {
    predecessors: Option<IndexVec<BasicBlock, Vec<BasicBlock>>>,
}

impl rustc_serialize::Encodable for Cache {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        Encodable::encode(&(), s)
    }
}

impl rustc_serialize::Decodable for Cache {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        Decodable::decode(d).map(|_v: ()| Self::new())
    }
}

impl<'a> HashStable<StableHashingContext<'a>> for Cache {
    fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
        // Do nothing.
    }
}

impl Cache {
    pub fn new() -> Self {
        Self {
            predecessors: None,
        }
    }

    pub fn invalidate_predecessors(&mut self) {
        // FIXME: consider being more fine-grained
        self.predecessors = None;
    }

    pub fn ensure_predecessors(&mut self, body: &Body<'_>) {
        if self.predecessors.is_none() {
            let mut result = IndexVec::from_elem(vec![], body.basic_blocks());
            for (bb, data) in body.basic_blocks().iter_enumerated() {
                if let Some(ref term) = data.terminator {
                    for &tgt in term.successors() {
                        result[tgt].push(bb);
                    }
                }
            }

            self.predecessors = Some(result)
        }
    }

    /// This will recompute the predecessors cache if it is not available
    fn predecessors(&mut self, body: &Body<'_>) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
        self.ensure_predecessors(body);
        self.predecessors.as_ref().unwrap()
    }

    fn unwrap_predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] {
        &self.predecessors.as_ref().unwrap()[bb]
    }

    fn unwrap_predecessor_locations<'a>(
        &'a self,
        loc: Location,
        body: &'a Body<'a>
    ) -> impl Iterator<Item = Location> + 'a {
        let if_zero_locations = if loc.statement_index == 0 {
            let predecessor_blocks = self.unwrap_predecessors_for(loc.block);
            let num_predecessor_blocks = predecessor_blocks.len();
            Some(
                (0..num_predecessor_blocks)
                    .map(move |i| predecessor_blocks[i])
                    .map(move |bb| body.terminator_loc(bb)),
            )
        } else {
            None
        };

        let if_not_zero_locations = if loc.statement_index == 0 {
            None
        } else {
            Some(Location { block: loc.block, statement_index: loc.statement_index - 1 })
        };

        if_zero_locations.into_iter().flatten().chain(if_not_zero_locations)
    }

    pub fn basic_blocks_mut<'a, 'tcx>(
        &mut self,
        body: &'a mut Body<'tcx>
    ) -> &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
        debug!("bbm: Clearing predecessors cache for body at: {:?}", body.span.data());
        self.invalidate_predecessors();
        &mut body.basic_blocks
    }

    pub fn basic_blocks_and_local_decls_mut<'a, 'tcx>(
        &mut self,
        body: &'a mut Body<'tcx>
    ) -> (&'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &'a mut LocalDecls<'tcx>) {
        debug!("bbaldm: Clearing predecessors cache for body at: {:?}", body.span.data());
        self.invalidate_predecessors();
        (&mut body.basic_blocks, &mut body.local_decls)
    }
}

#[derive(Clone, Debug, RustcEncodable, RustcDecodable, TypeFoldable)]
pub struct BodyCache<'tcx> {
    cache: Cache,
    body: Body<'tcx>,
}

impl BodyCache<'tcx> {
    pub fn new(body: Body<'tcx>) -> Self {
        Self {
            cache: Cache::new(),
            body,
        }
    }
}

#[macro_export]
macro_rules! read_only {
    ($body:expr) => {
        {
            $body.ensure_predecessors();
            $body.unwrap_read_only()
        }
    };
}

impl BodyCache<'tcx> {
    pub fn ensure_predecessors(&mut self) {
        self.cache.ensure_predecessors(&self.body);
    }

    pub fn predecessors(&mut self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
        self.cache.predecessors(&self.body)
    }

    pub fn unwrap_read_only(&self) -> ReadOnlyBodyCache<'_, 'tcx> {
        ReadOnlyBodyCache::new(&self.cache, &self.body)
    }

    pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
        self.cache.basic_blocks_mut(&mut self.body)
    }

    pub fn basic_blocks_and_local_decls_mut(
        &mut self
    ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
        self.cache.basic_blocks_and_local_decls_mut(&mut self.body)
    }
}

impl<'tcx> Index<BasicBlock> for BodyCache<'tcx> {
    type Output = BasicBlockData<'tcx>;

    fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
        &self.body[index]
    }
}

impl<'tcx> IndexMut<BasicBlock> for BodyCache<'tcx> {
    fn index_mut(&mut self, index: BasicBlock) -> &mut Self::Output {
        &mut self.basic_blocks_mut()[index]
    }
}

impl<'tcx> Deref for BodyCache<'tcx> {
    type Target = Body<'tcx>;

    fn deref(&self) -> &Self::Target {
        &self.body
    }
}

impl<'tcx> DerefMut for BodyCache<'tcx> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.body
    }
}

#[derive(Copy, Clone, Debug)]
pub struct ReadOnlyBodyCache<'a, 'tcx> {
    cache: &'a Cache,
    body: &'a Body<'tcx>,
}

impl ReadOnlyBodyCache<'a, 'tcx> {
    fn new(cache: &'a Cache, body: &'a Body<'tcx>) -> Self {
        assert!(
            cache.predecessors.is_some(),
            "Cannot construct ReadOnlyBodyCache without computed predecessors");
        Self {
            cache,
            body,
        }
    }

    pub fn predecessors(&self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
        self.cache.predecessors.as_ref().unwrap()
    }

    pub fn predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] {
        self.cache.unwrap_predecessors_for(bb)
    }

    pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ {
        self.cache.unwrap_predecessor_locations(loc, self.body)
    }

    pub fn body(&self) -> &'a Body<'tcx> {
        self.body
    }

    pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
        &self.body.basic_blocks
    }

    pub fn dominators(&self) -> Dominators<BasicBlock> {
        dominators(self)
    }
}

impl graph::DirectedGraph for ReadOnlyBodyCache<'a, 'tcx> {
    type Node = BasicBlock;
}

impl graph::GraphPredecessors<'graph> for ReadOnlyBodyCache<'a, 'tcx> {
    type Item = BasicBlock;
    type Iter = IntoIter<BasicBlock>;
}

impl graph::WithPredecessors for ReadOnlyBodyCache<'a, 'tcx> {
    fn predecessors(
        &self,
        node: Self::Node,
    ) -> <Self as GraphPredecessors<'_>>::Iter {
        self.cache.unwrap_predecessors_for(node).to_vec().into_iter()
    }
}

impl graph::WithNumNodes for ReadOnlyBodyCache<'a, 'tcx> {
    fn num_nodes(&self) -> usize {
        self.body.num_nodes()
    }
}

impl graph::WithStartNode for ReadOnlyBodyCache<'a, 'tcx> {
    fn start_node(&self) -> Self::Node {
        self.body.start_node()
    }
}

impl graph::WithSuccessors for ReadOnlyBodyCache<'a, 'tcx> {
    fn successors(
        &self,
        node: Self::Node,
    ) -> <Self as GraphSuccessors<'_>>::Iter {
        self.body.successors(node)
    }
}

impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyCache<'a, 'tcx> {
    type Item = BasicBlock;
    type Iter = iter::Cloned<Successors<'b>>;
}

impl Deref for ReadOnlyBodyCache<'a, 'tcx> {
    type Target = Body<'tcx>;

    fn deref(&self) -> &Self::Target {
        self.body
    }
}

impl Index<BasicBlock> for ReadOnlyBodyCache<'a, 'tcx> {
    type Output = BasicBlockData<'tcx>;

    fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
        &self.body[index]
    }
}

CloneTypeFoldableAndLiftImpls! {
    Cache,
}

impl_stable_hash_for!(struct BodyCache<'tcx> {
    cache,
    body,
});
<commit_msg>Use new HashStable proc macro<commit_after>use rustc_index::vec::IndexVec;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
use crate::ich::StableHashingContext;
use crate::mir::{BasicBlock, BasicBlockData, Body, LocalDecls, Location, Successors};
use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
use rustc_data_structures::graph::dominators::{dominators, Dominators};
use std::iter;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::vec::IntoIter;

#[derive(Clone, Debug)]
pub struct Cache {
    predecessors: Option<IndexVec<BasicBlock, Vec<BasicBlock>>>,
}

impl rustc_serialize::Encodable for Cache {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        Encodable::encode(&(), s)
    }
}

impl rustc_serialize::Decodable for Cache {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        Decodable::decode(d).map(|_v: ()| Self::new())
    }
}

impl<'a> HashStable<StableHashingContext<'a>> for Cache {
    fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
        // Do nothing.
    }
}

impl Cache {
    pub fn new() -> Self {
        Self {
            predecessors: None,
        }
    }

    pub fn invalidate_predecessors(&mut self) {
        // FIXME: consider being more fine-grained
        self.predecessors = None;
    }

    pub fn ensure_predecessors(&mut self, body: &Body<'_>) {
        if self.predecessors.is_none() {
            let mut result = IndexVec::from_elem(vec![], body.basic_blocks());
            for (bb, data) in body.basic_blocks().iter_enumerated() {
                if let Some(ref term) = data.terminator {
                    for &tgt in term.successors() {
                        result[tgt].push(bb);
                    }
                }
            }

            self.predecessors = Some(result)
        }
    }

    /// This will recompute the predecessors cache if it is not available
    fn predecessors(&mut self, body: &Body<'_>) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
        self.ensure_predecessors(body);
        self.predecessors.as_ref().unwrap()
    }

    fn unwrap_predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] {
        &self.predecessors.as_ref().unwrap()[bb]
    }

    fn unwrap_predecessor_locations<'a>(
        &'a self,
        loc: Location,
        body: &'a Body<'a>
    ) -> impl Iterator<Item = Location> + 'a {
        let if_zero_locations = if loc.statement_index == 0 {
            let predecessor_blocks = self.unwrap_predecessors_for(loc.block);
            let num_predecessor_blocks = predecessor_blocks.len();
            Some(
                (0..num_predecessor_blocks)
                    .map(move |i| predecessor_blocks[i])
                    .map(move |bb| body.terminator_loc(bb)),
            )
        } else {
            None
        };

        let if_not_zero_locations = if loc.statement_index == 0 {
            None
        } else {
            Some(Location { block: loc.block, statement_index: loc.statement_index - 1 })
        };

        if_zero_locations.into_iter().flatten().chain(if_not_zero_locations)
    }

    pub fn basic_blocks_mut<'a, 'tcx>(
        &mut self,
        body: &'a mut Body<'tcx>
    ) -> &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
        debug!("bbm: Clearing predecessors cache for body at: {:?}", body.span.data());
        self.invalidate_predecessors();
        &mut body.basic_blocks
    }

    pub fn basic_blocks_and_local_decls_mut<'a, 'tcx>(
        &mut self,
        body: &'a mut Body<'tcx>
    ) -> (&'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &'a mut LocalDecls<'tcx>) {
        debug!("bbaldm: Clearing predecessors cache for body at: {:?}", body.span.data());
        self.invalidate_predecessors();
        (&mut body.basic_blocks, &mut body.local_decls)
    }
}

#[derive(Clone, Debug, HashStable, RustcEncodable, RustcDecodable, TypeFoldable)]
pub struct BodyCache<'tcx> {
    cache: Cache,
    body: Body<'tcx>,
}

impl BodyCache<'tcx> {
    pub fn new(body: Body<'tcx>) -> Self {
        Self {
            cache: Cache::new(),
            body,
        }
    }
}

#[macro_export]
macro_rules! read_only {
    ($body:expr) => {
        {
            $body.ensure_predecessors();
            $body.unwrap_read_only()
        }
    };
}

impl BodyCache<'tcx> {
    pub fn ensure_predecessors(&mut self) {
        self.cache.ensure_predecessors(&self.body);
    }

    pub fn predecessors(&mut self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
        self.cache.predecessors(&self.body)
    }

    pub fn unwrap_read_only(&self) -> ReadOnlyBodyCache<'_, 'tcx> {
        ReadOnlyBodyCache::new(&self.cache, &self.body)
    }

    pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
        self.cache.basic_blocks_mut(&mut self.body)
    }

    pub fn basic_blocks_and_local_decls_mut(
        &mut self
    ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
        self.cache.basic_blocks_and_local_decls_mut(&mut self.body)
    }
}

impl<'tcx> Index<BasicBlock> for BodyCache<'tcx> {
    type Output = BasicBlockData<'tcx>;

    fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
        &self.body[index]
    }
}

impl<'tcx> IndexMut<BasicBlock> for BodyCache<'tcx> {
    fn index_mut(&mut self, index: BasicBlock) -> &mut Self::Output {
        &mut self.basic_blocks_mut()[index]
    }
}

impl<'tcx> Deref for BodyCache<'tcx> {
    type Target = Body<'tcx>;

    fn deref(&self) -> &Self::Target {
        &self.body
    }
}

impl<'tcx> DerefMut for BodyCache<'tcx> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.body
    }
}

#[derive(Copy, Clone, Debug)]
pub struct ReadOnlyBodyCache<'a, 'tcx> {
    cache: &'a Cache,
    body: &'a Body<'tcx>,
}

impl ReadOnlyBodyCache<'a, 'tcx> {
    fn new(cache: &'a Cache, body: &'a Body<'tcx>) -> Self {
        assert!(
            cache.predecessors.is_some(),
            "Cannot construct ReadOnlyBodyCache without computed predecessors");
        Self {
            cache,
            body,
        }
    }

    pub fn predecessors(&self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
        self.cache.predecessors.as_ref().unwrap()
    }

    pub fn predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] {
        self.cache.unwrap_predecessors_for(bb)
    }

    pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ {
        self.cache.unwrap_predecessor_locations(loc, self.body)
    }

    pub fn body(&self) -> &'a Body<'tcx> {
        self.body
    }

    pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
        &self.body.basic_blocks
    }

    pub fn dominators(&self) -> Dominators<BasicBlock> {
        dominators(self)
    }
}

impl graph::DirectedGraph for ReadOnlyBodyCache<'a, 'tcx> {
    type Node = BasicBlock;
}

impl graph::GraphPredecessors<'graph> for ReadOnlyBodyCache<'a, 'tcx> {
    type Item = BasicBlock;
    type Iter = IntoIter<BasicBlock>;
}

impl graph::WithPredecessors for ReadOnlyBodyCache<'a, 'tcx> {
    fn predecessors(
        &self,
        node: Self::Node,
    ) -> <Self as GraphPredecessors<'_>>::Iter {
        self.cache.unwrap_predecessors_for(node).to_vec().into_iter()
    }
}

impl graph::WithNumNodes for ReadOnlyBodyCache<'a, 'tcx> {
    fn num_nodes(&self) -> usize {
        self.body.num_nodes()
    }
}

impl graph::WithStartNode for ReadOnlyBodyCache<'a, 'tcx> {
    fn start_node(&self) -> Self::Node {
        self.body.start_node()
    }
}

impl graph::WithSuccessors for ReadOnlyBodyCache<'a, 'tcx> {
    fn successors(
        &self,
        node: Self::Node,
    ) -> <Self as GraphSuccessors<'_>>::Iter {
        self.body.successors(node)
    }
}

impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyCache<'a, 'tcx> {
    type Item = BasicBlock;
    type Iter = iter::Cloned<Successors<'b>>;
}

impl Deref for ReadOnlyBodyCache<'a, 'tcx> {
    type Target = Body<'tcx>;

    fn deref(&self) -> &Self::Target {
        self.body
    }
}

impl Index<BasicBlock> for ReadOnlyBodyCache<'a, 'tcx> {
    type Output = BasicBlockData<'tcx>;

    fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
        &self.body[index]
    }
}

CloneTypeFoldableAndLiftImpls! {
    Cache,
}
<|endoftext|>