<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

pub use autocxx_engine::Error as EngineError;
pub use autocxx_engine::ParseError;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use tempfile::{tempdir, TempDir};

/// Errors returned during creation of a cc::Build from an include_cxx
/// macro.
#[derive(Debug)]
pub enum Error {
    /// The cxx module couldn't parse the code generated by autocxx.
    /// This could well be a bug in autocxx.
    InvalidCxx(EngineError),
    /// The .rs file didn't exist or couldn't be parsed.
    ParseError(ParseError),
    /// We couldn't create a temporary directory to store the c++ code.
    TempDirCreationFailed(std::io::Error),
    /// We couldn't write the c++ code to disk.
    FileWriteFail(std::io::Error),
    /// No `include_cxx` macro was found anywhere.
    NoIncludeCxxMacrosFound,
    /// Problem converting the `AUTOCXX_INC` environment variable
    /// to a set of canonical paths.
    IncludeDirProblem(EngineError),
}

/// Structure for use in a build.rs file to aid with conversion
/// of a `include_cxx!` macro into a `cc::Build`.
/// This structure owns a temporary directory containing
/// the generated C++ code, as well as owning the cc::Build
/// which knows how to build it.
/// Typically you'd use this from a build.rs file by
/// using `new` and then using `builder` to fetch the `cc::Build`
/// object and asking the resultant `cc::Build` to compile the code.
/// You'll also need to set the `AUTOCXX_INC` environment variable
/// to specify the path for finding header files.
pub struct Builder {
    build: cc::Build,
    _tdir: TempDir,
}

impl Builder {
    /// Construct a Builder.
    pub fn new<P1: AsRef<Path>>(rs_file: P1, autocxx_inc: &str) -> Result<Self, Error> {
        // TODO - we have taken a different approach here from cxx.
        // cxx jumps through many (probably very justifiable) hoops
        // to generate .h and .cxx files in the Cargo out directory
        // (I think). We cheat and just make a temp dir. We shouldn't.
        let tdir = tempdir().map_err(Error::TempDirCreationFailed)?;
        let mut builder = cc::Build::new();
        builder.cpp(true);
        let autocxxes =
            autocxx_engine::parse_file(rs_file, Some(autocxx_inc)).map_err(Error::ParseError)?;
        let mut counter = 0;
        for include_cpp in autocxxes {
            for inc_dir in include_cpp
                .include_dirs()
                .map_err(Error::IncludeDirProblem)?
            {
                builder.include(inc_dir);
            }
            let generated_code = include_cpp
                .generate_h_and_cxx()
                .map_err(Error::InvalidCxx)?;
            for filepair in generated_code.0 {
                let fname = format!("gen{}.cxx", counter);
                counter += 1;
                let gen_cxx_path = Self::write_to_file(&tdir, &fname, &filepair.implementation)
                    .map_err(Error::FileWriteFail)?;
                builder.file(gen_cxx_path);

                Self::write_to_file(&tdir, &filepair.header_name, &filepair.header)
                    .map_err(Error::FileWriteFail)?;
            }
        }
        if counter == 0 {
            Err(Error::NoIncludeCxxMacrosFound)
        } else {
            Ok(Builder {
                build: builder,
                _tdir: tdir,
            })
        }
    }

    /// Fetch the cc::Build from this.
    pub fn builder(&mut self) -> &mut cc::Build {
        &mut self.build
    }

    fn write_to_file(tdir: &TempDir, filename: &str, content: &[u8]) -> std::io::Result<PathBuf> {
        let path = tdir.path().join(filename);
        let mut f = File::create(&path)?;
        f.write_all(content)?;
        Ok(path)
    }
}
<commit_msg>Write cxx.h to temp dir when using builder.<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

pub use autocxx_engine::Error as EngineError;
pub use autocxx_engine::ParseError;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use tempfile::{tempdir, TempDir};

/// Errors returned during creation of a cc::Build from an include_cxx
/// macro.
#[derive(Debug)]
pub enum Error {
    /// The cxx module couldn't parse the code generated by autocxx.
    /// This could well be a bug in autocxx.
    InvalidCxx(EngineError),
    /// The .rs file didn't exist or couldn't be parsed.
    ParseError(ParseError),
    /// We couldn't create a temporary directory to store the c++ code.
    TempDirCreationFailed(std::io::Error),
    /// We couldn't write the c++ code to disk.
    FileWriteFail(std::io::Error),
    /// No `include_cxx` macro was found anywhere.
    NoIncludeCxxMacrosFound,
    /// Problem converting the `AUTOCXX_INC` environment variable
    /// to a set of canonical paths.
    IncludeDirProblem(EngineError),
}

/// Structure for use in a build.rs file to aid with conversion
/// of a `include_cxx!` macro into a `cc::Build`.
/// This structure owns a temporary directory containing
/// the generated C++ code, as well as owning the cc::Build
/// which knows how to build it.
/// Typically you'd use this from a build.rs file by
/// using `new` and then using `builder` to fetch the `cc::Build`
/// object and asking the resultant `cc::Build` to compile the code.
/// You'll also need to set the `AUTOCXX_INC` environment variable
/// to specify the path for finding header files.
pub struct Builder {
    build: cc::Build,
    _tdir: TempDir,
}

impl Builder {
    /// Construct a Builder.
    pub fn new<P1: AsRef<Path>>(rs_file: P1, autocxx_inc: &str) -> Result<Self, Error> {
        // TODO - we have taken a different approach here from cxx.
        // cxx jumps through many (probably very justifiable) hoops
        // to generate .h and .cxx files in the Cargo out directory
        // (I think). We cheat and just make a temp dir. We shouldn't.
        let tdir = tempdir().map_err(Error::TempDirCreationFailed)?;
        let mut builder = cc::Build::new();
        builder.cpp(true);
        // Write cxx.h to that location, as it may be needed by
        // some of our generated code.
        Self::write_to_file(
            &tdir,
            "cxx.h",
            autocxx_engine::HEADER.as_bytes(),
        )
        .map_err(Error::FileWriteFail)?;
        let autocxx_inc = Self::append_extra_path(autocxx_inc, tdir.path().to_path_buf());
        let autocxxes =
            autocxx_engine::parse_file(rs_file, Some(&autocxx_inc)).map_err(Error::ParseError)?;
        let mut counter = 0;
        for include_cpp in autocxxes {
            for inc_dir in include_cpp
                .include_dirs()
                .map_err(Error::IncludeDirProblem)?
            {
                builder.include(inc_dir);
            }
            let generated_code = include_cpp
                .generate_h_and_cxx()
                .map_err(Error::InvalidCxx)?;
            for filepair in generated_code.0 {
                let fname = format!("gen{}.cxx", counter);
                counter += 1;
                let gen_cxx_path = Self::write_to_file(&tdir, &fname, &filepair.implementation)
                    .map_err(Error::FileWriteFail)?;
                builder.file(gen_cxx_path);

                Self::write_to_file(&tdir, &filepair.header_name, &filepair.header)
                    .map_err(Error::FileWriteFail)?;
            }
        }
        if counter == 0 {
            Err(Error::NoIncludeCxxMacrosFound)
        } else {
            Ok(Builder {
                build: builder,
                _tdir: tdir,
            })
        }
    }

    fn append_extra_path(path_list: &str, extra_path: PathBuf) -> String {
        let mut paths = std::env::split_paths(&path_list).collect::<Vec<_>>();
        paths.push(extra_path);
        std::env::join_paths(paths)
            .unwrap()
            .to_str()
            .unwrap()
            .to_string()
    }

    /// Fetch the cc::Build from this.
    pub fn builder(&mut self) -> &mut cc::Build {
        &mut self.build
    }

    fn write_to_file(tdir: &TempDir, filename: &str, content: &[u8]) -> std::io::Result<PathBuf> {
        let path = tdir.path().join(filename);
        let mut f = File::create(&path)?;
        f.write_all(content)?;
        Ok(path)
    }
}
<|endoftext|>


<commit_before>#![feature(asm)]

fn not_in_miri() -> i32 {
    // Inline assembly definitely does not work in Miri.
    let dummy = 42;
    unsafe {
        asm!("" : : "r"(&dummy));
    }
    return dummy;
}

fn main() {
    not_in_miri();
    println!("cargo:rerun-if-changed=build.rs");
}
<commit_msg>adjust for asm -> llvm_asm rename<commit_after>#![feature(llvm_asm)]

fn not_in_miri() -> i32 {
    // Inline assembly definitely does not work in Miri.
    let dummy = 42;
    unsafe {
        llvm_asm!("" : : "r"(&dummy));
    }
    return dummy;
}

fn main() {
    not_in_miri();
    println!("cargo:rerun-if-changed=build.rs");
}
<|endoftext|>


<commit_before>//! SEGIMAP is an IMAP server implementation.
#![deny(non_camel_case_types)]
#![cfg_attr(feature = "unstable", feature(test))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

extern crate bufstream;
extern crate crypto;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate mime;
#[macro_use]
extern crate nom;
extern crate num;
extern crate openssl;
extern crate rand;
extern crate regex;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate time;
extern crate toml;
extern crate walkdir;

use server::{lmtp_serve, imap_serve, Server};

use std::net::TcpListener;
use std::sync::Arc;
use std::thread::spawn;

mod command;
mod error;
mod folder;
mod parser;
#[macro_use]
mod util;
#[macro_use]
mod server;
mod message;

fn listen_lmtp(v: TcpListener, serv: Arc<Server>) {
    for stream in v.incoming() {
        match stream {
            Err(e) => {
                error!("Error accepting incoming LMTP connection: {}", e);
            }
            Ok(stream) => {
                let session_serv = serv.clone();
                spawn(move || { lmtp_serve(session_serv, stream) });
            }
        }
    }
}

