<commit_before>pub use diagnostic_shim::{Diagnostic, DiagnosticShim, EmitErrorExt};

use proc_macro2::{TokenStream, Span};
use syn::{Ident, Type, DeriveInput, Data, GenericArgument};
use meta::MetaItem;

pub fn wrap_in_dummy_mod(const_name: Ident, item: TokenStream) -> TokenStream {
    quote! {
        #[allow(non_snake_case, unused_extern_crates, unused_imports)]
        fn #const_name() {
            // https://github.com/rust-lang/rust/issues/47314
            extern crate std;
            use diesel;

            #item
        }
    }
}

pub fn inner_of_option_ty(ty: &Type) -> &Type {
    option_ty_arg(ty).unwrap_or(ty)
}

pub fn is_option_ty(ty: &Type) -> bool {
    option_ty_arg(ty).is_some()
}

fn option_ty_arg(ty: &Type) -> Option<&Type> {
    use syn::PathArguments::AngleBracketed;

    match *ty {
        Type::Path(ref ty) => {
            let last_segment = ty.path.segments.iter().last().unwrap();
            match last_segment.arguments {
                AngleBracketed(ref args) if last_segment.ident == "Option" => {
                    match args.args.iter().last() {
                        Some(&GenericArgument::Type(ref ty)) => Some(ty),
                        _ => None,
                    }
                }
                _ => None,
            }
        }
        _ => None,
    }
}