fn listen_imap(v: TcpListener, serv: Arc<Server>) {
    for stream in v.incoming() {
        match stream {
            Err(e) => { error!("Error accepting incoming IMAP connection: {}", e) }
            Ok(stream) => {
                let session_serv = serv.clone();
                spawn(move || { imap_serve(session_serv, stream) });
            }
        }
    }
}

fn main() {
    let _ = env_logger::init().unwrap();
    info!("Application started");

    // Create the server. We wrap it so that it is atomically reference
    // counted. This allows us to safely share it across threads

    let serv = match Server::new() {
        Err(e) => {
            error!("Error starting server: {}", e);
            return;
        },
        Ok(s) => Arc::new(s)
    };

    // Spawn a separate thread for listening for LMTP connections
    let lmtp_h = if let Some(lmtp_listener) = serv.lmtp_listener() {
        match lmtp_listener {
            Err(e) => {
                error!("Error listening on LMTP port: {}", e);
                None
            }
            Ok(v) => {
                let lmtp_serv = serv.clone();
                Some(spawn(move || listen_lmtp(v, lmtp_serv)))
            }
        }
    } else { None };

    let lmtp_ssl_h = if let Some(lmtp_listener) = serv.lmtp_ssl_listener() {
        match lmtp_listener {
            Err(e) => {
                error!("Error listening on LMTP SSL port: {}", e);
                None
            }
            Ok(v) => {
                let lmtp_serv = serv.clone();
                Some(spawn(move || listen_lmtp(v, lmtp_serv)))
            }
        }
    } else { None };

    // The main thread handles listening for IMAP connections
    let imap_h = if let Some(imap_listener) = serv.imap_listener() {
        match imap_listener {
            Err(e) => {
                error!("Error listening on IMAP port: {}", e);
                None
            }
            Ok(v) => {
                let imap_serv = serv.clone();
                Some(spawn(move || listen_imap(v, imap_serv)))
            }
        }
    } else { None };

    let imap_ssl_h = if let Some(imap_listener) = serv.imap_ssl_listener() {
        match imap_listener {
            Err(e) => {
                error!("Error listening on IMAP port: {}", e);
                None
            }
            Ok(v) => {
                Some(spawn(move || listen_imap(v, serv)))
            }
        }
    } else { None };

    if let Some(lh) = lmtp_h {
        return_on_err!(lh.join());
    }

    if let Some(lsh) = lmtp_ssl_h {
        return_on_err!(lsh.join());
    }

    if let Some(ih) = imap_h {
        return_on_err!(ih.join());
    }

    if let Some(ish) = imap_ssl_h {
        return_on_err!(ish.join());
    }
}
<commit_msg>Minor refactor for listen loop<commit_after>//! SEGIMAP is an IMAP server implementation.
#![deny(non_camel_case_types)]
#![cfg_attr(feature = "unstable", feature(test))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

extern crate bufstream;
extern crate crypto;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate mime;
#[macro_use]
extern crate nom;
extern crate num;
extern crate openssl;
extern crate rand;
extern crate regex;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate time;
extern crate toml;
extern crate walkdir;

use server::{lmtp_serve, imap_serve, Server};

use std::net::{TcpListener, TcpStream};
use std::sync::Arc;
use std::thread::spawn;

mod command;
mod error;
mod folder;
mod parser;
#[macro_use]
mod util;
#[macro_use]
mod server;
mod message;

fn listen_generic(v: TcpListener, serv: Arc<Server>, prot: &str, serve_func: (fn(Arc<Server>, TcpStream))) {
    for stream in v.incoming() {
        match stream {
            Err(e) => {
                error!("Error accepting incoming {} connection: {}", prot, e);
            }
            Ok(stream) => {
                let session_serv = serv.clone();
                spawn(move || { serve_func(session_serv, stream) });
            }
        }
    }
}

fn listen_lmtp(v: TcpListener, serv: Arc<Server>) {
    listen_generic(v, serv, "LMTP", lmtp_serve);
}

fn listen_imap(v: TcpListener, serv: Arc<Server>) {
    listen_generic(v, serv, "IMAP", imap_serve);
}

fn main() {
    let _ = env_logger::init().unwrap();
    info!("Application started");

    // Create the server. We wrap it so that it is atomically reference
    // counted. This allows us to safely share it across threads

    let serv = match Server::new() {
        Err(e) => {
            error!("Error starting server: {}", e);
            return;
        },
        Ok(s) => Arc::new(s)
    };

    // Spawn a separate thread for listening for LMTP connections
    let lmtp_h = if let Some(lmtp_listener) = serv.lmtp_listener() {
        match lmtp_listener {
            Err(e) => {
                error!("Error listening on LMTP port: {}", e);
                None
            }
            Ok(v) => {
                let lmtp_serv = serv.clone();
                Some(spawn(move || listen_lmtp(v, lmtp_serv)))
            }
        }
    } else { None };

    let lmtp_ssl_h = if let Some(lmtp_listener) = serv.lmtp_ssl_listener() {
        match lmtp_listener {
            Err(e) => {
                error!("Error listening on LMTP SSL port: {}", e);
                None
            }
            Ok(v) => {
                let lmtp_serv = serv.clone();
                Some(spawn(move || listen_lmtp(v, lmtp_serv)))
            }
        }
    } else { None };

    // The main thread handles listening for IMAP connections
    let imap_h = if let Some(imap_listener) = serv.imap_listener() {
        match imap_listener {
            Err(e) => {
                error!("Error listening on IMAP port: {}", e);
                None
            }
            Ok(v) => {
                let imap_serv = serv.clone();
                Some(spawn(move || listen_imap(v, imap_serv)))
            }
        }
    } else { None };

    let imap_ssl_h = if let Some(imap_listener) = serv.imap_ssl_listener() {
        match imap_listener {
            Err(e) => {
                error!("Error listening on IMAP port: {}", e);
                None
            }
            Ok(v) => {
                Some(spawn(move || listen_imap(v, serv)))
            }
        }
    } else { None };

    if let Some(lh) = lmtp_h {
        return_on_err!(lh.join());
    }

    if let Some(lsh) = lmtp_ssl_h {
        return_on_err!(lsh.join());
    }

    if let Some(ih) = imap_h {
        return_on_err!(ih.join());
    }

    if let Some(ish) = imap_ssl_h {
        return_on_err!(ish.join());
    }
}
<|endoftext|>


<commit_before>use std::marker;
use std::sync::Arc;
use std::sync::Mutex;

use futures::future;

use std::future::Future;

use crate::error;
use crate::misc::any_to_string;
use crate::result;
use futures::FutureExt;
use std::panic::AssertUnwindSafe;

pub(crate) trait DiedType: Default + Clone + Send {
    fn what() -> &'static str;
}

#[derive(Copy, Clone, Default)]
pub(crate) struct ClientDiedType;
#[derive(Copy, Clone, Default)]
pub(crate) struct ConnDiedType;

impl DiedType for ClientDiedType {
    fn what() -> &'static str {
        "client"
    }
}

impl DiedType for ConnDiedType {
    fn what() -> &'static str {
        "connection"
    }
}

#[derive(Default, Clone)]
pub(crate) struct SomethingDiedErrorHolder<D: DiedType> {
    error: Arc<Mutex<Option<Arc<error::Error>>>>,
    _marker: marker::PhantomData<D>,
}

impl<D: DiedType> SomethingDiedErrorHolder<D> {
    pub fn new() -> Self {
        Default::default()
    }

    fn client_died_error(&self) -> Arc<error::Error> {
        let lock = self.error.lock().unwrap();
        (*lock)
            .clone()
            .unwrap_or_else(|| Arc::new(crate::Error::DeathReasonUnknown))
    }

    pub fn error(&self) -> error::Error {
        error::Error::ClientDied(self.client_died_error())
    }

    fn set_once(&self, error: error::Error) {
        let mut lock = self.error.lock().unwrap();
        if (*lock).is_none() {
            *lock = Some(Arc::new(error));
        }
    }

    pub fn wrap_future<F>(&self, future: F) -> impl Future<Output = ()> + Send
    where
        F: Future<Output = result::Result<()>> + Send,
    {
        let holder = self.clone();
        let future = future.then(move |r| {
            match r {
                Ok(()) => {
                    info!("{} completed without errors", D::what());
                    holder.set_once(error::Error::ClientCompletedWithoutError);
                }
                Err(e) => {
                    warn!("{} completed with error: {:?}", D::what(), e);
                    holder.set_once(e);
                }
            }
            future::ok::<(), ()>(())
        });

        let holder = self.clone();
        let future = AssertUnwindSafe(future).catch_unwind().then(move |r| {
            if let Err(e) = r {
                let message = any_to_string(e);
                warn!("{} panicked: {}", D::what(), message);
                holder.set_once(error::Error::ClientPanicked(message));
            }
            future::ready(())
        });

        future
    }
}
<commit_msg>Slightly simplify SomethingDiedErrorHolder::wrap_future<commit_after>use std::marker;
use std::sync::Arc;
use std::sync::Mutex;

use futures::future;

use std::future::Future;

use crate::error;
use crate::misc::any_to_string;
use crate::result;
use futures::FutureExt;
use std::panic::AssertUnwindSafe;

pub(crate) trait DiedType: Default + Clone + Send {
    fn what() -> &'static str;
}

#[derive(Copy, Clone, Default)]
pub(crate) struct ClientDiedType;
#[derive(Copy, Clone, Default)]
pub(crate) struct ConnDiedType;

impl DiedType for ClientDiedType {
    fn what() -> &'static str {
        "client"
    }
}

impl DiedType for ConnDiedType {
    fn what() -> &'static str {
        "connection"
    }
}

#[derive(Default, Clone)]
pub(crate) struct SomethingDiedErrorHolder<D: DiedType> {
    error: Arc<Mutex<Option<Arc<error::Error>>>>,
    _marker: marker::PhantomData<D>,
}

impl<D: DiedType> SomethingDiedErrorHolder<D> {
    pub fn new() -> Self {
        Default::default()
    }

    fn client_died_error(&self) -> Arc<error::Error> {
        let lock = self.error.lock().unwrap();
        (*lock)
            .clone()
            .unwrap_or_else(|| Arc::new(crate::Error::DeathReasonUnknown))
    }

    pub fn error(&self) -> error::Error {
        error::Error::ClientDied(self.client_died_error())
    }

    fn set_once(&self, error: error::Error) {
        let mut lock = self.error.lock().unwrap();
        if (*lock).is_none() {
            *lock = Some(Arc::new(error));
        }
    }

    pub fn wrap_future<F>(&self, future: F) -> impl Future<Output = ()> + Send
    where
        F: Future<Output = result::Result<()>> + Send,
    {
        let holder = self.clone();
        let future = future.then(move |r| {
            match r {
                Ok(()) => {
                    info!("{} completed without errors", D::what());
                    holder.set_once(error::Error::ClientCompletedWithoutError);
                }
                Err(e) => {
                    warn!("{} completed with error: {:?}", D::what(), e);
                    holder.set_once(e);
                }
            }
            future::ready(())
        });

        let holder = self.clone();
        let future = AssertUnwindSafe(future).catch_unwind().then(move |r| {
            match r {
                Err(e) => {
                    let message = any_to_string(e);
                    warn!("{} panicked: {}", D::what(), message);
                    holder.set_once(error::Error::ClientPanicked(message));
                }
                Ok(()) => {}
            }
            future::ready(())
        });

        future
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::common::utils::create_dir_if_not_exist;
use crate::{
    common::{
        types::{CliError, CliTypedResult},
        utils::write_to_file,
    },
    CliCommand,
};
use aptos_config::config::Token;
use aptos_genesis::config::Layout;
use aptos_github_client::Client as GithubClient;
use async_trait::async_trait;
use clap::Parser;
use framework::ReleaseBundle;
use serde::{de::DeserializeOwned, Serialize};
use std::path::Path;
use std::{fmt::Debug, io::Read, path::PathBuf, str::FromStr};

pub const LAYOUT_FILE: &str = "layout.yaml";
pub const OPERATOR_FILE: &str = "operator.yaml";
pub const OWNER_FILE: &str = "owner.yaml";
pub const FRAMEWORK_NAME: &str = "framework.mrb";
pub const BALANCES_FILE: &str = "balances.yaml";
pub const EMPLOYEE_VESTING_ACCOUNTS_FILE: &str = "employee_vesting_accounts.yaml";

/// Setup a shared Git repository for Genesis
///
/// This will setup a folder or an online Github repository to be used
/// for Genesis.  If it's the local, it will create the folders but not
/// set up a Git repository.
#[derive(Parser)]
pub struct SetupGit {
    #[clap(flatten)]
    pub(crate) git_options: GitOptions,

    /// Path to the `Layout` file which defines where all the files are
    #[clap(long, parse(from_os_str))]
    pub(crate) layout_file: PathBuf,
}

#[async_trait]
impl CliCommand<()> for SetupGit {
    fn command_name(&self) -> &'static str {
        "SetupGit"
    }

    async fn execute(self) -> CliTypedResult<()> {
        let layout = Layout::from_disk(&self.layout_file)?;

        // Upload layout file to ensure we can read later
        let client = self.git_options.get_client()?;
        client.put(Path::new(LAYOUT_FILE), &layout)?;

        Ok(())
    }
}

#[derive(Clone, Debug, Default)]
pub struct GithubRepo {
    owner: String,
    repository: String,
}

impl FromStr for GithubRepo {
    type Err = CliError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<_> = s.split('/').collect();
        if parts.len() != 2 {
            Err(CliError::CommandArgumentError("Invalid repository must be of the form 'owner/repository` e.g. 'aptos-labs/aptos-core'".to_string()))
        } else {
            Ok(GithubRepo {
                owner: parts.first().unwrap().to_string(),
                repository: parts.get(1).unwrap().to_string(),
            })
        }
    }
}

#[derive(Clone, Default, Parser)]
pub struct GitOptions {
    /// Github repository e.g. 'aptos-labs/aptos-core'
    #[clap(long)]
    pub(crate) github_repository: Option<GithubRepo>,

    /// Github repository branch e.g. main
    #[clap(long, default_value = "main")]
    pub(crate) github_branch: String,

    /// Path to Github API token.  Token must have repo:* permissions
    #[clap(long, parse(from_os_str))]
    pub(crate) github_token_file: Option<PathBuf>,

    /// Path to local git repository
    #[clap(long, parse(from_os_str))]
    pub(crate) local_repository_dir: Option<PathBuf>,
}

impl GitOptions {
    pub fn get_client(self) -> CliTypedResult<Client> {
        if self.github_repository.is_none()
            && self.github_token_file.is_none()
            && self.local_repository_dir.is_some()
        {
            Ok(Client::local(self.local_repository_dir.unwrap()))
        } else if self.github_repository.is_some()
            && self.github_token_file.is_some()
            && self.local_repository_dir.is_none()
        {
            Client::github(
                self.github_repository.unwrap(),
                self.github_branch,
                self.github_token_file.unwrap(),
            )
        } else {
            Err(CliError::CommandArgumentError("Must provide either only --local-repository-dir or both --github-repository and --github-token-path".to_string()))
        }
    }
}

/// A client for abstracting away local vs Github storage
///
/// Note: Writes do not commit locally
pub enum Client {
    Local(PathBuf),
    Github(GithubClient),
}

impl Client {
    pub fn local(path: PathBuf) -> Client {
        Client::Local(path)
    }

    pub fn github(
        repository: GithubRepo,
        branch: String,
        token_path: PathBuf,
    ) -> CliTypedResult<Client> {
        let token = Token::FromDisk(token_path).read_token()?;
        Ok(Client::Github(GithubClient::new(
            repository.owner,
            repository.repository,
            branch,
            token,
        )))
    }

    /// Retrieves an object as a YAML encoded file from the appropriate storage
    pub fn get<T: DeserializeOwned + Debug>(&self, path: &Path) -> CliTypedResult<T> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(path);
                let mut file = std::fs::File::open(path.as_path())
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;

                let mut contents = String::new();
                file.read_to_string(&mut contents)
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;
                from_yaml(&contents)
            }
            Client::Github(client) => {
                from_base64_encoded_yaml(&client.get_file(&path.display().to_string())?)
            }
        }
    }

    /// Puts an object as a YAML encoded file to the appropriate storage
    pub fn put<T: Serialize + ?Sized>(&self, name: &Path, input: &T) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(name);

                // Create repository path and any sub-directories
                if let Some(dir) = path.parent() {
                    self.create_dir(dir)?;
                } else {
                    return Err(CliError::UnexpectedError(format!(
                        "Path should always have a parent {}",
                        path.display()
                    )));
                }
                write_to_file(
                    path.as_path(),
                    &path.display().to_string(),
                    to_yaml(input)?.as_bytes(),
                )?;
            }
            Client::Github(client) => {
                client.put(&name.display().to_string(), &to_base64_encoded_yaml(input)?)?;
            }
        }

        Ok(())
    }

    pub fn create_dir(&self, dir: &Path) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(dir);
                create_dir_if_not_exist(path.as_path())?;
            }
            Client::Github(_) => {
                // There's no such thing as an empty directory in Git, so do nothing
            }
        }

        Ok(())
    }

    /// Retrieve framework release bundle.
    pub fn get_framework(&self) -> CliTypedResult<ReleaseBundle> {
        match self {
            Client::Local(local_repository_path) => Ok(ReleaseBundle::read(
                local_repository_path.join(FRAMEWORK_NAME),
            )?),
            Client::Github(client) => {
                let bytes = base64::decode(client.get_file(FRAMEWORK_NAME)?)?;
                Ok(bcs::from_bytes::<ReleaseBundle>(&bytes)?)
            }
        }
    }
}

pub fn to_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(serde_yaml::to_string(input)?)
}

pub fn from_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    Ok(serde_yaml::from_str(input)?)
}

pub fn to_base64_encoded_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(base64::encode(to_yaml(input)?))
}

pub fn from_base64_encoded_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    from_yaml(&String::from_utf8(base64::decode(input)?)?)
}
<commit_msg>[genesis] Make a better message if a file isn't found<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::common::utils::create_dir_if_not_exist;
use crate::{
    common::{
        types::{CliError, CliTypedResult},
        utils::write_to_file,
    },
    CliCommand,
};
use aptos_config::config::Token;
use aptos_genesis::config::Layout;
use aptos_github_client::Client as GithubClient;
use async_trait::async_trait;
use clap::Parser;
use framework::ReleaseBundle;
use serde::{de::DeserializeOwned, Serialize};
use std::path::Path;
use std::{fmt::Debug, io::Read, path::PathBuf, str::FromStr};

pub const LAYOUT_FILE: &str = "layout.yaml";
pub const OPERATOR_FILE: &str = "operator.yaml";
pub const OWNER_FILE: &str = "owner.yaml";
pub const FRAMEWORK_NAME: &str = "framework.mrb";
pub const BALANCES_FILE: &str = "balances.yaml";
pub const EMPLOYEE_VESTING_ACCOUNTS_FILE: &str = "employee_vesting_accounts.yaml";

/// Setup a shared Git repository for Genesis
///
/// This will setup a folder or an online Github repository to be used
/// for Genesis.  If it's the local, it will create the folders but not
/// set up a Git repository.
#[derive(Parser)]
pub struct SetupGit {
    #[clap(flatten)]
    pub(crate) git_options: GitOptions,

    /// Path to the `Layout` file which defines where all the files are
    #[clap(long, parse(from_os_str))]
    pub(crate) layout_file: PathBuf,
}