pub fn ty_for_foreign_derive(item: &DeriveInput, flags: &MetaItem) -> Result<Type, Diagnostic> {
    if flags.has_flag("foreign_derive") {
        match item.data {
            Data::Struct(ref body) => match body.fields.iter().nth(0) {
                Some(field) => Ok(field.ty.clone()),
                None => Err(flags
                    .span()
                    .error("foreign_derive requires at least one field")),
            },
            _ => Err(flags
                .span()
                .error("foreign_derive can only be used with structs")),
        }
    } else {
        let ident = &item.ident;
        let (_, ty_generics, ..) = item.generics.split_for_impl();
        Ok(parse_quote!(#ident #ty_generics))
    }
}

pub fn fix_span(maybe_bad_span: Span, mut fallback: Span) -> Span {
    let bad_span_debug = "#0 bytes(0..0)";

    if format!("{:?}", fallback) == bad_span_debug {
        // On recent rust nightlies, even our fallback span is bad.
        fallback = Span::call_site();
    }

    if format!("{:?}", maybe_bad_span) == bad_span_debug {
        fallback
    } else {
        maybe_bad_span
    }
}
<commit_msg>cargo fmt<commit_after>pub use diagnostic_shim::{Diagnostic, DiagnosticShim, EmitErrorExt};

use meta::MetaItem;
use proc_macro2::{Span, TokenStream};
use syn::{Data, DeriveInput, GenericArgument, Ident, Type};

pub fn wrap_in_dummy_mod(const_name: Ident, item: TokenStream) -> TokenStream {
    quote! {
        #[allow(non_snake_case, unused_extern_crates, unused_imports)]
        fn #const_name() {
            // https://github.com/rust-lang/rust/issues/47314
            extern crate std;
            use diesel;

            #item
        }
    }
}

pub fn inner_of_option_ty(ty: &Type) -> &Type {
    option_ty_arg(ty).unwrap_or(ty)
}

pub fn is_option_ty(ty: &Type) -> bool {
    option_ty_arg(ty).is_some()
}

fn option_ty_arg(ty: &Type) -> Option<&Type> {
    use syn::PathArguments::AngleBracketed;

    match *ty {
        Type::Path(ref ty) => {
            let last_segment = ty.path.segments.iter().last().unwrap();
            match last_segment.arguments {
                AngleBracketed(ref args) if last_segment.ident == "Option" => {
                    match args.args.iter().last() {
                        Some(&GenericArgument::Type(ref ty)) => Some(ty),
                        _ => None,
                    }
                }
                _ => None,
            }
        }
        _ => None,
    }
}

pub fn ty_for_foreign_derive(item: &DeriveInput, flags: &MetaItem) -> Result<Type, Diagnostic> {
    if flags.has_flag("foreign_derive") {
        match item.data {
            Data::Struct(ref body) => match body.fields.iter().nth(0) {
                Some(field) => Ok(field.ty.clone()),
                None => Err(flags
                    .span()
                    .error("foreign_derive requires at least one field")),
            },
            _ => Err(flags
                .span()
                .error("foreign_derive can only be used with structs")),
        }
    } else {
        let ident = &item.ident;
        let (_, ty_generics, ..) = item.generics.split_for_impl();
        Ok(parse_quote!(#ident #ty_generics))
    }
}

pub fn fix_span(maybe_bad_span: Span, mut fallback: Span) -> Span {
    let bad_span_debug = "#0 bytes(0..0)";

    if format!("{:?}", fallback) == bad_span_debug {
        // On recent rust nightlies, even our fallback span is bad.
        fallback = Span::call_site();
    }

    if format!("{:?}", maybe_bad_span) == bad_span_debug {
        fallback
    } else {
        maybe_bad_span
    }
}
<|endoftext|>


<commit_before>use configuration;
use logger;
use file;
use platform;
use system_services::{SystemServices, SystemInterface};

pub struct Provisioner{
    system_service: SystemServices
}

impl Provisioner {
    pub fn new(system_service: SystemServices) -> Provisioner {
        Provisioner {
            system_service: system_service
        }
    }

    pub fn provision(&self, configuration: &configuration::Configuration) -> i32 {
        let mut packages = Vec::new();

        if !configuration.is_valid() {
            for error_message in configuration.error_messages() {
                logger::print_message(error_message, logger::MessageType::Stderr);
            }
            return 1;
        }

        packages.extend(configuration.packages.iter().cloned());

        packages.reverse();

        let mut exit_codes = Vec::new();

        if self.manage_hostname(&configuration) {
            exit_codes.push(0);
        } else {
            exit_codes.push(1);
        }

        let package_exit_codes = self.install_packages(&packages);
        exit_codes.extend(&package_exit_codes[..]);

        let results = self.handle_file_resources(&configuration.files);
        exit_codes.extend(&results[..]);

        exit_codes.sort();

        match exit_codes.last() {
            Some(&0) => return 0,
            None     => return 0,
            _        => return 1
        }
    }

    fn manage_hostname(&self, configuration: &configuration::Configuration) -> bool {
        if configuration.hostname == "default" {
            return true
        }

        let current_hostname = match self.system_service.get_hostname() {
            Some(hn)    => hn,
            None        => String::new()
        };

        if current_hostname == configuration.hostname.to_string() {
            return true
        } else {
            match self.system_service.set_hostname(&configuration.hostname) {
                true => {
                    logger::print_message(format!("==> Set hostname to {}", configuration.hostname), logger::MessageType::Stdout);
                    true
                },
                false => {
                    logger::print_message(format!("==> Failed to set hostname to {}", configuration.hostname), logger::MessageType::Stderr);
                    false
                }
            }
        }
    }

    fn install_packages(&self, package_list: &Vec<String>) -> Vec<i32> {
        let mut exit_codes = Vec::new();
        let mut packages = package_list.clone();

        while let Some(package) = packages.pop() {
            if self.system_service.is_package_installed(&package) {
                continue;
            }
            let shellout = self.system_service.install_package(&package);
            logger::print_shellout::<String>(&package, &shellout);
            let exit_status = shellout.status.clone();
            if exit_status.success() == false {
                exit_codes.push(exit_status.code().unwrap());
            }
        }
        exit_codes
    }

    fn file_is_equal_to(&self, file_resource: &file::FileResource) -> bool {
        //TODO better error handling here
        let other_file = file::FileResource::create_from_path(&file_resource.path).unwrap();
        other_file.hash() == file_resource.hash()
    }

    fn handle_file_resources(&self, resources: &Vec<file::FileResource>) -> Vec<i32> {
        let mut results = Vec::new();
        for resource in resources {
            if self.system_service.file_exists(&resource.path) && self.file_is_equal_to(&resource) {
                results.push(0);
                continue;
            }
            let result = resource.write_file();
            match result {
                Ok(_) =>  {
                    let msg = format!("==> Wrote file {}", resource.path);
                    logger::print_message(msg, logger::MessageType::Stdout);
                    results.push(0);
                },
                Err(err) => {
                    let msg = format!("==> Error while writing file {}", resource.path);
                    logger::print_message(msg, logger::MessageType::Stderr);
                    logger::print_message(format!("==> {}", err), logger::MessageType::Stderr);
                    results.push(1);
                }
            }
        }
        results
    }
}
<commit_msg>install_packages also returns success exit codes<commit_after>use configuration;
use logger;
use file;
use platform;
use system_services::{SystemServices, SystemInterface};

pub struct Provisioner{
    system_service: SystemServices
}

impl Provisioner {
    pub fn new(system_service: SystemServices) -> Provisioner {
        Provisioner {
            system_service: system_service
        }
    }

    pub fn provision(&self, configuration: &configuration::Configuration) -> i32 {
        let mut packages = Vec::new();

        if !configuration.is_valid() {
            for error_message in configuration.error_messages() {
                logger::print_message(error_message, logger::MessageType::Stderr);
            }
            return 1;
        }

        packages.extend(configuration.packages.iter().cloned());

        packages.reverse();

        let mut exit_codes = Vec::new();

        if self.manage_hostname(&configuration) {
            exit_codes.push(0);
        } else {
            exit_codes.push(1);
        }

        let package_exit_codes = self.install_packages(&packages);
        exit_codes.extend(&package_exit_codes[..]);

        let results = self.handle_file_resources(&configuration.files);
        exit_codes.extend(&results[..]);

        exit_codes.sort();

        match exit_codes.last() {
            Some(&0) => return 0,
            None     => return 0,
            _        => return 1
        }
    }

    fn manage_hostname(&self, configuration: &configuration::Configuration) -> bool {
        if configuration.hostname == "default" {
            return true
        }

        let current_hostname = match self.system_service.get_hostname() {
            Some(hn)    => hn,
            None        => String::new()
        };

        if current_hostname == configuration.hostname.to_string() {
            return true
        } else {
            match self.system_service.set_hostname(&configuration.hostname) {
                true => {
                    logger::print_message(format!("==> Set hostname to {}", configuration.hostname), logger::MessageType::Stdout);
                    true
                },
                false => {
                    logger::print_message(format!("==> Failed to set hostname to {}", configuration.hostname), logger::MessageType::Stderr);
                    false
                }
            }
        }
    }

    fn install_packages(&self, package_list: &Vec<String>) -> Vec<i32> {
        let mut exit_codes = Vec::new();
        let mut packages = package_list.clone();

        while let Some(package) = packages.pop() {
            if self.system_service.is_package_installed(&package) {
                continue;
            }
            let shellout = self.system_service.install_package(&package);
            logger::print_shellout::<String>(&package, &shellout);
            let exit_status = shellout.status.clone();
            exit_codes.push(exit_status.code().unwrap());
        }
        exit_codes
    }

    fn file_is_equal_to(&self, file_resource: &file::FileResource) -> bool {
        //TODO better error handling here
        let other_file = file::FileResource::create_from_path(&file_resource.path).unwrap();
        other_file.hash() == file_resource.hash()
    }

    fn handle_file_resources(&self, resources: &Vec<file::FileResource>) -> Vec<i32> {
        let mut results = Vec::new();
        for resource in resources {
            if self.system_service.file_exists(&resource.path) && self.file_is_equal_to(&resource) {
                results.push(0);
                continue;
            }
            let result = resource.write_file();
            match result {
                Ok(_) =>  {
                    let msg = format!("==> Wrote file {}", resource.path);
                    logger::print_message(msg, logger::MessageType::Stdout);
                    results.push(0);
                },
                Err(err) => {
                    let msg = format!("==> Error while writing file {}", resource.path);
                    logger::print_message(msg, logger::MessageType::Stderr);
                    logger::print_message(format!("==> {}", err), logger::MessageType::Stderr);
                    results.push(1);
                }
            }
        }
        results
    }
}
<|endoftext|>


<commit_before>use std::process::Command;

#[test]
fn run_lisp_tests() {
    let status = Command::new("cargo")
        .args(&["test"])
        .current_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/lisp"))
        .spawn()
        .expect("should spawn tests OK")
        .wait()
        .expect("should wait OK");
    assert!(status.success());
}
<commit_msg>In optimized builds, run lisp tests with `cargo test --release`.<commit_after>use std::process::Command;

#[test]
fn run_lisp_tests() {
    let mut args = vec!["test"];

    if !cfg!(debug_assertions) {
        args.push("--release");
    }

    let status = Command::new("cargo")
        .args(&args)
        .current_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/lisp"))
        .spawn()
        .expect("should spawn tests OK")
        .wait()
        .expect("should wait OK");
    assert!(status.success());
}
<|endoftext|>


<commit_before>#[test]
#[cfg(not(debug_assertions))]
fn assert_size() {
    use std::mem::size_of;

    use crate::sys;

    // Without debug assertions enabled `TcpListener`, `TcpStream` and `UdpSocket` should have the
    // same size as the system specific socket, i.e. just a file descriptor on Unix platforms.
    assert_eq!(size_of::<TcpListener>(), size_of::<sys::TcpListener>());
    assert_eq!(size_of::<TcpStream>(), size_of::<sys::TcpStream>());
    assert_eq!(size_of::<UdpSocket>(), size_of::<sys::UdpSocket>());
}
<commit_msg>Fix size test<commit_after>use mio::net::*;

#[test]
#[cfg(unix)]
#[cfg(not(debug_assertions))]
fn assert_size() {
    use std::mem::size_of;

    // Without debug assertions enabled `TcpListener`, `TcpStream` and `UdpSocket` should have the
    // same size as the system specific socket, i.e. just a file descriptor on Unix platforms.
    assert_eq!(size_of::<TcpListener>(), size_of::<std::net::TcpListener>());
    assert_eq!(size_of::<TcpStream>(), size_of::<std::net::TcpStream>());
    assert_eq!(size_of::<UdpSocket>(), size_of::<std::net::UdpSocket>());
}
<|endoftext|>


<commit_before>use super::chunk::{Chunk, Chunks};
use super::segs::Segment;

use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::sync::Arc;
use std::time::Duration;
use std::collections::BTreeSet;
use std::collections::Bound::{Included, Unbounded};

use libc;
use parking_lot::MutexGuard;

static MAX_CLEAN_RETRY: u16 = 100;

pub fn ceiling_frag(frags: &MutexGuard<BTreeSet<usize>>, location: usize) -> Option<usize> {
    match frags.range((Included(&location), Unbounded)).next() {
        Some(l) => Some(*l),
        None => None
    }
}

pub struct Cleaner {
    chunks: Arc<Chunks>,
    closed: AtomicBool
}

impl Cleaner {
    pub fn new(chunks: &Arc<Chunks>) -> Arc<Cleaner> {
        let cleaner = Arc::new(Cleaner {
            chunks: chunks.clone(),
            closed: AtomicBool::new(false)
        });
        let cleaner_clone = cleaner.clone();
        thread::spawn(move || {
            let chunks = &cleaner_clone.chunks;
            while !cleaner_clone.closed.load(Ordering::Relaxed) {
                Cleaner::clean_chunks(&chunks);
                thread::sleep(Duration::from_millis(10));
            }
        });
        return cleaner;
    }
    pub fn clean_chunks(chunks: &Arc<Chunks>) {
        for chunk in &chunks.list { // consider put this in separate thread or fiber
            Cleaner::clean_chunk(chunk);
        }
    }
    pub fn clean_chunk(chunk: &Chunk) {
        for seg in &chunk.segs {
            Cleaner::clean_segment(chunk, seg);
        }
    }
    pub fn clean_segment(chunk: &Chunk, seg: &Segment) {
        // Clean only if segment have fragments
        if seg.no_frags() {return;}
        // Retry cleaning the segment if unexpected state discovered
        let mut retried = 0;
        // Lock segment exclusively only if it is not rw locked to avoid waiting for disk backups.
        // There is one potential deadlock with writing cells. Because every cell write operations
        // locks on cell first and then lock it's underlying segment to acquire space, but cleaner
        // will lock segments first then lock the cell to move it to fill the fragments.
        // The solution is to lock the segment first. Before moving the cells, segment lock have to
        // be released and then lock the cell lock. After cell moved, release the cell lock and do
        // further operations on segment with a new segment lock guard.
        // Because the segment will be locked twice, there is no guarantee for not modifying the
        // segment when moving the cell, extra efforts need to taken care of to ensure correctness.
        debug!("Cleaning segment: {}", seg.addr);
        let mut defrag_pos = seg.addr;
        while retried < MAX_CLEAN_RETRY {
            // those are for moving cell next to the fragment after the segment locking block
            // it will be assigned later
            let  mut next_loc: usize = 0;
            let  mut frag_loc: usize = 0;
            {
                let seg_lock = seg.lock.try_write();
                if seg_lock.is_none() {return;}
                // Cleaner defrag pointers only move forward when cleaning fragments. Which means if new
                // fragments produced before our defrag_pos when cleaning the segment, those fragments
                // will be ignored in this cleaning turn and leave to be cleaned up in next turn. This
                // design meant to prevent long term cleaning and give back spaces by resetting append
                // header as soon as possible if the segment procedures fragments all
                // the time
                let mut frags = seg.frags.lock();
                let frag_opt = ceiling_frag(&frags, defrag_pos);
                if frag_opt.is_none() {
                    debug!("No fragments, will exit for segment: {}", seg.addr);
                    return;
                }  // return if there is no fragments to cleaned
                frag_loc = frag_opt.unwrap();
                debug!("Cleaning fragment at {} for segment: {}", frag_loc, seg.addr);
                // The first things we need to do is read the length of the fragment and check it there
                // is a tombstone at the location to make sure there is no corruption. Corruption is
                // unexpected, we can retry in next iteration but I don't think it can be self-healed.
                let frag_version = unsafe {*seg.cell_version(frag_loc)};
                if frag_version != 0 {
                    error!("There is no tombstone at the fragment location: {} - Version: {}",
                    frag_loc, frag_version);
                    retried += 1; continue;
                }
                let frag_len = unsafe {*seg.cell_size(frag_loc)};
                // Next we need to get the location of the cell or fragment next to the fragment
                next_loc = frag_loc + frag_len as usize;
                // Check if it have reached the append header, which is the last fragment. In this case
                // we need to perform a atomic cas on the append header to move it right at the location
                // of the fragment
                if next_loc == seg.append_header.load(Ordering::SeqCst) {
                    if seg.append_header.compare_and_swap(next_loc, frag_loc, Ordering::SeqCst) != next_loc {
                        // it may failed for some reason, we need to retry it
                        debug!("Segment append header moved when cleaning");
                        retried += 1; continue;
                    } else {
                        // if it succeed, the segment have been cleaned in this turn
                        debug!("Clean fragments completed, will exit for segment: {}", seg.addr);
                        frags.remove(&frag_loc); return;
                    }
                }
                // Then we need to discuss the two type of the unit we may encounter
                let next_version = unsafe {*seg.cell_version(next_loc)};
                // if it is a fragment
                if next_version == 0 {
                    if frags.contains(&next_loc) {
                        debug!("Unit next to fragment {} is another fragment {} on record", frag_loc, next_loc);
                        // if there is any record in the segment for the next fragment, we need to
                        // combine it with the fragment we are working on
                        let next_len: u32 = unsafe {*seg.cell_size(next_loc)};
                        debug!("Size of next fragment for {} is : {}", next_loc, next_len);
                        // remove the next fragment
                        frags.remove(&next_loc);
                        // reset size of the tombstone for the fragment we are working on
                        let new_frag_len = seg.cell_size(frag_loc);
                        let new_frag_len_val = frag_len + next_len;
                        unsafe {*new_frag_len = new_frag_len_val;}
                        debug!("Resize fragment {} from {} to {}", frag_loc, frag_len, new_frag_len_val);
                        // reset retry
                        retried = 0;
                        // and move to next iteration
                        continue;
                    } else {
                        // if not, we need to try again
                        retried += 1; continue;
                        debug!("Next fragment not in segment record: {}", next_loc);
                    }
                }
                // if not, it should be an alive cell, we need to release the segment lock to proceed
            }
            // first ensure there is a valid location in 'next_loc'
            if next_loc <= 0 || frag_loc <= 0 {
                error!("next_loc not assigned when trying to move a cell for cleaning");
                retried += 1; continue;
            }
            // we will fetch the cell by it's hash
            let cell_hash = unsafe {*seg.cell_hash(next_loc)};
            // 'cell_loc' will contain a lock to the cell if succeed
            let cell_loc = chunk.location_of(cell_hash);
            // check if the hash exists in the chunk. If not, retry
            if cell_loc.is_none() {
                debug!("Cell hash not exists in the chunk: {}", cell_hash);
                retried += 1; continue;
            }
            let mut cell_loc = cell_loc.unwrap();
            //check if the location of the hash is exactly the as our 'next_loc'. If not, retry
            if *cell_loc != next_loc {
                debug!("Cell location changed: {}", cell_hash);
                retried += 1; continue;
            }
            // after everything all fine, we can lock the segment again with the cell locked first
            let seg_lock = seg.lock.write();
            let mut frags = seg.frags.lock();
            // because the cell is locked, it will always be there in the segment
            let cell_len = unsafe {*seg.cell_size(next_loc)} as usize;
            let frag_len = unsafe {*seg.cell_size(frag_loc)} as usize;
            debug!("Moving cell {} of size {} for fragment {} of size {}", next_loc, cell_len, frag_loc, frag_len);
            // There is only one cleaner for each segment at a time, the fragment will be there for
            // sure. Next we need to do is move the cell to the location of the fragment, update
            // cell index in chunk, put new fragment and tombstone next to the moved cell.
            unsafe {
                libc::memmove(
                    frag_loc as *mut libc::c_void,
                    *cell_loc as *mut libc::c_void,
                    cell_len
                );
            }
            let original_cell_loc = *cell_loc;
            *cell_loc = frag_loc;
            // remove the fragment
            debug!("Removing fragment {}", frag_loc);
            frags.remove(&frag_loc);
            let new_frag_loc = frag_loc + cell_len;
            let new_frag_len = original_cell_loc + cell_len - new_frag_loc;
            debug!("New fragment next to the moved cell {} is {}, size {}", next_loc, new_frag_loc, new_frag_len);
            // insert new fragment next to the moved cell
            frags.insert(new_frag_loc);
            // put tombstone
            seg.put_cell_tombstone(new_frag_loc);
            // write length to the tombstone;
            unsafe {*seg.cell_size(new_frag_loc) = new_frag_len as u32};
            defrag_pos = new_frag_loc;
        }
        debug!("Clean segment completed: {}", seg.addr);
    }
}<commit_msg>reset retried counter to 0 after cell moved<commit_after>use super::chunk::{Chunk, Chunks};
use super::segs::Segment;

use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::sync::Arc;
use std::time::Duration;
use std::collections::BTreeSet;
use std::collections::Bound::{Included, Unbounded};

use libc;
use parking_lot::MutexGuard;

static MAX_CLEAN_RETRY: u16 = 100;

pub fn ceiling_frag(frags: &MutexGuard<BTreeSet<usize>>, location: usize) -> Option<usize> {
    match frags.range((Included(&location), Unbounded)).next() {
        Some(l) => Some(*l),
        None => None
    }
}

pub struct Cleaner {
    chunks: Arc<Chunks>,
    closed: AtomicBool
}

impl Cleaner {
    pub fn new(chunks: &Arc<Chunks>) -> Arc<Cleaner> {
        let cleaner = Arc::new(Cleaner {
            chunks: chunks.clone(),
            closed: AtomicBool::new(false)
        });
        let cleaner_clone = cleaner.clone();
        thread::spawn(move || {
            let chunks = &cleaner_clone.chunks;
            while !cleaner_clone.closed.load(Ordering::Relaxed) {
                Cleaner::clean_chunks(&chunks);
                thread::sleep(Duration::from_millis(10));
            }
        });
        return cleaner;
    }
    pub fn clean_chunks(chunks: &Arc<Chunks>) {
        for chunk in &chunks.list { // consider put this in separate thread or fiber
            Cleaner::clean_chunk(chunk);
        }
    }
    pub fn clean_chunk(chunk: &Chunk) {
        for seg in &chunk.segs {
            Cleaner::clean_segment(chunk, seg);
        }
    }
    pub fn clean_segment(chunk: &Chunk, seg: &Segment) {
        // Clean only if segment have fragments
        if seg.no_frags() {return;}
        // Retry cleaning the segment if unexpected state discovered
        let mut retried = 0;
        // Lock segment exclusively only if it is not rw locked to avoid waiting for disk backups.
        // There is one potential deadlock with writing cells. Because every cell write operations
        // locks on cell first and then lock it's underlying segment to acquire space, but cleaner
        // will lock segments first then lock the cell to move it to fill the fragments.
        // The solution is to lock the segment first. Before moving the cells, segment lock have to
        // be released and then lock the cell lock. After cell moved, release the cell lock and do
        // further operations on segment with a new segment lock guard.
        // Because the segment will be locked twice, there is no guarantee for not modifying the
        // segment when moving the cell, extra efforts need to taken care of to ensure correctness.
        debug!("Cleaning segment: {}", seg.addr);
        let mut defrag_pos = seg.addr;
        while retried < MAX_CLEAN_RETRY {
            // those are for moving cell next to the fragment after the segment locking block
            // it will be assigned later
            let  mut next_loc: usize = 0;
            let  mut frag_loc: usize = 0;
            {
                let seg_lock = seg.lock.try_write();
                if seg_lock.is_none() {return;}
                // Cleaner defrag pointers only move forward when cleaning fragments. Which means if new
                // fragments produced before our defrag_pos when cleaning the segment, those fragments
                // will be ignored in this cleaning turn and leave to be cleaned up in next turn. This
                // design meant to prevent long term cleaning and give back spaces by resetting append
                // header as soon as possible if the segment procedures fragments all
                // the time
                let mut frags = seg.frags.lock();
                let frag_opt = ceiling_frag(&frags, defrag_pos);
                if frag_opt.is_none() {
                    debug!("No fragments, will exit for segment: {}", seg.addr);
                    return;
                }  // return if there is no fragments to cleaned
                frag_loc = frag_opt.unwrap();
                debug!("Cleaning fragment at {} for segment: {}", frag_loc, seg.addr);
                // The first things we need to do is read the length of the fragment and check it there
                // is a tombstone at the location to make sure there is no corruption. Corruption is
                // unexpected, we can retry in next iteration but I don't think it can be self-healed.
                let frag_version = unsafe {*seg.cell_version(frag_loc)};
                if frag_version != 0 {
                    error!("There is no tombstone at the fragment location: {} - Version: {}",
                    frag_loc, frag_version);
                    retried += 1; continue;
                }
                let frag_len = unsafe {*seg.cell_size(frag_loc)};
                // Next we need to get the location of the cell or fragment next to the fragment
                next_loc = frag_loc + frag_len as usize;
                // Check if it have reached the append header, which is the last fragment. In this case
                // we need to perform a atomic cas on the append header to move it right at the location
                // of the fragment
                if next_loc == seg.append_header.load(Ordering::SeqCst) {
                    if seg.append_header.compare_and_swap(next_loc, frag_loc, Ordering::SeqCst) != next_loc {
                        // it may failed for some reason, we need to retry it
                        debug!("Segment append header moved when cleaning");
                        retried += 1; continue;
                    } else {
                        // if it succeed, the segment have been cleaned in this turn
                        debug!("Clean fragments completed, will exit for segment: {}", seg.addr);
                        frags.remove(&frag_loc); return;
                    }
                }
                // Then we need to discuss the two type of the unit we may encounter
                let next_version = unsafe {*seg.cell_version(next_loc)};
                // if it is a fragment
                if next_version == 0 {
                    if frags.contains(&next_loc) {
                        debug!("Unit next to fragment {} is another fragment {} on record", frag_loc, next_loc);
                        // if there is any record in the segment for the next fragment, we need to
                        // combine it with the fragment we are working on
                        let next_len: u32 = unsafe {*seg.cell_size(next_loc)};
                        debug!("Size of next fragment for {} is : {}", next_loc, next_len);
                        // remove the next fragment
                        frags.remove(&next_loc);
                        // reset size of the tombstone for the fragment we are working on
                        let new_frag_len = seg.cell_size(frag_loc);
                        let new_frag_len_val = frag_len + next_len;
                        unsafe {*new_frag_len = new_frag_len_val;}
                        debug!("Resize fragment {} from {} to {}", frag_loc, frag_len, new_frag_len_val);
                        // reset retry
                        retried = 0;
                        // and move to next iteration
                        continue;
                    } else {
                        // if not, we need to try again
                        retried += 1; continue;
                        debug!("Next fragment not in segment record: {}", next_loc);
                    }
                }
                // if not, it should be an alive cell, we need to release the segment lock to proceed
            }
            // first ensure there is a valid location in 'next_loc'
            if next_loc <= 0 || frag_loc <= 0 {
                error!("next_loc not assigned when trying to move a cell for cleaning");
                retried += 1; continue;
            }
            // we will fetch the cell by it's hash
            let cell_hash = unsafe {*seg.cell_hash(next_loc)};
            // 'cell_loc' will contain a lock to the cell if succeed
            let cell_loc = chunk.location_of(cell_hash);
            // check if the hash exists in the chunk. If not, retry
            if cell_loc.is_none() {
                debug!("Cell hash not exists in the chunk: {}", cell_hash);
                retried += 1; continue;
            }
            let mut cell_loc = cell_loc.unwrap();
            //check if the location of the hash is exactly the as our 'next_loc'. If not, retry
            if *cell_loc != next_loc {
                debug!("Cell location changed: {}", cell_hash);
                retried += 1; continue;
            }
            // after everything all fine, we can lock the segment again with the cell locked first
            let seg_lock = seg.lock.write();
            let mut frags = seg.frags.lock();
            // because the cell is locked, it will always be there in the segment
            let cell_len = unsafe {*seg.cell_size(next_loc)} as usize;
            let frag_len = unsafe {*seg.cell_size(frag_loc)} as usize;
            debug!("Moving cell {} of size {} for fragment {} of size {}", next_loc, cell_len, frag_loc, frag_len);
            // There is only one cleaner for each segment at a time, the fragment will be there for
            // sure. Next we need to do is move the cell to the location of the fragment, update
            // cell index in chunk, put new fragment and tombstone next to the moved cell.
            unsafe {
                libc::memmove(
                    frag_loc as *mut libc::c_void,
                    *cell_loc as *mut libc::c_void,
                    cell_len
                );
            }
            let original_cell_loc = *cell_loc;
            *cell_loc = frag_loc;
            // remove the fragment
            debug!("Removing fragment {}", frag_loc);
            frags.remove(&frag_loc);
            let new_frag_loc = frag_loc + cell_len;
            let new_frag_len = original_cell_loc + cell_len - new_frag_loc;
            debug!("New fragment next to the moved cell {} is {}, size {}", next_loc, new_frag_loc, new_frag_len);
            // insert new fragment next to the moved cell
            frags.insert(new_frag_loc);
            // put tombstone
            seg.put_cell_tombstone(new_frag_loc);
            // write length to the tombstone;
            unsafe {*seg.cell_size(new_frag_loc) = new_frag_len as u32};
            retried = 0;
            defrag_pos = new_frag_loc;
        }
        debug!("Clean segment completed: {}", seg.addr);
    }
}<|endoftext|>


<commit_before>extern crate lzma;

use lzma::error::LzmaError;
use std::io::{Read, Cursor, Write};
use std::thread;

const TEST_STRING: &'static str = include_str!("test_file.txt");

#[test]
fn simple_compress_decompress() {
	let mut compressed = lzma::compress(&TEST_STRING.to_string().into_bytes(), 6).unwrap();
	let decompressed = String::from_utf8(lzma::decompress(&mut compressed).unwrap()).unwrap();

	assert!(compressed.len() < TEST_STRING.len());
	assert_eq!(TEST_STRING, decompressed);
}

#[test]
fn extreme() {
	let mut compressed = lzma::compress(&TEST_STRING.to_string().into_bytes(), 9).unwrap();
	let mut extreme_compressed = lzma::compress(&TEST_STRING.to_string().into_bytes(), 9 | lzma::EXTREME_PRESET).unwrap();
	let decompressed = String::from_utf8(lzma::decompress(&mut compressed).unwrap()).unwrap();
	let extreme_decompressed = String::from_utf8(lzma::decompress(&mut extreme_compressed).unwrap()).unwrap();

	// TODO: This test is not great.  We just want to know if the EXTREME_PRESET flag is working.
	// It might occur that the len's are equal because EXTREME wasn't able to compress more (or less).
	assert!(extreme_compressed.len() != compressed.len());
	assert_eq!(TEST_STRING, decompressed);
	assert_eq!(TEST_STRING, extreme_decompressed);
}

#[test]
fn reader_wormhole() {
	let compressor = lzma::LzmaReader::new_compressor(Cursor::new(TEST_STRING), 5).unwrap();
	let mut decompressor = lzma::LzmaReader::new_decompressor(compressor).unwrap();
	let mut s = String::new();

	decompressor.read_to_string(&mut s).unwrap();

	assert_eq!(TEST_STRING, s);
}

#[test]
fn writer_wormhole() {
	let mut output = vec![0u8; 0];
	{
		let decompressor = lzma::LzmaWriter::new_decompressor(&mut output).unwrap();
		let mut compressor = lzma::LzmaWriter::new_compressor(decompressor, 2).unwrap();

		write!(compressor, "{}", TEST_STRING).unwrap();
		compressor.finish().unwrap();
	}

	assert_eq!(TEST_STRING, String::from_utf8(output).unwrap());
}

#[test]
fn truncation_causes_error() {
	let mut compressed = lzma::compress(&"Like tears in rain".to_string().into_bytes(), 6).unwrap();
	let bad_len = compressed.len() - 1;
	compressed.truncate(bad_len);
	match lzma::decompress(&mut compressed) {
		Err(lzma::LzmaError::Io(err)) => {
			match *err.get_ref().unwrap().downcast_ref::<LzmaError>().unwrap() {
				LzmaError::Buf => (),
				_ => panic!("Decompressing a truncated buffer should return an LzmaError::Buf error"),
			}
		},
		_ => panic!("Decompressing a truncated buffer should return an LzmaError::Buf error"),
	}
}

// Test to make sure that LzmaReader implements the Send trait correctly
#[test]
fn reader_thread_send() {
	let compressor = lzma::LzmaReader::new_compressor(Cursor::new(TEST_STRING), 5).unwrap();
	let mut decompressor = lzma::LzmaReader::new_decompressor(compressor).unwrap();

	let output = thread::spawn(move || {
		let mut s = String::new();
		decompressor.read_to_string(&mut s).unwrap();
		s

	}).join().unwrap();

	assert_eq!(TEST_STRING, output);
}
<commit_msg>Added test that exercises weird write_all behavior.<commit_after>extern crate lzma;

use lzma::error::LzmaError;
use std::io::{Read, Cursor, Write};
use std::thread;

const TEST_STRING: &'static str = include_str!("test_file.txt");

#[test]
fn simple_compress_decompress() {
	let mut compressed = lzma::compress(&TEST_STRING.to_string().into_bytes(), 6).unwrap();
	let decompressed = String::from_utf8(lzma::decompress(&mut compressed).unwrap()).unwrap();

	assert!(compressed.len() < TEST_STRING.len());
	assert_eq!(TEST_STRING, decompressed);
}

#[test]
fn extreme() {
	let mut compressed = lzma::compress(&TEST_STRING.to_string().into_bytes(), 9).unwrap();
	let mut extreme_compressed = lzma::compress(&TEST_STRING.to_string().into_bytes(), 9 | lzma::EXTREME_PRESET).unwrap();
	let decompressed = String::from_utf8(lzma::decompress(&mut compressed).unwrap()).unwrap();
	let extreme_decompressed = String::from_utf8(lzma::decompress(&mut extreme_compressed).unwrap()).unwrap();

	// TODO: This test is not great.  We just want to know if the EXTREME_PRESET flag is working.
	// It might occur that the len's are equal because EXTREME wasn't able to compress more (or less).
	assert!(extreme_compressed.len() != compressed.len());
	assert_eq!(TEST_STRING, decompressed);
	assert_eq!(TEST_STRING, extreme_decompressed);
}

#[test]
fn reader_wormhole() {
	let compressor = lzma::LzmaReader::new_compressor(Cursor::new(TEST_STRING), 5).unwrap();
	let mut decompressor = lzma::LzmaReader::new_decompressor(compressor).unwrap();
	let mut s = String::new();

	decompressor.read_to_string(&mut s).unwrap();

	assert_eq!(TEST_STRING, s);
}

#[test]
fn writer_wormhole() {
	let mut output = vec![0u8; 0];
	{
		let decompressor = lzma::LzmaWriter::new_decompressor(&mut output).unwrap();
		let mut compressor = lzma::LzmaWriter::new_compressor(decompressor, 2).unwrap();

		write!(compressor, "{}", TEST_STRING).unwrap();
		compressor.finish().unwrap();
	}

	assert_eq!(TEST_STRING, String::from_utf8(output).unwrap());
}

#[test]
fn truncation_causes_error() {
	let mut compressed = lzma::compress(&"Like tears in rain".to_string().into_bytes(), 6).unwrap();
	let bad_len = compressed.len() - 1;
	compressed.truncate(bad_len);
	match lzma::decompress(&mut compressed) {
		Err(lzma::LzmaError::Io(err)) => {
			match *err.get_ref().unwrap().downcast_ref::<LzmaError>().unwrap() {
				LzmaError::Buf => (),
				_ => panic!("Decompressing a truncated buffer should return an LzmaError::Buf error"),
			}
		},
		_ => panic!("Decompressing a truncated buffer should return an LzmaError::Buf error"),
	}
}

// Test to make sure that LzmaReader implements the Send trait correctly
#[test]
fn reader_thread_send() {
	let compressor = lzma::LzmaReader::new_compressor(Cursor::new(TEST_STRING), 5).unwrap();
	let mut decompressor = lzma::LzmaReader::new_decompressor(compressor).unwrap();

	let output = thread::spawn(move || {
		let mut s = String::new();
		decompressor.read_to_string(&mut s).unwrap();
		s

	}).join().unwrap();

	assert_eq!(TEST_STRING, output);
}

// Decompressing the test string in here causes LZMA to return 0 (bytes consumed from input) occasionally.
// Good for testing that our Writer implementation handles that correctly.
#[test]
fn test_string_1() {
	let input = b"\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21\x01\x12\x00\x00\x00\x23\xb8\x87\x2c\xe1\x20\xff\x00\x4c\x5d\x00\x30\xef\xfb\xbf\xfe\xa3\xb1\x5e\xe5\xf8\x3f\xb2\xaa\x26\x55\xf8\x68\x70\x41\x70\x15\x0f\x8d\xfd\x1e\x4c\x1b\x8a\x42\xb7\x19\xf4\x69\x18\x71\xae\x66\x23\x8a\x8a\x4d\x2f\xa3\x0d\xd9\x7f\xa6\xe3\x8c\x23\x11\x53\xe0\x59\x18\xc5\x75\x8a\xe2\x77\xf8\xb6\x94\x7f\x0c\x6a\xc0\xde\x74\x49\x64\xe2\xe8\x22\xa0\xfd\x00\xb3\xfd\x27\xbc\xcd\x64\x62\xb1\x00\x01\x68\x80\xc2\x04\x00\x00\x29\x67\x59\x4d\xb1\xc4\x67\xfb\x02\x00\x00\x00\x00\x04\x59\x5a";
	let mut buffer = Vec::new();
	{
		let mut writer = lzma::LzmaWriter::new_decompressor(&mut buffer).unwrap();

		writer.write_all(input).unwrap();
		writer.finish().unwrap();
	}
	assert_eq!(buffer.len(), 73984);    // Original string is 73,984 * b'a'.
}<|endoftext|>


<commit_before>extern crate postgres;
extern crate r2d2;
extern crate r2d2_postgres;

use std::default::Default;
use std::sync::{Arc, Future};
use std::comm;

use postgres::NoSsl;
use r2d2_postgres::PostgresPoolManager;
use r2d2_postgres::GenericConnection;

#[test]
fn test_basic() {
    let manager = PostgresPoolManager::new("postgres://postgres@localhost", NoSsl);
    let config = r2d2::Config {
        pool_size: 2,
        ..Default::default()
    };
    let handler = r2d2::NoopErrorHandler;
    let pool = Arc::new(r2d2::Pool::new(config, manager, handler).unwrap());

    let (s1, r1) = comm::channel();
    let (s2, r2) = comm::channel();

    let pool1 = pool.clone();
    let mut fut1 = Future::spawn(proc() {
        let conn = pool1.get().unwrap();
        s1.send(());
        r2.recv();
        drop(conn);
    });

    let pool2 = pool.clone();
    let mut fut2 = Future::spawn(proc() {
        let conn = pool2.get().unwrap();
        s2.send(());
        r1.recv();
        drop(conn);
    });

    fut1.get();
    fut2.get();

    pool.get().unwrap();
}

#[test]
fn test_is_valid() {
    let manager = PostgresPoolManager::new("postgres://postgres@localhost", NoSsl);
    let config = r2d2::Config {
        pool_size: 1,
        test_on_check_out: true,
        ..Default::default()
    };
    let handler = r2d2::NoopErrorHandler;
    let pool = r2d2::Pool::new(config, manager, handler).unwrap();

    pool.get().unwrap();
}

#[test]
fn test_statement_pool() {
    let config = r2d2_postgres::Config { statement_pool_size: 1 };
    let manager = r2d2_postgres::StatementCachingManager::new(
        "postgres://postgres@localhost", NoSsl, config);
    let pool = r2d2::Pool::new(Default::default(), manager, r2d2::NoopErrorHandler).unwrap();

    let conn = pool.get().unwrap();
    let stmt = conn.prepare("SELECT 1::INT").unwrap();
    let stmt2 = conn.prepare("SELECT 1::INT").unwrap();
    assert_eq!(&*stmt as *const _, &*stmt2 as *const _);
    assert_eq!(stmt.query([]).unwrap().next().unwrap().get::<_, i32>(0), 1i32);

    let stmt3 = conn.prepare("SELECT 2::INT").unwrap();
    assert_eq!(stmt3.query([]).unwrap().next().unwrap().get::<_, i32>(0), 2i32);
    let stmt4 = conn.prepare("SELECT 1::INT").unwrap();
    let a = &*stmt as *const _;
    let b = &*stmt4 as *const _;
    assert!(a != b);
    assert_eq!(stmt4.query([]).unwrap().next().unwrap().get::<_, i32>(0), 1i32);
}
<commit_msg>Fix tests<commit_after>extern crate postgres;
extern crate r2d2;
extern crate r2d2_postgres;

use std::default::Default;
use std::sync::{Arc, Future};
use std::comm;

use postgres::SslMode;
use r2d2_postgres::PostgresPoolManager;
use r2d2_postgres::GenericConnection;

#[test]
fn test_basic() {
    let manager = PostgresPoolManager::new("postgres://postgres@localhost", SslMode::None);
    let config = r2d2::Config {
        pool_size: 2,
        ..Default::default()
    };
    let handler = r2d2::NoopErrorHandler;
    let pool = Arc::new(r2d2::Pool::new(config, manager, handler).unwrap());

    let (s1, r1) = comm::channel();
    let (s2, r2) = comm::channel();

    let pool1 = pool.clone();
    let mut fut1 = Future::spawn(proc() {
        let conn = pool1.get().unwrap();
        s1.send(());
        r2.recv();
        drop(conn);
    });

    let pool2 = pool.clone();
    let mut fut2 = Future::spawn(proc() {
        let conn = pool2.get().unwrap();
        s2.send(());
        r1.recv();
        drop(conn);
    });

    fut1.get();
    fut2.get();

    pool.get().unwrap();
}

#[test]
fn test_is_valid() {
    let manager = PostgresPoolManager::new("postgres://postgres@localhost", SslMode::None);
    let config = r2d2::Config {
        pool_size: 1,
        test_on_check_out: true,
        ..Default::default()
    };
    let handler = r2d2::NoopErrorHandler;
    let pool = r2d2::Pool::new(config, manager, handler).unwrap();

    pool.get().unwrap();
}

#[test]
fn test_statement_pool() {
    let config = r2d2_postgres::Config { statement_pool_size: 1 };
    let manager = r2d2_postgres::StatementCachingManager::new(
        "postgres://postgres@localhost", SslMode::None, config);
    let pool = r2d2::Pool::new(Default::default(), manager, r2d2::NoopErrorHandler).unwrap();

    let conn = pool.get().unwrap();
    let stmt = conn.prepare("SELECT 1::INT").unwrap();
    let stmt2 = conn.prepare("SELECT 1::INT").unwrap();
    assert_eq!(&*stmt as *const _, &*stmt2 as *const _);
    assert_eq!(stmt.query([]).unwrap().next().unwrap().get::<_, i32>(0), 1i32);

    let stmt3 = conn.prepare("SELECT 2::INT").unwrap();
    assert_eq!(stmt3.query([]).unwrap().next().unwrap().get::<_, i32>(0), 2i32);
    let stmt4 = conn.prepare("SELECT 1::INT").unwrap();
    let a = &*stmt as *const _;
    let b = &*stmt4 as *const _;
    assert!(a != b);
    assert_eq!(stmt4.query([]).unwrap().next().unwrap().get::<_, i32>(0), 1i32);
}
<|endoftext|>


<commit_before>pub mod parser;
use std::collections::HashMap;
type Direction = String;

/*
 * For some reason, the rustc compiler thinks this is all dead code
 * probably since it's attached to the compiler, and the code that uses
 * these structs is generated, the compiler does not pick up on this
 * that is why this is all marked as allow(dead_code)
 */

#[derive(Debug)]
#[allow(dead_code)]
pub enum Config {
	Set(), // variable -> Symbol
	Exec(Action),
	BindSym(Vec<String>, Action),
	FloatingMod(String),
  Comment()
}

/* some actions are standalone
* they can be executed without a binding
* ie: exec --no-startup-id feh ~/.config/wallpaper.png
*/
#[allow(dead_code)]
#[derive(Debug)]
pub enum Action {
	Exec(Option<Vec<String>>, String), // standalone
	Workspace(String),
	Focus(Direction)
}

// we can just make the String a ref to the Vector of Symbols,
// it doesn't matter, as long as we can access those variables later.
pub struct Variables {
  pub variables: HashMap<String, Vec<String>>,
}

impl<'a> Variables {
  #[allow(dead_code)]
  pub fn new() -> Self {

    Variables {
      variables: HashMap::new(),
    }
  }
  #[allow(dead_code)]
  pub fn set(&mut self, v: String, s: Vec<String>) -> Config {
    match self.variables.contains_key(&v) {
      true => panic!("Duplicate Variable! Variable: {} already exits!", v),
      false => {
        self.variables.insert(v, s);
        Config::Set()
      }
    }
  }

  #[allow(dead_code)]
  pub fn get(&self, k: &str) -> Vec<String> {
    let result = match self.variables.get(k) {
      Some(s) => s,
      None => panic!("Variable: {} not found!", k),
    };

    return result.clone();
  }

  // if there should only be one symbol attached to a variable
  // IE for workspaces
  #[allow(dead_code)]
  pub fn get_single(&'a self, k: &str) -> &'a str {
    match self.variables.get(k) {
      Some(s) => {
        println!("Called!: {}", s[0]);
        if s.len() > 1 {
          panic!("More than one symbol attached to this variable!: {}", k);
        }
        self.variables.get(k).unwrap()[0].as_ref()
      },
      None => panic!("Variable: {} not found!", k),
    }
}
}

<commit_msg>changing Variable HashMap wrapper to &str instead of String to avoid cloning<commit_after>pub mod parser;
use std::collections::HashMap;
type Direction = String;

/*
 * For some reason, the rustc compiler thinks this is all dead code
 * probably since it's attached to the compiler, and the code that uses
 * these structs is generated, the compiler does not pick up on this
 * that is why this is all marked as allow(dead_code)
 */

#[derive(Debug)]
#[allow(dead_code)]
pub enum Config {
	Set(), // variable -> Symbol
	Exec(Action),
	BindSym(Vec<String>, Action),
	FloatingMod(String),
  Comment()
}

/* some actions are standalone
* they can be executed without a binding
* ie: exec --no-startup-id feh ~/.config/wallpaper.png
*/
#[allow(dead_code)]
#[derive(Debug)]
pub enum Action {
	Exec(Option<Vec<String>>, String), // standalone
	Workspace(String),
	Focus(Direction)
}

// we can just make the String a ref to the Vector of Symbols,
// it doesn't matter, as long as we can access those variables later.
pub struct Variables<'a> {
  pub variables: HashMap<String, Vec<&'a str>>,
}

impl<'a> Variables<'a> {
  #[allow(dead_code)]
  pub fn new() -> Self {

    Variables {
      variables: HashMap::new(),
    }
  }
  #[allow(dead_code)]
  pub fn set(&mut self, v: String, s: Vec<&'a str>) -> Config {
    match self.variables.contains_key(&v) {
      true => panic!("Duplicate Variable! Variable: {} already exits!", v),
      false => {
        self.variables.insert(v, s);
        Config::Set()
      }
    }
  }

  #[allow(dead_code)]
  pub fn get(&'a self, k: &str) -> Vec<&'a str> {
    match self.variables.get(k) {
      Some(s) => {
        *s
      },
      None => panic!("Variable: {} not found!", k),
    }

  }

  // if there should only be one symbol attached to a variable
  // IE for workspaces
  #[allow(dead_code)]
  pub fn get_single(&'a self, k: &str) -> &'a str {
    match self.variables.get(k) {
      Some(s) => {
        println!("Called!: {}", s[0]);
        if s.len() > 1 {
          panic!("More than one symbol attached to this variable!: {}", k);
        }
        self.variables.get(k).unwrap()[0].as_ref()
      },
      None => panic!("Variable: {} not found!", k),
    }
}
}

<|endoftext|>


<commit_before>use super::{attr, elem, EncodeContext, ToHtml};
use chrono::{DateTime, Datelike};
use stencila_schema::*;

/// Encode a `Date` to HTML
///
/// Takes a similar approach to the encoding of `Cite` nodes in that it encodes parts
/// of the date as spans which the theme can choose to reorder and/or hide.
impl ToHtml for Date {
    fn to_html(&self, _context: &EncodeContext) -> String {
        let content = match DateTime::parse_from_rfc3339(&self.value) {
            Ok(datetime) => [
                elem("span", &[], &datetime.year().to_string()),
                elem("span", &[], &datetime.month().to_string()),
                elem("span", &[], &datetime.day().to_string()),
            ]
            .concat(),
            Err(error) => {
                tracing::warn!("While parsing date `{}`: {}", self.value, error);
                self.value.clone()
            }
        };
        elem("time", &[attr("datetime", &self.value)], &content)
    }
}

/// Encode a dependency of an executable code node
///
/// Note that for this type, and for `CodeExecutableCodeDependents`, the node being
/// encoded is a _partial_ copy of a node. So any properties encoded here must be copied
/// across in the `node-execute::compile` module.
impl ToHtml for CodeExecutableCodeDependencies {
    fn to_html(&self, _context: &EncodeContext) -> String {
        let (
            node_kind,
            id,
            label,
            programming_language,
            execute_auto,
            execute_required,
            execute_status,
        ) = match self {
            CodeExecutableCodeDependencies::CodeChunk(CodeChunk {
                id,
                label,
                programming_language,
                execute_auto,
                execute_required,
                execute_status,
                ..
            }) => (
                "CodeChunk",
                id,
                label.as_ref().map(|label| label.as_str()),
                Some(programming_language),
                execute_auto
                    .as_ref()
                    .map_or("Needed", |value| value.as_ref()),
                execute_required,
                execute_status,
            ),
            CodeExecutableCodeDependencies::Parameter(Parameter { id, name, .. }) => (
                "Parameter",
                id,
                Some(name.as_str()),
                None,
                "Needed",
                &None,
                &None,
            ),
        };
        elem(
            "stencila-code-dependency",
            &[
                attr("node-kind", node_kind),
                id.as_ref()
                    .map_or("".to_string(), |value| attr("node-id", value.as_str())),
                label
                    .as_ref()
                    .map_or("".to_string(), |value| attr("label", value.as_ref())),
                programming_language
                    .as_ref()
                    .map_or("".to_string(), |value| attr("programming-language", value)),
                attr("execute-auto", execute_auto),
                execute_required.as_ref().map_or("".to_string(), |value| {
                    attr("execute-required", value.as_ref())
                }),
                execute_status.as_ref().map_or("".to_string(), |value| {
                    attr("execute-status", value.as_ref())
                }),
            ],
            "",
        )
    }
}

/// Encode a dependent of an executable code node
impl ToHtml for CodeExecutableCodeDependents {
    fn to_html(&self, _context: &EncodeContext) -> String {
        let (
            node_kind,
            id,
            label,
            programming_language,
            execute_auto,
            execute_required,
            execute_status,
        ) = match self {
            CodeExecutableCodeDependents::CodeChunk(CodeChunk {
                id,
                label,
                programming_language,
                execute_auto,
                execute_required,
                execute_status,
                ..
            }) => (
                "CodeChunk",
                id,
                label,
                programming_language,
                execute_auto
                    .as_ref()
                    .map_or("Needed", |value| value.as_ref()),
                execute_required,
                execute_status,
            ),
            CodeExecutableCodeDependents::CodeExpression(CodeExpression {
                id,
                programming_language,
                execute_required,
                execute_status,
                ..
            }) => (
                "CodeExpression",
                id,
                &None,
                programming_language,
                "Needed",
                execute_required,
                execute_status,
            ),
        };
        elem(
            "stencila-code-dependency",
            &[
                attr("node-kind", node_kind),
                id.as_ref()
                    .map_or("".to_string(), |value| attr("node-id", value.as_str())),
                label
                    .as_ref()
                    .map_or("".to_string(), |value| attr("label", value.as_ref())),
                attr("programming-language", programming_language),
                attr("execute-auto", execute_auto),
                execute_required.as_ref().map_or("".to_string(), |value| {
                    attr("execute-required", value.as_ref())
                }),
                execute_status.as_ref().map_or("".to_string(), |value| {
                    attr("execute-status", value.as_ref())
                }),
            ],
            "",
        )
    }
}
<commit_msg>chore(Rust): Linting fix<commit_after>use super::{attr, elem, EncodeContext, ToHtml};
use chrono::{DateTime, Datelike};
use stencila_schema::*;

/// Encode a `Date` to HTML
///
/// Takes a similar approach to the encoding of `Cite` nodes in that it encodes parts
/// of the date as spans which the theme can choose to reorder and/or hide.
impl ToHtml for Date {
    fn to_html(&self, _context: &EncodeContext) -> String {
        let content = match DateTime::parse_from_rfc3339(&self.value) {
            Ok(datetime) => [
                elem("span", &[], &datetime.year().to_string()),
                elem("span", &[], &datetime.month().to_string()),
                elem("span", &[], &datetime.day().to_string()),
            ]
            .concat(),
            Err(error) => {
                tracing::warn!("While parsing date `{}`: {}", self.value, error);
                self.value.clone()
            }
        };
        elem("time", &[attr("datetime", &self.value)], &content)
    }
}

/// Encode a dependency of an executable code node
///
/// Note that for this type, and for `CodeExecutableCodeDependents`, the node being
/// encoded is a _partial_ copy of a node. So any properties encoded here must be copied
/// across in the `node-execute::compile` module.
impl ToHtml for CodeExecutableCodeDependencies {
    fn to_html(&self, _context: &EncodeContext) -> String {
        let (
            node_kind,
            id,
            label,
            programming_language,
            execute_auto,
            execute_required,
            execute_status,
        ) = match self {
            CodeExecutableCodeDependencies::CodeChunk(CodeChunk {
                id,
                label,
                programming_language,
                execute_auto,
                execute_required,
                execute_status,
                ..
            }) => (
                "CodeChunk",
                id,
                label.as_ref().map(|label| label.as_str()),
                Some(programming_language),
                execute_auto
                    .as_ref()
                    .map_or("Needed", |value| value.as_ref()),
                execute_required,
                execute_status,
            ),
            CodeExecutableCodeDependencies::Parameter(Parameter { id, name, .. }) => (
                "Parameter",
                id,
                Some(name.as_str()),
                None,
                "Needed",
                &None,
                &None,
            ),
        };
        elem(
            "stencila-code-dependency",
            &[
                attr("node-kind", node_kind),
                id.as_ref()
                    .map_or("".to_string(), |value| attr("node-id", value.as_str())),
                label
                    .as_ref()
                    .map_or("".to_string(), |value| attr("label", value)),
                programming_language
                    .as_ref()
                    .map_or("".to_string(), |value| attr("programming-language", value)),
                attr("execute-auto", execute_auto),
                execute_required.as_ref().map_or("".to_string(), |value| {
                    attr("execute-required", value.as_ref())
                }),
                execute_status.as_ref().map_or("".to_string(), |value| {
                    attr("execute-status", value.as_ref())
                }),
            ],
            "",
        )
    }
}

/// Encode a dependent of an executable code node
impl ToHtml for CodeExecutableCodeDependents {
    fn to_html(&self, _context: &EncodeContext) -> String {
        let (
            node_kind,
            id,
            label,
            programming_language,
            execute_auto,
            execute_required,
            execute_status,
        ) = match self {
            CodeExecutableCodeDependents::CodeChunk(CodeChunk {
                id,
                label,
                programming_language,
                execute_auto,
                execute_required,
                execute_status,
                ..
            }) => (
                "CodeChunk",
                id,
                label,
                programming_language,
                execute_auto
                    .as_ref()
                    .map_or("Needed", |value| value.as_ref()),
                execute_required,
                execute_status,
            ),
            CodeExecutableCodeDependents::CodeExpression(CodeExpression {
                id,
                programming_language,
                execute_required,
                execute_status,
                ..
            }) => (
                "CodeExpression",
                id,
                &None,
                programming_language,
                "Needed",
                execute_required,
                execute_status,
            ),
        };
        elem(
            "stencila-code-dependency",
            &[
                attr("node-kind", node_kind),
                id.as_ref()
                    .map_or("".to_string(), |value| attr("node-id", value.as_str())),
                label
                    .as_ref()
                    .map_or("".to_string(), |value| attr("label", value.as_ref())),
                attr("programming-language", programming_language),
                attr("execute-auto", execute_auto),
                execute_required.as_ref().map_or("".to_string(), |value| {
                    attr("execute-required", value.as_ref())
                }),
                execute_status.as_ref().map_or("".to_string(), |value| {
                    attr("execute-status", value.as_ref())
                }),
            ],
            "",
        )
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLError, WebGLRenderbufferId, WebGLResult};
use dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as WebGl2Constants;
use dom::bindings::codegen::Bindings::WebGLRenderbufferBinding;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use dom::bindings::inheritance::Castable;
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::webglobject::WebGLObject;
use dom::webglrenderingcontext::{WebGLRenderingContext, is_gles};
use dom_struct::dom_struct;
use std::cell::Cell;

#[dom_struct]
pub struct WebGLRenderbuffer {
    webgl_object: WebGLObject,
    id: WebGLRenderbufferId,
    ever_bound: Cell<bool>,
    is_deleted: Cell<bool>,
    size: Cell<Option<(i32, i32)>>,
    internal_format: Cell<Option<u32>>,
    is_initialized: Cell<bool>,
}

impl WebGLRenderbuffer {
    fn new_inherited(context: &WebGLRenderingContext, id: WebGLRenderbufferId) -> Self {
        Self {
            webgl_object: WebGLObject::new_inherited(context),
            id: id,
            ever_bound: Cell::new(false),
            is_deleted: Cell::new(false),
            internal_format: Cell::new(None),
            size: Cell::new(None),
            is_initialized: Cell::new(false),
        }
    }

    pub fn maybe_new(context: &WebGLRenderingContext) -> Option<DomRoot<Self>> {
        let (sender, receiver) = webgl_channel().unwrap();
        context.send_command(WebGLCommand::CreateRenderbuffer(sender));
        receiver
            .recv()
            .unwrap()
            .map(|id| WebGLRenderbuffer::new(context, id))
    }

    pub fn new(context: &WebGLRenderingContext, id: WebGLRenderbufferId) -> DomRoot<Self> {
        reflect_dom_object(
            Box::new(WebGLRenderbuffer::new_inherited(context, id)),
            &*context.global(),
            WebGLRenderbufferBinding::Wrap,
        )
    }
}

impl WebGLRenderbuffer {
    pub fn id(&self) -> WebGLRenderbufferId {
        self.id
    }

    pub fn size(&self) -> Option<(i32, i32)> {
        self.size.get()
    }

    pub fn internal_format(&self) -> u32 {
        self.internal_format.get().unwrap_or(constants::RGBA4)
    }

    pub fn mark_initialized(&self) {
        self.is_initialized.set(true);
    }

    pub fn is_initialized(&self) -> bool {
        self.is_initialized.get()
    }

    pub fn bind(&self, target: u32) {
        self.ever_bound.set(true);
        self.upcast::<WebGLObject>()
            .context()
            .send_command(WebGLCommand::BindRenderbuffer(target, Some(self.id)));
    }

    pub fn delete(&self) {
        if !self.is_deleted.get() {
            self.is_deleted.set(true);

            /*
            If a renderbuffer object is deleted while its image is attached to the currently
            bound framebuffer, then it is as if FramebufferRenderbuffer had been called, with
            a renderbuffer of 0, for each attachment point to which this image was attached
            in the currently bound framebuffer.
            - GLES 2.0, 4.4.3, "Attaching Renderbuffer Images to a Framebuffer"
             */
            let currently_bound_framebuffer =
                self.upcast::<WebGLObject>().context().bound_framebuffer();
            if let Some(fb) = currently_bound_framebuffer {
                fb.detach_renderbuffer(self);
            }

            self.upcast::<WebGLObject>()
                .context()
                .send_command(WebGLCommand::DeleteRenderbuffer(self.id));
        }
    }

    pub fn is_deleted(&self) -> bool {
        self.is_deleted.get()
    }

    pub fn ever_bound(&self) -> bool {
        self.ever_bound.get()
    }

    pub fn storage(&self, internal_format: u32, width: i32, height: i32) -> WebGLResult<()> {
        // Validate the internal_format, and save it for completeness
        // validation.
        let actual_format = match internal_format {
            constants::RGBA4 |
            constants::DEPTH_COMPONENT16 |
            constants::STENCIL_INDEX8 |
            // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.7
            constants::DEPTH_STENCIL => internal_format,
            constants::RGB5_A1 => {
                // 16-bit RGBA formats are not supported on desktop GL.
                if is_gles() {
                    constants::RGB5_A1
                } else {
                    WebGl2Constants::RGBA8
                }
            }
            constants::RGB565 => {
                // RGB565 is not supported on desktop GL.
                if is_gles() {
                    constants::RGB565
                } else {
                    WebGl2Constants::RGB8
                }
            }
            _ => return Err(WebGLError::InvalidEnum),
        };

        self.internal_format.set(Some(internal_format));
        self.is_initialized.set(false);

        // FIXME: Invalidate completeness after the call

        self.upcast::<WebGLObject>()
            .context()
            .send_command(WebGLCommand::RenderbufferStorage(
                constants::RENDERBUFFER,
                actual_format,
                width,
                height,
            ));

        self.size.set(Some((width, height)));

        Ok(())
    }
}
<commit_msg>webgl: Use standard texture format for WebGL-specific DEPTH_STENCIL format.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLError, WebGLRenderbufferId, WebGLResult};
use dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as WebGl2Constants;
use dom::bindings::codegen::Bindings::WebGLRenderbufferBinding;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use dom::bindings::inheritance::Castable;
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::webglobject::WebGLObject;
use dom::webglrenderingcontext::{WebGLRenderingContext, is_gles};
use dom_struct::dom_struct;
use std::cell::Cell;

#[dom_struct]
pub struct WebGLRenderbuffer {
    webgl_object: WebGLObject,
    id: WebGLRenderbufferId,
    ever_bound: Cell<bool>,
    is_deleted: Cell<bool>,
    size: Cell<Option<(i32, i32)>>,
    internal_format: Cell<Option<u32>>,
    is_initialized: Cell<bool>,
}

impl WebGLRenderbuffer {
    fn new_inherited(context: &WebGLRenderingContext, id: WebGLRenderbufferId) -> Self {
        Self {
            webgl_object: WebGLObject::new_inherited(context),
            id: id,
            ever_bound: Cell::new(false),
            is_deleted: Cell::new(false),
            internal_format: Cell::new(None),
            size: Cell::new(None),
            is_initialized: Cell::new(false),
        }
    }

    pub fn maybe_new(context: &WebGLRenderingContext) -> Option<DomRoot<Self>> {
        let (sender, receiver) = webgl_channel().unwrap();
        context.send_command(WebGLCommand::CreateRenderbuffer(sender));
        receiver
            .recv()
            .unwrap()
            .map(|id| WebGLRenderbuffer::new(context, id))
    }

    pub fn new(context: &WebGLRenderingContext, id: WebGLRenderbufferId) -> DomRoot<Self> {
        reflect_dom_object(
            Box::new(WebGLRenderbuffer::new_inherited(context, id)),
            &*context.global(),
            WebGLRenderbufferBinding::Wrap,
        )
    }
}

impl WebGLRenderbuffer {
    pub fn id(&self) -> WebGLRenderbufferId {
        self.id
    }

    pub fn size(&self) -> Option<(i32, i32)> {
        self.size.get()
    }

    pub fn internal_format(&self) -> u32 {
        self.internal_format.get().unwrap_or(constants::RGBA4)
    }

    pub fn mark_initialized(&self) {
        self.is_initialized.set(true);
    }

    pub fn is_initialized(&self) -> bool {
        self.is_initialized.get()
    }

    pub fn bind(&self, target: u32) {
        self.ever_bound.set(true);
        self.upcast::<WebGLObject>()
            .context()
            .send_command(WebGLCommand::BindRenderbuffer(target, Some(self.id)));
    }

    pub fn delete(&self) {
        if !self.is_deleted.get() {
            self.is_deleted.set(true);

            /*
            If a renderbuffer object is deleted while its image is attached to the currently
            bound framebuffer, then it is as if FramebufferRenderbuffer had been called, with
            a renderbuffer of 0, for each attachment point to which this image was attached
            in the currently bound framebuffer.
            - GLES 2.0, 4.4.3, "Attaching Renderbuffer Images to a Framebuffer"
             */
            let currently_bound_framebuffer =
                self.upcast::<WebGLObject>().context().bound_framebuffer();
            if let Some(fb) = currently_bound_framebuffer {
                fb.detach_renderbuffer(self);
            }

            self.upcast::<WebGLObject>()
                .context()
                .send_command(WebGLCommand::DeleteRenderbuffer(self.id));
        }
    }

    pub fn is_deleted(&self) -> bool {
        self.is_deleted.get()
    }

    pub fn ever_bound(&self) -> bool {
        self.ever_bound.get()
    }

    pub fn storage(&self, internal_format: u32, width: i32, height: i32) -> WebGLResult<()> {
        // Validate the internal_format, and save it for completeness
        // validation.
        let actual_format = match internal_format {
            constants::RGBA4 |
            constants::DEPTH_COMPONENT16 |
            constants::STENCIL_INDEX8 => internal_format,
            // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.8
            constants::DEPTH_STENCIL => WebGl2Constants::DEPTH24_STENCIL8,
            constants::RGB5_A1 => {
                // 16-bit RGBA formats are not supported on desktop GL.
                if is_gles() {
                    constants::RGB5_A1
                } else {
                    WebGl2Constants::RGBA8
                }
            }
            constants::RGB565 => {
                // RGB565 is not supported on desktop GL.
                if is_gles() {
                    constants::RGB565
                } else {
                    WebGl2Constants::RGB8
                }
            }
            _ => return Err(WebGLError::InvalidEnum),
        };

        self.internal_format.set(Some(internal_format));
        self.is_initialized.set(false);

        // FIXME: Invalidate completeness after the call

        self.upcast::<WebGLObject>()
            .context()
            .send_command(WebGLCommand::RenderbufferStorage(
                constants::RENDERBUFFER,
                actual_format,
                width,
                height,
            ));

        self.size.set(Some((width, height)));

        Ok(())
    }
}
<|endoftext|>


<commit_before>use insta::assert_debug_snapshot_matches;
use ra_ide_api::{
    mock_analysis::{single_file, single_file_with_position, MockAnalysis},
    AnalysisChange, CrateGraph, FileId, Query, NavigationTarget,
};
use ra_syntax::{TextRange, SmolStr};

#[test]
fn test_unresolved_module_diagnostic() {
    let (analysis, file_id) = single_file("mod foo;");
    let diagnostics = analysis.diagnostics(file_id).unwrap();
    assert_debug_snapshot_matches!("unresolved_module_diagnostic", &diagnostics);
}

// FIXME: move this test to hir
#[test]
fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
    let (analysis, file_id) = single_file("mod foo {}");
    let diagnostics = analysis.diagnostics(file_id).unwrap();
    assert!(diagnostics.is_empty());
}

#[test]
fn test_resolve_crate_root() {
    let mock = MockAnalysis::with_files(
        "
        //- /bar.rs
        mod foo;
        //- /foo.rs
        // empty <|>
    ",
    );
    let root_file = mock.id_of("/bar.rs");
    let mod_file = mock.id_of("/foo.rs");
    let mut host = mock.analysis_host();
    assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());

    let mut crate_graph = CrateGraph::default();
    let crate_id = crate_graph.add_crate_root(root_file);
    let mut change = AnalysisChange::new();
    change.set_crate_graph(crate_graph);
    host.apply_change(change);

    assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]);
}

fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
    let (analysis, position) = single_file_with_position(text);
    analysis.find_all_refs(position).unwrap()
}

fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
    let (analysis, _) = single_file(text);
    analysis.symbol_search(Query::new(query.into())).unwrap()
}

#[test]
fn test_find_all_refs_for_local() {
    let code = r#"
    fn main() {
        let mut i = 1;
        let j = 1;
        i = i<|> + j;

        {
            i = 0;
        }

        i = 5;
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 5);
}

#[test]
fn test_find_all_refs_for_param_inside() {
    let code = r#"
    fn foo(i : u32) -> u32 {
        i<|>
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 2);
}

#[test]
fn test_find_all_refs_for_fn_param() {
    let code = r#"
    fn foo(i<|> : u32) -> u32 {
        i
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 2);
}

#[test]
fn test_world_symbols_with_no_container() {
    {
        let code = r#"
        enum FooInner { }
        "#;

        let mut symbols = get_symbols_matching(code, "FooInner");

        let s = symbols.pop().unwrap();

        assert_eq!(s.name(), "FooInner");
        assert!(s.container_name().is_none());
    }
}

#[test]
fn test_world_symbols_include_container_name() {
    {
        let code = r#"
    fn foo() {
        enum FooInner { }
    }
        "#;

        let mut symbols = get_symbols_matching(code, "FooInner");

        let s = symbols.pop().unwrap();

        assert_eq!(s.name(), "FooInner");
        assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
    }

    {
        let code = r#"
    mod foo {
        struct FooInner;
    }
        "#;

        let mut symbols = get_symbols_matching(code, "FooInner");

        let s = symbols.pop().unwrap();

        assert_eq!(s.name(), "FooInner");
        assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
    }
}