#[async_trait]
impl CliCommand<()> for SetupGit {
    fn command_name(&self) -> &'static str {
        "SetupGit"
    }

    async fn execute(self) -> CliTypedResult<()> {
        let layout = Layout::from_disk(&self.layout_file)?;

        // Upload layout file to ensure we can read later
        let client = self.git_options.get_client()?;
        client.put(Path::new(LAYOUT_FILE), &layout)?;

        Ok(())
    }
}

#[derive(Clone, Debug, Default)]
pub struct GithubRepo {
    owner: String,
    repository: String,
}

impl FromStr for GithubRepo {
    type Err = CliError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<_> = s.split('/').collect();
        if parts.len() != 2 {
            Err(CliError::CommandArgumentError("Invalid repository must be of the form 'owner/repository` e.g. 'aptos-labs/aptos-core'".to_string()))
        } else {
            Ok(GithubRepo {
                owner: parts.first().unwrap().to_string(),
                repository: parts.get(1).unwrap().to_string(),
            })
        }
    }
}

#[derive(Clone, Default, Parser)]
pub struct GitOptions {
    /// Github repository e.g. 'aptos-labs/aptos-core'
    #[clap(long)]
    pub(crate) github_repository: Option<GithubRepo>,

    /// Github repository branch e.g. main
    #[clap(long, default_value = "main")]
    pub(crate) github_branch: String,

    /// Path to Github API token.  Token must have repo:* permissions
    #[clap(long, parse(from_os_str))]
    pub(crate) github_token_file: Option<PathBuf>,

    /// Path to local git repository
    #[clap(long, parse(from_os_str))]
    pub(crate) local_repository_dir: Option<PathBuf>,
}

impl GitOptions {
    pub fn get_client(self) -> CliTypedResult<Client> {
        if self.github_repository.is_none()
            && self.github_token_file.is_none()
            && self.local_repository_dir.is_some()
        {
            Ok(Client::local(self.local_repository_dir.unwrap()))
        } else if self.github_repository.is_some()
            && self.github_token_file.is_some()
            && self.local_repository_dir.is_none()
        {
            Client::github(
                self.github_repository.unwrap(),
                self.github_branch,
                self.github_token_file.unwrap(),
            )
        } else {
            Err(CliError::CommandArgumentError("Must provide either only --local-repository-dir or both --github-repository and --github-token-path".to_string()))
        }
    }
}

/// A client for abstracting away local vs Github storage
///
/// Note: Writes do not commit locally
pub enum Client {
    Local(PathBuf),
    Github(GithubClient),
}

impl Client {
    pub fn local(path: PathBuf) -> Client {
        Client::Local(path)
    }

    pub fn github(
        repository: GithubRepo,
        branch: String,
        token_path: PathBuf,
    ) -> CliTypedResult<Client> {
        let token = Token::FromDisk(token_path).read_token()?;
        Ok(Client::Github(GithubClient::new(
            repository.owner,
            repository.repository,
            branch,
            token,
        )))
    }

    /// Retrieves an object as a YAML encoded file from the appropriate storage
    pub fn get<T: DeserializeOwned + Debug>(&self, path: &Path) -> CliTypedResult<T> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(path);

                if !path.exists() {
                    return Err(CliError::UnableToReadFile(
                        path.display().to_string(),
                        "File not found".to_string(),
                    ));
                }

                let mut file = std::fs::File::open(path.as_path())
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;

                let mut contents = String::new();
                file.read_to_string(&mut contents)
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;
                from_yaml(&contents)
            }
            Client::Github(client) => {
                from_base64_encoded_yaml(&client.get_file(&path.display().to_string())?)
            }
        }
    }

    /// Puts an object as a YAML encoded file to the appropriate storage
    pub fn put<T: Serialize + ?Sized>(&self, name: &Path, input: &T) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(name);

                // Create repository path and any sub-directories
                if let Some(dir) = path.parent() {
                    self.create_dir(dir)?;
                } else {
                    return Err(CliError::UnexpectedError(format!(
                        "Path should always have a parent {}",
                        path.display()
                    )));
                }
                write_to_file(
                    path.as_path(),
                    &path.display().to_string(),
                    to_yaml(input)?.as_bytes(),
                )?;
            }
            Client::Github(client) => {
                client.put(&name.display().to_string(), &to_base64_encoded_yaml(input)?)?;
            }
        }

        Ok(())
    }

    pub fn create_dir(&self, dir: &Path) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(dir);
                create_dir_if_not_exist(path.as_path())?;
            }
            Client::Github(_) => {
                // There's no such thing as an empty directory in Git, so do nothing
            }
        }

        Ok(())
    }

    /// Retrieve framework release bundle.
    pub fn get_framework(&self) -> CliTypedResult<ReleaseBundle> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(FRAMEWORK_NAME);
                if !path.exists() {
                    return Err(CliError::UnableToReadFile(
                        path.display().to_string(),
                        "File not found".to_string(),
                    ));
                }
                Ok(ReleaseBundle::read(path)?)
            }
            Client::Github(client) => {
                let bytes = base64::decode(client.get_file(FRAMEWORK_NAME)?)?;
                Ok(bcs::from_bytes::<ReleaseBundle>(&bytes)?)
            }
        }
    }
}

pub fn to_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(serde_yaml::to_string(input)?)
}

pub fn from_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    Ok(serde_yaml::from_str(input)?)
}

pub fn to_base64_encoded_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(base64::encode(to_yaml(input)?))
}

pub fn from_base64_encoded_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    from_yaml(&String::from_utf8(base64::decode(input)?)?)
}
<|endoftext|>


<commit_before>use std::{
    fmt, time,
    sync::Arc,
};

use rustc_hash::FxHashMap;
use ra_db::{
    SourceRootId, FileId, CrateGraph, SourceDatabase, SourceRoot,
    salsa::{Database, SweepStrategy},
};
use ra_syntax::SourceFile;
use ra_prof::profile;
use relative_path::RelativePathBuf;
use rayon::prelude::*;

use crate::{
    db::RootDatabase,
    symbol_index::{SymbolIndex, SymbolsDatabase},
    status::syntax_tree_stats,
};

#[derive(Default)]
pub struct AnalysisChange {
    new_roots: Vec<(SourceRootId, bool)>,
    roots_changed: FxHashMap<SourceRootId, RootChange>,
    files_changed: Vec<(FileId, Arc<String>)>,
    libraries_added: Vec<LibraryData>,
    crate_graph: Option<CrateGraph>,
}

impl fmt::Debug for AnalysisChange {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut d = fmt.debug_struct("AnalysisChange");
        if !self.new_roots.is_empty() {
            d.field("new_roots", &self.new_roots);
        }
        if !self.roots_changed.is_empty() {
            d.field("roots_changed", &self.roots_changed);
        }
        if !self.files_changed.is_empty() {
            d.field("files_changed", &self.files_changed.len());
        }
        if !self.libraries_added.is_empty() {
            d.field("libraries_added", &self.libraries_added.len());
        }
        if !self.crate_graph.is_some() {
            d.field("crate_graph", &self.crate_graph);
        }
        d.finish()
    }
}

impl AnalysisChange {
    pub fn new() -> AnalysisChange {
        AnalysisChange::default()
    }

    pub fn add_root(&mut self, root_id: SourceRootId, is_local: bool) {
        self.new_roots.push((root_id, is_local));
    }

    pub fn add_file(
        &mut self,
        root_id: SourceRootId,
        file_id: FileId,
        path: RelativePathBuf,
        text: Arc<String>,
    ) {
        let file = AddFile { file_id, path, text };
        self.roots_changed.entry(root_id).or_default().added.push(file);
    }

    pub fn change_file(&mut self, file_id: FileId, new_text: Arc<String>) {
        self.files_changed.push((file_id, new_text))
    }

    pub fn remove_file(&mut self, root_id: SourceRootId, file_id: FileId, path: RelativePathBuf) {
        let file = RemoveFile { file_id, path };
        self.roots_changed.entry(root_id).or_default().removed.push(file);
    }

    pub fn add_library(&mut self, data: LibraryData) {
        self.libraries_added.push(data)
    }

    pub fn set_crate_graph(&mut self, graph: CrateGraph) {
        self.crate_graph = Some(graph);
    }
}

#[derive(Debug)]
struct AddFile {
    file_id: FileId,
    path: RelativePathBuf,
    text: Arc<String>,
}

#[derive(Debug)]
struct RemoveFile {
    file_id: FileId,
    path: RelativePathBuf,
}

#[derive(Default)]
struct RootChange {
    added: Vec<AddFile>,
    removed: Vec<RemoveFile>,
}

impl fmt::Debug for RootChange {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("AnalysisChange")
            .field("added", &self.added.len())
            .field("removed", &self.removed.len())
            .finish()
    }
}

pub struct LibraryData {
    root_id: SourceRootId,
    root_change: RootChange,
    symbol_index: SymbolIndex,
}

impl fmt::Debug for LibraryData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LibraryData")
            .field("root_id", &self.root_id)
            .field("root_change", &self.root_change)
            .field("n_symbols", &self.symbol_index.len())
            .finish()
    }
}

impl LibraryData {
    pub fn prepare(
        root_id: SourceRootId,
        files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
    ) -> LibraryData {
        let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, _, text)| {
            let file = SourceFile::parse(text).tree;
            (*file_id, file)
        }));
        let mut root_change = RootChange::default();
        root_change.added = files
            .into_iter()
            .map(|(file_id, path, text)| AddFile { file_id, path, text })
            .collect();
        LibraryData { root_id, root_change, symbol_index }
    }
}

const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);

impl RootDatabase {
    pub(crate) fn apply_change(&mut self, change: AnalysisChange) {
        let _p = profile("RootDatabase::apply_change");
        log::info!("apply_change {:?}", change);
        {
            let _p = profile("RootDatabase::apply_change/cancellation");
            self.salsa_runtime().next_revision();
        }
        if !change.new_roots.is_empty() {
            let mut local_roots = Vec::clone(&self.local_roots());
            for (root_id, is_local) in change.new_roots {
                self.set_source_root(root_id, Default::default());
                if is_local {
                    local_roots.push(root_id);
                }
            }
            self.set_local_roots(Arc::new(local_roots));
        }

        for (root_id, root_change) in change.roots_changed {
            self.apply_root_change(root_id, root_change);
        }
        for (file_id, text) in change.files_changed {
            self.set_file_text(file_id, text)
        }
        if !change.libraries_added.is_empty() {
            let mut libraries = Vec::clone(&self.library_roots());
            for library in change.libraries_added {
                libraries.push(library.root_id);
                self.set_source_root(library.root_id, Default::default());
                self.set_constant_library_symbols(library.root_id, Arc::new(library.symbol_index));
                self.apply_root_change(library.root_id, library.root_change);
            }
            self.set_library_roots(Arc::new(libraries));
        }
        if let Some(crate_graph) = change.crate_graph {
            self.set_crate_graph(Arc::new(crate_graph))
        }
    }

    fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
        let mut source_root = SourceRoot::clone(&self.source_root(root_id));
        for add_file in root_change.added {
            self.set_file_text(add_file.file_id, add_file.text);
            self.set_file_relative_path(add_file.file_id, add_file.path.clone());
            self.set_file_source_root(add_file.file_id, root_id);
            source_root.files.insert(add_file.path, add_file.file_id);
        }
        for remove_file in root_change.removed {
            self.set_file_text(remove_file.file_id, Default::default());
            source_root.files.remove(&remove_file.path);
        }
        self.set_source_root(root_id, Arc::new(source_root));
    }

    pub(crate) fn maybe_collect_garbage(&mut self) {
        if self.last_gc_check.elapsed() > GC_COOLDOWN {
            self.last_gc_check = time::Instant::now();
            let retained_trees = syntax_tree_stats(self).retained;
            if retained_trees > 100 {
                log::info!("automatic garbadge collection, {} retained trees", retained_trees);
                self.collect_garbage();
            }
        }
    }

    pub(crate) fn collect_garbage(&mut self) {
        let _p = profile("RootDatabase::collect_garbage");
        self.last_gc = time::Instant::now();

        let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();

        self.query(ra_db::ParseQuery).sweep(sweep);

        self.query(hir::db::ParseOrExpandQuery).sweep(sweep);
        self.query(hir::db::AstIdMapQuery).sweep(sweep);

        self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep);
        self.query(hir::db::ImplsInModuleWithSourceMapQuery).sweep(sweep);
        self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep);

        self.query(hir::db::ExprScopesQuery).sweep(sweep);
        self.query(hir::db::InferQuery).sweep(sweep);
        self.query(hir::db::BodyHirQuery).sweep(sweep);
    }
}
<commit_msg>collect macro queries<commit_after>use std::{
    fmt, time,
    sync::Arc,
};

use rustc_hash::FxHashMap;
use ra_db::{
    SourceRootId, FileId, CrateGraph, SourceDatabase, SourceRoot,
    salsa::{Database, SweepStrategy},
};
use ra_syntax::SourceFile;
use ra_prof::profile;
use relative_path::RelativePathBuf;
use rayon::prelude::*;

use crate::{
    db::RootDatabase,
    symbol_index::{SymbolIndex, SymbolsDatabase},
    status::syntax_tree_stats,
};

#[derive(Default)]
pub struct AnalysisChange {
    new_roots: Vec<(SourceRootId, bool)>,
    roots_changed: FxHashMap<SourceRootId, RootChange>,
    files_changed: Vec<(FileId, Arc<String>)>,
    libraries_added: Vec<LibraryData>,
    crate_graph: Option<CrateGraph>,
}

impl fmt::Debug for AnalysisChange {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut d = fmt.debug_struct("AnalysisChange");
        if !self.new_roots.is_empty() {
            d.field("new_roots", &self.new_roots);
        }
        if !self.roots_changed.is_empty() {
            d.field("roots_changed", &self.roots_changed);
        }
        if !self.files_changed.is_empty() {
            d.field("files_changed", &self.files_changed.len());
        }
        if !self.libraries_added.is_empty() {
            d.field("libraries_added", &self.libraries_added.len());
        }
        if !self.crate_graph.is_some() {
            d.field("crate_graph", &self.crate_graph);
        }
        d.finish()
    }
}

impl AnalysisChange {
    pub fn new() -> AnalysisChange {
        AnalysisChange::default()
    }

    pub fn add_root(&mut self, root_id: SourceRootId, is_local: bool) {
        self.new_roots.push((root_id, is_local));
    }

    pub fn add_file(
        &mut self,
        root_id: SourceRootId,
        file_id: FileId,
        path: RelativePathBuf,
        text: Arc<String>,
    ) {
        let file = AddFile { file_id, path, text };
        self.roots_changed.entry(root_id).or_default().added.push(file);
    }

    pub fn change_file(&mut self, file_id: FileId, new_text: Arc<String>) {
        self.files_changed.push((file_id, new_text))
    }

    pub fn remove_file(&mut self, root_id: SourceRootId, file_id: FileId, path: RelativePathBuf) {
        let file = RemoveFile { file_id, path };
        self.roots_changed.entry(root_id).or_default().removed.push(file);
    }

    pub fn add_library(&mut self, data: LibraryData) {
        self.libraries_added.push(data)
    }

    pub fn set_crate_graph(&mut self, graph: CrateGraph) {
        self.crate_graph = Some(graph);
    }
}

#[derive(Debug)]
struct AddFile {
    file_id: FileId,
    path: RelativePathBuf,
    text: Arc<String>,
}

#[derive(Debug)]
struct RemoveFile {
    file_id: FileId,
    path: RelativePathBuf,
}

#[derive(Default)]
struct RootChange {
    added: Vec<AddFile>,
    removed: Vec<RemoveFile>,
}

impl fmt::Debug for RootChange {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("AnalysisChange")
            .field("added", &self.added.len())
            .field("removed", &self.removed.len())
            .finish()
    }
}

pub struct LibraryData {
    root_id: SourceRootId,
    root_change: RootChange,
    symbol_index: SymbolIndex,
}

impl fmt::Debug for LibraryData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LibraryData")
            .field("root_id", &self.root_id)
            .field("root_change", &self.root_change)
            .field("n_symbols", &self.symbol_index.len())
            .finish()
    }
}

impl LibraryData {
    pub fn prepare(
        root_id: SourceRootId,
        files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
    ) -> LibraryData {
        let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, _, text)| {
            let file = SourceFile::parse(text).tree;
            (*file_id, file)
        }));
        let mut root_change = RootChange::default();
        root_change.added = files
            .into_iter()
            .map(|(file_id, path, text)| AddFile { file_id, path, text })
            .collect();
        LibraryData { root_id, root_change, symbol_index }
    }
}

const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);

impl RootDatabase {
    pub(crate) fn apply_change(&mut self, change: AnalysisChange) {
        let _p = profile("RootDatabase::apply_change");
        log::info!("apply_change {:?}", change);
        {
            let _p = profile("RootDatabase::apply_change/cancellation");
            self.salsa_runtime().next_revision();
        }
        if !change.new_roots.is_empty() {
            let mut local_roots = Vec::clone(&self.local_roots());
            for (root_id, is_local) in change.new_roots {
                self.set_source_root(root_id, Default::default());
                if is_local {
                    local_roots.push(root_id);
                }
            }
            self.set_local_roots(Arc::new(local_roots));
        }

        for (root_id, root_change) in change.roots_changed {
            self.apply_root_change(root_id, root_change);
        }
        for (file_id, text) in change.files_changed {
            self.set_file_text(file_id, text)
        }
        if !change.libraries_added.is_empty() {
            let mut libraries = Vec::clone(&self.library_roots());
            for library in change.libraries_added {
                libraries.push(library.root_id);
                self.set_source_root(library.root_id, Default::default());
                self.set_constant_library_symbols(library.root_id, Arc::new(library.symbol_index));
                self.apply_root_change(library.root_id, library.root_change);
            }
            self.set_library_roots(Arc::new(libraries));
        }
        if let Some(crate_graph) = change.crate_graph {
            self.set_crate_graph(Arc::new(crate_graph))
        }
    }

    fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
        let mut source_root = SourceRoot::clone(&self.source_root(root_id));
        for add_file in root_change.added {
            self.set_file_text(add_file.file_id, add_file.text);
            self.set_file_relative_path(add_file.file_id, add_file.path.clone());
            self.set_file_source_root(add_file.file_id, root_id);
            source_root.files.insert(add_file.path, add_file.file_id);
        }
        for remove_file in root_change.removed {
            self.set_file_text(remove_file.file_id, Default::default());
            source_root.files.remove(&remove_file.path);
        }
        self.set_source_root(root_id, Arc::new(source_root));
    }

    pub(crate) fn maybe_collect_garbage(&mut self) {
        if self.last_gc_check.elapsed() > GC_COOLDOWN {
            self.last_gc_check = time::Instant::now();
            let retained_trees = syntax_tree_stats(self).retained;
            if retained_trees > 100 {
                log::info!("automatic garbadge collection, {} retained trees", retained_trees);
                self.collect_garbage();
            }
        }
    }

    pub(crate) fn collect_garbage(&mut self) {
        let _p = profile("RootDatabase::collect_garbage");
        self.last_gc = time::Instant::now();

        let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();

        self.query(ra_db::ParseQuery).sweep(sweep);

        self.query(hir::db::ParseOrExpandQuery).sweep(sweep);
        self.query(hir::db::MacroDefQuery).sweep(sweep);
        self.query(hir::db::MacroArgQuery).sweep(sweep);
        self.query(hir::db::MacroExpandQuery).sweep(sweep);
        self.query(hir::db::AstIdMapQuery).sweep(sweep);

        self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep);
        self.query(hir::db::ImplsInModuleWithSourceMapQuery).sweep(sweep);
        self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep);

        self.query(hir::db::ExprScopesQuery).sweep(sweep);
        self.query(hir::db::InferQuery).sweep(sweep);
        self.query(hir::db::BodyHirQuery).sweep(sweep);
    }
}
<|endoftext|>