#[test]
#[ignore]
fn world_symbols_include_stuff_from_macros() {
    let (analysis, _) = single_file(
        "
salsa::query_group! {
pub trait HirDatabase: SyntaxDatabase {}
}
    ",
    );

    let mut symbols = analysis.symbol_search(Query::new("Hir".into())).unwrap();
    let s = symbols.pop().unwrap();
    assert_eq!(s.name(), "HirDatabase");
    assert_eq!(s.full_range(), TextRange::from_to(33.into(), 44.into()));
}
<commit_msg>Remove unnecessary braces<commit_after>use insta::assert_debug_snapshot_matches;
use ra_ide_api::{
    mock_analysis::{single_file, single_file_with_position, MockAnalysis},
    AnalysisChange, CrateGraph, FileId, Query, NavigationTarget,
};
use ra_syntax::{TextRange, SmolStr};

#[test]
fn test_unresolved_module_diagnostic() {
    let (analysis, file_id) = single_file("mod foo;");
    let diagnostics = analysis.diagnostics(file_id).unwrap();
    assert_debug_snapshot_matches!("unresolved_module_diagnostic", &diagnostics);
}

// FIXME: move this test to hir
#[test]
fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
    let (analysis, file_id) = single_file("mod foo {}");
    let diagnostics = analysis.diagnostics(file_id).unwrap();
    assert!(diagnostics.is_empty());
}