<commit_before>#![feature(plugin, inclusive_range_syntax)]
#![feature(dotdot_in_tuple_patterns)]
#![plugin(clippy)]

#![allow(dead_code, no_effect, unnecessary_operation)]
#![allow(let_and_return)]
#![allow(needless_return)]
#![allow(unused_variables)]
#![allow(cyclomatic_complexity)]
#![allow(blacklisted_name)]

fn bar<T>(_: T) {}
fn foo() -> bool { unimplemented!() }

struct Foo {
    bar: u8,
}

#[deny(if_same_then_else)]
#[deny(match_same_arms)]
fn if_same_then_else() -> Result<&'static str, ()> {
    if true {
        Foo { bar: 42 };
        0..10;
        ..;
        0..;
        ..10;
        0...10;
        foo();
    }
    else { //~ERROR this `if` has identical blocks
        Foo { bar: 42 };
        0..10;
        ..;
        0..;
        ..10;
        0...10;
        foo();
    }

    if true {
        Foo { bar: 42 };
    }
    else {
        Foo { bar: 43 };
    }

    if true {
        0..10;
    }
    else {
        0...10;
    }

    if true {
        foo();
        foo();
    }
    else {
        foo();
    }

    let _ = if true {
        foo();
        42
    }
    else { //~ERROR this `if` has identical blocks
        foo();
        42
    };

    if true {
        foo();
    }

    let _ = if true {
        42
    }
    else { //~ERROR this `if` has identical blocks
        42
    };

    if true {
        let bar = if true {
            42
        }
        else {
            43
        };

        while foo() { break; }
        bar + 1;
    }
    else { //~ERROR this `if` has identical blocks
        let bar = if true {
            42
        }
        else {
            43
        };

        while foo() { break; }
        bar + 1;
    }

    if true {
        let _ = match 42 {
            42 => 1,
            a if a > 0 => 2,
            10...15 => 3,
            _ => 4,
        };
    }
    else if false {
        foo();
    }
    else if foo() { //~ERROR this `if` has identical blocks
        let _ = match 42 {
            42 => 1,
            a if a > 0 => 2,
            10...15 => 3,
            _ => 4,
        };
    }

    if true {
        if let Some(a) = Some(42) {}
    }
    else { //~ERROR this `if` has identical blocks
        if let Some(a) = Some(42) {}
    }

    if true {
        if let (1, .., 3) = (1, 2, 3) {}
    }
    else { //~ERROR this `if` has identical blocks
        if let (1, .., 3) = (1, 2, 3) {}
    }

    if true {
        if let (1, .., 3) = (1, 2, 3) {}
    }
    else {
        if let (.., 3) = (1, 2, 3) {}
    }

    if true {
        if let (1, .., 3) = (1, 2, 3) {}
    }
    else {
        if let (.., 4) = (1, 2, 3) {}
    }

    if true {
        if let (1, .., 3) = (1, 2, 3) {}
    }
    else {
        if let (.., 1, 3) = (1, 2, 3) {}
    }

    if true {
        if let Some(a) = Some(42) {}
    }
    else {
        if let Some(a) = Some(43) {}
    }

    let _ = match 42 {
        42 => foo(),
        51 => foo(), //~ERROR this `match` has identical arm bodies
        _ => true,
    };

    let _ = match Some(42) {
        Some(_) => 24,
        None => 24,
    };

    let _ = match Some(42) {
        Some(42) => 24,
        Some(a) => 24, // bindings are different
        None => 0,
    };

    let _ = match Some(42) {
        Some(a) if a > 0 => 24,
        Some(a) => 24, // one arm has a guard
        None => 0,
    };

    match (Some(42), Some(42)) {
        (Some(a), None) => bar(a),
        (None, Some(a)) => bar(a), //~ERROR this `match` has identical arm bodies
        _ => (),
    }

    match (Some(42), Some(42)) {
        (Some(a), ..) => bar(a),
        (.., Some(a)) => bar(a), //~ERROR this `match` has identical arm bodies
        _ => (),
    }

    match (1, 2, 3) {
        (1, .., 3) => 42,
        (.., 3) => 42, //~ERROR this `match` has identical arm bodies
        _ => 0,
    };

    match (Some(42), Some("")) {
        (Some(a), None) => bar(a),
        (None, Some(a)) => bar(a), // bindings have different types
        _ => (),
    }

    if true {
        try!(Ok("foo"));
    }
    else { //~ERROR this `if` has identical blocks
        try!(Ok("foo"));
    }

    if true {
        let foo = "";
        return Ok(&foo[0..]);
    }
    else if false {
        let foo = "bar";
        return Ok(&foo[0..]);
    }
    else { //~ERROR this `if` has identical blocks
        let foo = "";
        return Ok(&foo[0..]);
    }
}

#[deny(ifs_same_cond)]
#[allow(if_same_then_else)] // all empty blocks
fn ifs_same_cond() {
    let a = 0;
    let b = false;

    if b {
    }
    else if b { //~ERROR this `if` has the same condition as a previous if
    }

    if a == 1 {
    }
    else if a == 1 { //~ERROR this `if` has the same condition as a previous if
    }

    if 2*a == 1 {
    }
    else if 2*a == 2 {
    }
    else if 2*a == 1 { //~ERROR this `if` has the same condition as a previous if
    }
    else if a == 1 {
    }

    // See #659
    if cfg!(feature = "feature1-659") {
        1
    } else if cfg!(feature = "feature2-659") {
        2
    } else {
        3
    };

    let mut v = vec![1];
    if v.pop() == None { // ok, functions
    }
    else if v.pop() == None {
    }

    if v.len() == 42 { // ok, functions
    }
    else if v.len() == 42 {
    }
}

fn main() {}
<commit_msg>additional error in copies test annotated<commit_after>#![feature(plugin, inclusive_range_syntax)]
#![feature(dotdot_in_tuple_patterns)]
#![plugin(clippy)]

#![allow(dead_code, no_effect, unnecessary_operation)]
#![allow(let_and_return)]
#![allow(needless_return)]
#![allow(unused_variables)]
#![allow(cyclomatic_complexity)]
#![allow(blacklisted_name)]

fn bar<T>(_: T) {}
fn foo() -> bool { unimplemented!() }

struct Foo {
    bar: u8,
}

#[deny(if_same_then_else)]
#[deny(match_same_arms)]
fn if_same_then_else() -> Result<&'static str, ()> {
    if true {
        Foo { bar: 42 };
        0..10;
        ..;
        0..;
        ..10;
        0...10;
        foo();
    }
    else { //~ERROR this `if` has identical blocks
        Foo { bar: 42 };
        0..10;
        ..;
        0..;
        ..10;
        0...10;
        foo();
    }

    if true {
        Foo { bar: 42 };
    }
    else {
        Foo { bar: 43 };
    }

    if true {
        0..10;
    }
    else {
        0...10;
    }

    if true {
        foo();
        foo();
    }
    else {
        foo();
    }

    let _ = if true {
        foo();
        42
    }
    else { //~ERROR this `if` has identical blocks
        foo();
        42
    };

    if true {
        foo();
    }

    let _ = if true {
        42
    }
    else { //~ERROR this `if` has identical blocks
        42
    };

    if true {
        let bar = if true {
            42
        }
        else {
            43
        };

        while foo() { break; }
        bar + 1;
    }
    else { //~ERROR this `if` has identical blocks
        let bar = if true {
            42
        }
        else {
            43
        };

        while foo() { break; }
        bar + 1;
    }

    if true {
        let _ = match 42 {
            42 => 1,
            a if a > 0 => 2,
            10...15 => 3,
            _ => 4,
        };
    }
    else if false {
        foo();
    }
    else if foo() { //~ERROR this `if` has identical blocks
        let _ = match 42 {
            42 => 1,
            a if a > 0 => 2,
            10...15 => 3,
            _ => 4,
        };
    }

    if true {
        if let Some(a) = Some(42) {}
    }
    else { //~ERROR this `if` has identical blocks
        if let Some(a) = Some(42) {}
    }

    if true {
        if let (1, .., 3) = (1, 2, 3) {}
    }
    else { //~ERROR this `if` has identical blocks
        if let (1, .., 3) = (1, 2, 3) {}
    }

    if true {
        if let (1, .., 3) = (1, 2, 3) {}
    }
    else {
        if let (.., 3) = (1, 2, 3) {}
    }

    if true {
        if let (1, .., 3) = (1, 2, 3) {}
    }
    else {
        if let (.., 4) = (1, 2, 3) {}
    }

    if true {
        if let (1, .., 3) = (1, 2, 3) {}
    }
    else {
        if let (.., 1, 3) = (1, 2, 3) {}
    }

    if true {
        if let Some(a) = Some(42) {}
    }
    else {
        if let Some(a) = Some(43) {}
    }

    let _ = match 42 {
        42 => foo(),
        51 => foo(), //~ERROR this `match` has identical arm bodies
        _ => true,
    };

    let _ = match Some(42) {
        Some(_) => 24,
        None => 24, //~ERROR this `match` has identical arm bodies
    };

    let _ = match Some(42) {
        Some(42) => 24,
        Some(a) => 24, // bindings are different
        None => 0,
    };

    let _ = match Some(42) {
        Some(a) if a > 0 => 24,
        Some(a) => 24, // one arm has a guard
        None => 0,
    };

    match (Some(42), Some(42)) {
        (Some(a), None) => bar(a),
        (None, Some(a)) => bar(a), //~ERROR this `match` has identical arm bodies
        _ => (),
    }

    match (Some(42), Some(42)) {
        (Some(a), ..) => bar(a),
        (.., Some(a)) => bar(a), //~ERROR this `match` has identical arm bodies
        _ => (),
    }

    match (1, 2, 3) {
        (1, .., 3) => 42,
        (.., 3) => 42, //~ERROR this `match` has identical arm bodies
        _ => 0,
    };

    match (Some(42), Some("")) {
        (Some(a), None) => bar(a),
        (None, Some(a)) => bar(a), // bindings have different types
        _ => (),
    }

    if true {
        try!(Ok("foo"));
    }
    else { //~ERROR this `if` has identical blocks
        try!(Ok("foo"));
    }

    if true {
        let foo = "";
        return Ok(&foo[0..]);
    }
    else if false {
        let foo = "bar";
        return Ok(&foo[0..]);
    }
    else { //~ERROR this `if` has identical blocks
        let foo = "";
        return Ok(&foo[0..]);
    }
}

#[deny(ifs_same_cond)]
#[allow(if_same_then_else)] // all empty blocks
fn ifs_same_cond() {
    let a = 0;
    let b = false;

    if b {
    }
    else if b { //~ERROR this `if` has the same condition as a previous if
    }

    if a == 1 {
    }
    else if a == 1 { //~ERROR this `if` has the same condition as a previous if
    }

    if 2*a == 1 {
    }
    else if 2*a == 2 {
    }
    else if 2*a == 1 { //~ERROR this `if` has the same condition as a previous if
    }
    else if a == 1 {
    }

    // See #659
    if cfg!(feature = "feature1-659") {
        1
    } else if cfg!(feature = "feature2-659") {
        2
    } else {
        3
    };

    let mut v = vec![1];
    if v.pop() == None { // ok, functions
    }
    else if v.pop() == None {
    }

    if v.len() == 42 { // ok, functions
    }
    else if v.len() == 42 {
    }
}

fn main() {}
<|endoftext|>


<commit_before>//! incremental BLOB I/O
use std::mem;
use std::ptr;

use super::ffi;
use {SqliteError, SqliteResult, SqliteConnection};

/// Handle to an open BLOB
pub struct SqliteBlob<'conn> {
    conn: &'conn SqliteConnection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

/// Enumeration of possible methods to seek within an BLOB.
pub enum SeekFrom {
    Start(i32),
    End(i32),
    Current(i32),
}

impl SqliteConnection {
    /// Open a handle to the BLOB located in `row`, `column`, `table` in database `db` ('main', 'temp', ...)
    pub fn blob_open<'a>(&'a self, db: &str, table: &str, column: &str, row: i64, read_only: bool) -> SqliteResult<SqliteBlob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = try!(super::str_to_cstring(db));
        let table = try!(super::str_to_cstring(table));
        let column = try!(super::str_to_cstring(column));
        let rc = unsafe{ ffi::sqlite3_blob_open(c.db(), db.as_ptr(), table.as_ptr(), column.as_ptr(), row, if read_only { 0 } else { 1 }, &mut blob) };
        c.decode_result(rc).map(|_| {
            SqliteBlob{ conn: self, blob: blob, pos: 0 }
        })
    }
}

impl<'conn> SqliteBlob<'conn> {
    /// Move a BLOB handle to a new row
    pub fn reopen(&mut self, row: i64) -> SqliteResult<()> {
        let rc = unsafe{ ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB
    pub fn size(&self) -> i32 {
        unsafe{ ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Read data from a BLOB incrementally
    pub fn read(&mut self, buf: &mut [u8]) -> SqliteResult<i32> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(SqliteError {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string()
            });
        }
        let mut n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            n = size - self.pos;
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe { ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos) };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n
        })
    }

    /// Write data into a BLOB incrementally
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase the size of a BLOB using this API.
    pub fn write(&mut self, buf: &[u8]) -> SqliteResult<i32> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(SqliteError {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string()
            });
        }
        let n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            return Err(SqliteError{code: ffi::SQLITE_MISUSE, message: format!("pos = {} + n = {} > size = {}", self.pos, n, size)});
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe { ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos) };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n
        })
    }

    /// Seek to an offset, in bytes, in BLOB.
    pub fn seek(&mut self, pos: SeekFrom) {
        self.pos  = match pos {
            SeekFrom::Start(offset) => offset,
            SeekFrom::Current(offset) => self.pos + offset,
            SeekFrom::End(offset) => self.size() + offset
        };
    }

    /// Close a BLOB handle
    pub fn close(mut self) -> SqliteResult<()> {
        self.close_()
    }

    fn close_(&mut self) -> SqliteResult<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

#[allow(unused_must_use)]
impl<'conn> Drop for SqliteBlob<'conn> {
    fn drop(&mut self) {
        self.close_();
    }
}

#[cfg(test)]
mod test {
    use SqliteConnection;

   #[test]
    fn test_blob() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let sql = "BEGIN;
                CREATE TABLE test (content BLOB);
                INSERT INTO test VALUES (ZEROBLOB(10));
                END;";
        db.execute_batch(sql).unwrap();
        let rowid = db.last_insert_rowid();

        let mut blob = db.blob_open("main", "test", "content", rowid, false).unwrap();
        blob.write(b"Clob").unwrap();
        let err = blob.write(b"5678901");
        //writeln!(io::stderr(), "{:?}", err);
        assert!(err.is_err());

        assert!(blob.reopen(rowid).is_ok());
        assert!(blob.close().is_ok());

        blob = db.blob_open("main", "test", "content", rowid, true).unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        assert!(blob.reopen(rowid).is_ok());
        blob.seek(super::SeekFrom::Start(0));
    }
}<commit_msg>Add Failure documentation<commit_after>//! incremental BLOB I/O
use std::mem;
use std::ptr;

use super::ffi;
use {SqliteError, SqliteResult, SqliteConnection};

/// Handle to an open BLOB
pub struct SqliteBlob<'conn> {
    conn: &'conn SqliteConnection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

/// Enumeration of possible methods to seek within an BLOB.
pub enum SeekFrom {
    Start(i32),
    End(i32),
    Current(i32),
}

impl SqliteConnection {
    /// Open a handle to the BLOB located in `row`, `column`, `table` in database `db` ('main', 'temp', ...)
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string or if the
    /// underlying SQLite BLOB open call fails.
    pub fn blob_open<'a>(&'a self, db: &str, table: &str, column: &str, row: i64, read_only: bool) -> SqliteResult<SqliteBlob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = try!(super::str_to_cstring(db));
        let table = try!(super::str_to_cstring(table));
        let column = try!(super::str_to_cstring(column));
        let rc = unsafe{ ffi::sqlite3_blob_open(c.db(), db.as_ptr(), table.as_ptr(), column.as_ptr(), row, if read_only { 0 } else { 1 }, &mut blob) };
        c.decode_result(rc).map(|_| {
            SqliteBlob{ conn: self, blob: blob, pos: 0 }
        })
    }
}

impl<'conn> SqliteBlob<'conn> {
    /// Move a BLOB handle to a new row
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> SqliteResult<()> {
        let rc = unsafe{ ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB
    pub fn size(&self) -> i32 {
        unsafe{ ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Read data from a BLOB incrementally
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if the underlying SQLite read call fails.
    pub fn read(&mut self, buf: &mut [u8]) -> SqliteResult<i32> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(SqliteError {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string()
            });
        }
        let mut n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            n = size - self.pos;
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe { ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos) };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n
        })
    }

    /// Write data into a BLOB incrementally
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if `buf` length + offset > BLOB size
    /// or if the underlying SQLite write call fails.
    pub fn write(&mut self, buf: &[u8]) -> SqliteResult<i32> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(SqliteError {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string()
            });
        }
        let n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            return Err(SqliteError{code: ffi::SQLITE_MISUSE, message: format!("pos = {} + n = {} > size = {}", self.pos, n, size)});
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe { ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos) };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n
        })
    }

    /// Seek to an offset, in bytes, in BLOB.
    pub fn seek(&mut self, pos: SeekFrom) {
        self.pos  = match pos {
            SeekFrom::Start(offset) => offset,
            SeekFrom::Current(offset) => self.pos + offset,
            SeekFrom::End(offset) => self.size() + offset
        };
    }

    /// Close a BLOB handle
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> SqliteResult<()> {
        self.close_()
    }

    fn close_(&mut self) -> SqliteResult<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

#[allow(unused_must_use)]
impl<'conn> Drop for SqliteBlob<'conn> {
    fn drop(&mut self) {
        self.close_();
    }
}

#[cfg(test)]
mod test {
    use SqliteConnection;

   #[test]
    fn test_blob() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let sql = "BEGIN;
                CREATE TABLE test (content BLOB);
                INSERT INTO test VALUES (ZEROBLOB(10));
                END;";
        db.execute_batch(sql).unwrap();
        let rowid = db.last_insert_rowid();

        let mut blob = db.blob_open("main", "test", "content", rowid, false).unwrap();
        blob.write(b"Clob").unwrap();
        let err = blob.write(b"5678901");
        //writeln!(io::stderr(), "{:?}", err);
        assert!(err.is_err());

        assert!(blob.reopen(rowid).is_ok());
        assert!(blob.close().is_ok());

        blob = db.blob_open("main", "test", "content", rowid, true).unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        assert!(blob.reopen(rowid).is_ok());
        blob.seek(super::SeekFrom::Start(0));
    }
}<|endoftext|>


<commit_before>//! Graph traits for associated data and graph construction.

use Graph;
use stable_graph::StableGraph;
use ::{
    EdgeType,
};
use graph::IndexType;
use graphmap::{GraphMap, NodeTrait};
use visit::{
    Data,
    NodeCount,
    NodeIndexable,
    Reversed,
};

trait_template!{
    /// Access node and edge weights (associated data).
pub trait DataMap : Data {
    @section self_ref
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight>;
    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight>;
}
}

macro_rules! access0 {
    ($e:expr) => ($e.0);
}