#[test]
fn test_resolve_crate_root() {
    let mock = MockAnalysis::with_files(
        "
        //- /bar.rs
        mod foo;
        //- /foo.rs
        // empty <|>
    ",
    );
    let root_file = mock.id_of("/bar.rs");
    let mod_file = mock.id_of("/foo.rs");
    let mut host = mock.analysis_host();
    assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());

    let mut crate_graph = CrateGraph::default();
    let crate_id = crate_graph.add_crate_root(root_file);
    let mut change = AnalysisChange::new();
    change.set_crate_graph(crate_graph);
    host.apply_change(change);

    assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]);
}

fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
    let (analysis, position) = single_file_with_position(text);
    analysis.find_all_refs(position).unwrap()
}

fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
    let (analysis, _) = single_file(text);
    analysis.symbol_search(Query::new(query.into())).unwrap()
}

#[test]
fn test_find_all_refs_for_local() {
    let code = r#"
    fn main() {
        let mut i = 1;
        let j = 1;
        i = i<|> + j;

        {
            i = 0;
        }

        i = 5;
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 5);
}

#[test]
fn test_find_all_refs_for_param_inside() {
    let code = r#"
    fn foo(i : u32) -> u32 {
        i<|>
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 2);
}

#[test]
fn test_find_all_refs_for_fn_param() {
    let code = r#"
    fn foo(i<|> : u32) -> u32 {
        i
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 2);
}

#[test]
fn test_world_symbols_with_no_container() {
    let code = r#"
    enum FooInner { }
    "#;

    let mut symbols = get_symbols_matching(code, "FooInner");

    let s = symbols.pop().unwrap();

    assert_eq!(s.name(), "FooInner");
    assert!(s.container_name().is_none());
}

#[test]
fn test_world_symbols_include_container_name() {
    let code = r#"
fn foo() {
    enum FooInner { }
}
    "#;

    let mut symbols = get_symbols_matching(code, "FooInner");

    let s = symbols.pop().unwrap();

    assert_eq!(s.name(), "FooInner");
    assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));

    let code = r#"
mod foo {
    struct FooInner;
}
    "#;

    let mut symbols = get_symbols_matching(code, "FooInner");

    let s = symbols.pop().unwrap();

    assert_eq!(s.name(), "FooInner");
    assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
}

#[test]
#[ignore]
fn world_symbols_include_stuff_from_macros() {
    let (analysis, _) = single_file(
        "
salsa::query_group! {
pub trait HirDatabase: SyntaxDatabase {}
}
    ",
    );

    let mut symbols = analysis.symbol_search(Query::new("Hir".into())).unwrap();
    let s = symbols.pop().unwrap();
    assert_eq!(s.name(), "HirDatabase");
    assert_eq!(s.full_range(), TextRange::from_to(33.into(), 44.into()));
}
<|endoftext|>