DataMap!{delegate_impl []}
DataMap!{delegate_impl [['a, G], G, &'a mut G, deref_twice]}
DataMap!{delegate_impl [[G], G, Reversed<G>, access0]}

trait_template! {
    /// Access node and edge weights mutably.
pub trait DataMapMut : DataMap {
    @section self_mut
    fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight>;
    fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight>;
}
}

DataMapMut!{delegate_impl [['a, G], G, &'a mut G, deref_twice]}
DataMapMut!{delegate_impl [[G], G, Reversed<G>, access0]}

/// A graph that can be extended with further nodes and edges
pub trait Build : Data + NodeCount {
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId;
    /// Add a new edge. If parallel edges (duplicate) are not allowed and
    /// the edge already exists, return `None`.
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId> {
        Some(self.update_edge(a, b, weight))
    }
    /// Add or update the edge from `a` to `b`. Return the id of the affected
    /// edge.
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId;
}

/// A graph that can be created
pub trait Create : Build + DataMapMut + Default {
    fn with_capacity(nodes: usize, edges: usize) -> Self;
}

impl<N, E, Ty, Ix> Data for Graph<N, E, Ty, Ix>
    where Ix: IndexType
{
    type NodeWeight = N;
    type EdgeWeight = E;
}

impl<N, E, Ty, Ix> DataMap for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
        self.node_weight(id)
    }
    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
        self.edge_weight(id)
    }
}

impl<N, E, Ty, Ix> DataMapMut for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
        self.node_weight_mut(id)
    }
    fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
        self.edge_weight_mut(id)
    }
}

impl<N, E, Ty, Ix> DataMap for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
        self.node_weight(id)
    }
    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
        self.edge_weight(id)
    }
}

impl<N, E, Ty, Ix> DataMapMut for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
        self.node_weight_mut(id)
    }
    fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
        self.edge_weight_mut(id)
    }
}

impl<N, E, Ty, Ix> Build for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
        self.add_node(weight)
    }
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId>
    {
        Some(self.add_edge(a, b, weight))
    }
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId
    {
        self.update_edge(a, b, weight)
    }
}

impl<N, E, Ty, Ix> Build for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
        self.add_node(weight)
    }
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId>
    {
        Some(self.add_edge(a, b, weight))
    }
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId
    {
        self.update_edge(a, b, weight)
    }
}

impl<N, E, Ty> Build for GraphMap<N, E, Ty>
    where Ty: EdgeType,
          N: NodeTrait,
{
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
        self.add_node(weight)
    }
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId>
    {
        if self.contains_edge(a, b) {
            None
        } else {
            let r = self.add_edge(a, b, weight);
            debug_assert!(r.is_none());
            Some((a, b))
        }
    }
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId
    {
        self.add_edge(a, b, weight);
        (a, b)
    }
}

impl<N, E, Ty, Ix> Create for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn with_capacity(nodes: usize, edges: usize) -> Self {
        Self::with_capacity(nodes, edges)
    }
}

impl<N, E, Ty, Ix> Create for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn with_capacity(nodes: usize, edges: usize) -> Self {
        Self::with_capacity(nodes, edges)
    }
}

/// A graph element
pub enum Element<N, E> {
    Node(N),
    Edge(usize, usize, E),
}

/// Create a graph from an iterator of elements.
pub trait FromElements : Create {
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        let mut gr = Self::with_capacity(0, 0);
        // usize -> NodeId map
        let mut map = Vec::new();
        for element in iterable {
            match element {
                Element::Node(w) => {
                    map.push(gr.add_node(w));
                }
                Element::Edge(a, b, w) => {
                    gr.add_edge(map[a], map[b], w);
                }
            }
        }
        gr
    }

}

fn from_elements_indexable<G, I>(iterable: I) -> G
    where G: Create + NodeIndexable,
          I: IntoIterator<Item=Element<G::NodeWeight, G::EdgeWeight>>,
{
    let mut gr = G::with_capacity(0, 0);
    let map = |gr: &G, i| gr.from_index(i);
    for element in iterable {
        match element {
            Element::Node(w) => {
                gr.add_node(w);
            }
            Element::Edge(a, b, w) => {
                let from = map(&gr, a);
                let to = map(&gr, b);
                gr.add_edge(from, to, w);
            }
        }
    }
    gr
}

impl<N, E, Ty, Ix> FromElements for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        from_elements_indexable(iterable)
    }
}

impl<N, E, Ty, Ix> FromElements for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        from_elements_indexable(iterable)
    }
}
<commit_msg>Create, FromElements for GraphMap. Change Create to not require DataMap<commit_after>//! Graph traits for associated data and graph construction.

use Graph;
use stable_graph::StableGraph;
use ::{
    EdgeType,
};
use graph::IndexType;
use graphmap::{GraphMap, NodeTrait};
use visit::{
    Data,
    NodeCount,
    NodeIndexable,
    Reversed,
};

trait_template!{
    /// Access node and edge weights (associated data).
pub trait DataMap : Data {
    @section self_ref
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight>;
    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight>;
}
}

macro_rules! access0 {
    ($e:expr) => ($e.0);
}

DataMap!{delegate_impl []}
DataMap!{delegate_impl [['a, G], G, &'a mut G, deref_twice]}
DataMap!{delegate_impl [[G], G, Reversed<G>, access0]}

trait_template! {
    /// Access node and edge weights mutably.
pub trait DataMapMut : DataMap {
    @section self_mut
    fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight>;
    fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight>;
}
}

DataMapMut!{delegate_impl [['a, G], G, &'a mut G, deref_twice]}
DataMapMut!{delegate_impl [[G], G, Reversed<G>, access0]}

/// A graph that can be extended with further nodes and edges
pub trait Build : Data + NodeCount {
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId;
    /// Add a new edge. If parallel edges (duplicate) are not allowed and
    /// the edge already exists, return `None`.
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId> {
        Some(self.update_edge(a, b, weight))
    }
    /// Add or update the edge from `a` to `b`. Return the id of the affected
    /// edge.
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId;
}

/// A graph that can be created
pub trait Create : Build + Default {
    fn with_capacity(nodes: usize, edges: usize) -> Self;
}

impl<N, E, Ty, Ix> Data for Graph<N, E, Ty, Ix>
    where Ix: IndexType
{
    type NodeWeight = N;
    type EdgeWeight = E;
}

impl<N, E, Ty, Ix> DataMap for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
        self.node_weight(id)
    }
    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
        self.edge_weight(id)
    }
}

impl<N, E, Ty, Ix> DataMapMut for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
        self.node_weight_mut(id)
    }
    fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
        self.edge_weight_mut(id)
    }
}

impl<N, E, Ty, Ix> DataMap for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
        self.node_weight(id)
    }
    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
        self.edge_weight(id)
    }
}

impl<N, E, Ty, Ix> DataMapMut for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
        self.node_weight_mut(id)
    }
    fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
        self.edge_weight_mut(id)
    }
}

impl<N, E, Ty, Ix> Build for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
        self.add_node(weight)
    }
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId>
    {
        Some(self.add_edge(a, b, weight))
    }
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId
    {
        self.update_edge(a, b, weight)
    }
}

impl<N, E, Ty, Ix> Build for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
        self.add_node(weight)
    }
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId>
    {
        Some(self.add_edge(a, b, weight))
    }
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId
    {
        self.update_edge(a, b, weight)
    }
}

impl<N, E, Ty> Build for GraphMap<N, E, Ty>
    where Ty: EdgeType,
          N: NodeTrait,
{
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
        self.add_node(weight)
    }
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId>
    {
        if self.contains_edge(a, b) {
            None
        } else {
            let r = self.add_edge(a, b, weight);
            debug_assert!(r.is_none());
            Some((a, b))
        }
    }
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId
    {
        self.add_edge(a, b, weight);
        (a, b)
    }
}

impl<N, E, Ty, Ix> Create for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn with_capacity(nodes: usize, edges: usize) -> Self {
        Self::with_capacity(nodes, edges)
    }
}

impl<N, E, Ty, Ix> Create for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn with_capacity(nodes: usize, edges: usize) -> Self {
        Self::with_capacity(nodes, edges)
    }
}

impl<N, E, Ty> Create for GraphMap<N, E, Ty>
    where Ty: EdgeType,
          N: NodeTrait,
{
    fn with_capacity(nodes: usize, edges: usize) -> Self {
        Self::with_capacity(nodes, edges)
    }
}

/// A graph element
pub enum Element<N, E> {
    Node(N),
    Edge(usize, usize, E),
}

/// Create a graph from an iterator of elements.
pub trait FromElements : Create {
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        let mut gr = Self::with_capacity(0, 0);
        // usize -> NodeId map
        let mut map = Vec::new();
        for element in iterable {
            match element {
                Element::Node(w) => {
                    map.push(gr.add_node(w));
                }
                Element::Edge(a, b, w) => {
                    gr.add_edge(map[a], map[b], w);
                }
            }
        }
        gr
    }

}

fn from_elements_indexable<G, I>(iterable: I) -> G
    where G: Create + NodeIndexable,
          I: IntoIterator<Item=Element<G::NodeWeight, G::EdgeWeight>>,
{
    let mut gr = G::with_capacity(0, 0);
    let map = |gr: &G, i| gr.from_index(i);
    for element in iterable {
        match element {
            Element::Node(w) => {
                gr.add_node(w);
            }
            Element::Edge(a, b, w) => {
                let from = map(&gr, a);
                let to = map(&gr, b);
                gr.add_edge(from, to, w);
            }
        }
    }
    gr
}

impl<N, E, Ty, Ix> FromElements for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        from_elements_indexable(iterable)
    }
}

impl<N, E, Ty, Ix> FromElements for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        from_elements_indexable(iterable)
    }
}

impl<N, E, Ty> FromElements for GraphMap<N, E, Ty>
    where Ty: EdgeType,
          N: NodeTrait,
{
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        from_elements_indexable(iterable)
    }
}
<|endoftext|>