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

use rocksdb_ffi::{self, DBCompressionType, DBRecoveryMode};
use merge_operator::{self, MergeOperatorCallback, full_merge_callback,
                     partial_merge_callback};
use comparator::{self, ComparatorCallback, compare_callback};
use merge_operator::MergeFn;

pub struct BlockBasedOptions {
    inner: rocksdb_ffi::DBBlockBasedTableOptions,
}

pub struct Options {
    pub inner: rocksdb_ffi::DBOptions,
}

pub struct WriteOptions {
    pub inner: rocksdb_ffi::DBWriteOptions,
}

impl Drop for Options {
    fn drop(&mut self) {
        unsafe {
            rocksdb_ffi::rocksdb_options_destroy(self.inner);
        }
    }
}

impl Drop for BlockBasedOptions {
    fn drop(&mut self) {
        unsafe {
            rocksdb_ffi::rocksdb_block_based_options_destroy(self.inner);
        }
    }
}

impl Drop for WriteOptions {
    fn drop(&mut self) {
        unsafe {
            rocksdb_ffi::rocksdb_writeoptions_destroy(self.inner);
        }
    }
}

impl Default for BlockBasedOptions {
    fn default() -> BlockBasedOptions {
        let block_opts =
            unsafe { rocksdb_ffi::rocksdb_block_based_options_create() };
        let rocksdb_ffi::DBBlockBasedTableOptions(opt_ptr) = block_opts;
        if opt_ptr.is_null() {
            panic!("Could not create rocksdb block based options".to_string());
        }
        BlockBasedOptions { inner: block_opts }
    }
}

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

    pub fn set_block_size(&mut self, size: usize) {
        unsafe {
            rocksdb_ffi::rocksdb_block_based_options_set_block_size(self.inner,
                                                                    size);
        }
    }

    pub fn set_lru_cache(&mut self, size: size_t) {
        let cache = rocksdb_ffi::new_cache(size);
        unsafe {
            // because cache is wrapped in shared_ptr, so we don't need to call
            // rocksdb_cache_destroy explicitly.
            rocksdb_ffi::rocksdb_block_based_options_set_block_cache(self.inner, cache);
        }
    }

    pub fn set_bloom_filter(&mut self,
                            bits_per_key: c_int,
                            block_based: bool) {
        unsafe {
            let bloom = if block_based {
                rocksdb_ffi::rocksdb_filterpolicy_create_bloom(bits_per_key)
            } else {
                rocksdb_ffi::rocksdb_filterpolicy_create_bloom_full(bits_per_key)
            };

            rocksdb_ffi::rocksdb_block_based_options_set_filter_policy(self.inner,
                                                                       bloom);
        }
    }

    pub fn set_cache_index_and_filter_blocks(&mut self, v: bool) {
        unsafe {
            rocksdb_ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks(self.inner,
                                                                                v as u8);
        }
    }
}

// TODO figure out how to create these in a Rusty way
// /pub fn set_filter(&mut self, filter: rocksdb_ffi::DBFilterPolicy) {
// /    unsafe {
// /        rocksdb_ffi::rocksdb_block_based_options_set_filter_policy(
// /            self.inner, filter);
// /    }
// /}

// /pub fn set_cache(&mut self, cache: rocksdb_ffi::DBCache) {
// /    unsafe {
// /        rocksdb_ffi::rocksdb_block_based_options_set_block_cache(
// /            self.inner, cache);
// /    }
// /}

// /pub fn set_cache_compressed(&mut self, cache: rocksdb_ffi::DBCache) {
// /    unsafe {
// /        rocksdb_ffi::
// rocksdb_block_based_options_set_block_cache_compressed(
// /            self.inner, cache);
// /    }
// /}

impl Default for Options {
    fn default() -> Options {
        unsafe {
            let opts = rocksdb_ffi::rocksdb_options_create();
            let rocksdb_ffi::DBOptions(opt_ptr) = opts;
            if opt_ptr.is_null() {
                panic!("Could not create rocksdb options".to_string());
            }
            Options { inner: opts }
        }
    }
}

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

    pub fn increase_parallelism(&mut self, parallelism: i32) {
        unsafe {
            rocksdb_ffi::rocksdb_options_increase_parallelism(self.inner,
                                                              parallelism);
        }
    }

    pub fn optimize_level_style_compaction(&mut self,
                                           memtable_memory_budget: i32) {
        unsafe {
            rocksdb_ffi::rocksdb_options_optimize_level_style_compaction(
                self.inner, memtable_memory_budget);
        }
    }

    pub fn create_if_missing(&mut self, create_if_missing: bool) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_create_if_missing(
                self.inner, create_if_missing);
        }
    }

    pub fn compression(&mut self, t: DBCompressionType) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_compression(self.inner, t);
        }
    }

    pub fn compression_per_level(&mut self,
                                 level_types: &[DBCompressionType]) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_compression_per_level(self.inner,
                                                                level_types.as_ptr(),
                                                                level_types.len() as size_t)
        }
    }

    pub fn add_merge_operator(&mut self, name: &str, merge_fn: MergeFn) {
        let cb = Box::new(MergeOperatorCallback {
            name: CString::new(name.as_bytes()).unwrap(),
            merge_fn: merge_fn,
        });

        unsafe {
            let mo = rocksdb_ffi::rocksdb_mergeoperator_create(
                mem::transmute(cb),
                merge_operator::destructor_callback,
                full_merge_callback,
                partial_merge_callback,
                None,
                merge_operator::name_callback);
            rocksdb_ffi::rocksdb_options_set_merge_operator(self.inner, mo);
        }
    }

    pub fn add_comparator(&mut self,
                          name: &str,
                          compare_fn: fn(&[u8], &[u8]) -> i32) {
        let cb = Box::new(ComparatorCallback {
            name: CString::new(name.as_bytes()).unwrap(),
            f: compare_fn,
        });

        unsafe {
            let cmp = rocksdb_ffi::rocksdb_comparator_create(
                mem::transmute(cb),
                comparator::destructor_callback,
                compare_callback,
                comparator::name_callback);
            rocksdb_ffi::rocksdb_options_set_comparator(self.inner, cmp);
        }
    }

    pub fn set_block_cache_size_mb(&mut self, cache_size: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_optimize_for_point_lookup(self.inner,
                                                                   cache_size);
        }
    }

    pub fn set_max_open_files(&mut self, nfiles: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_open_files(self.inner, nfiles);
        }
    }

    pub fn set_use_fsync(&mut self, useit: bool) {
        unsafe {
            if useit {
                rocksdb_ffi::rocksdb_options_set_use_fsync(self.inner, 1)
            } else {
                rocksdb_ffi::rocksdb_options_set_use_fsync(self.inner, 0)
            }
        }
    }

    pub fn set_bytes_per_sync(&mut self, nbytes: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_bytes_per_sync(self.inner, nbytes);
        }
    }

    pub fn set_disable_data_sync(&mut self, disable: bool) {
        unsafe {
            if disable {
                rocksdb_ffi::rocksdb_options_set_disable_data_sync(self.inner,
                                                                   1);
            } else {
                rocksdb_ffi::rocksdb_options_set_disable_data_sync(self.inner,
                                                                   0);
            }
        }
    }

    pub fn allow_os_buffer(&mut self, is_allow: bool) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_allow_os_buffer(self.inner,
                                                             is_allow);
        }
    }

    pub fn set_table_cache_num_shard_bits(&mut self, nbits: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_table_cache_numshardbits(self.inner,
                                                                      nbits);
        }
    }

    pub fn set_min_write_buffer_number(&mut self, nbuf: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_min_write_buffer_number_to_merge(
                self.inner, nbuf);
        }
    }

    pub fn set_max_write_buffer_number(&mut self, nbuf: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_write_buffer_number(self.inner,
                                                                     nbuf);
        }
    }

    pub fn set_write_buffer_size(&mut self, size: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_write_buffer_size(self.inner,
                                                               size);
        }
    }

    pub fn set_max_bytes_for_level_base(&mut self, size: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_bytes_for_level_base(self.inner, size);
        }
    }

    pub fn set_max_bytes_for_level_multiplier(&mut self, mul: i32) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_bytes_for_level_multiplier(self.inner, mul);
        }
    }

    pub fn set_target_file_size_base(&mut self, size: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_target_file_size_base(self.inner,
                                                                   size);
        }
    }

    pub fn set_min_write_buffer_number_to_merge(&mut self, to_merge: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_min_write_buffer_number_to_merge(
                self.inner, to_merge);
        }
    }

    pub fn set_level_zero_file_num_compaction_trigger(&mut self, n: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_level0_file_num_compaction_trigger(
                self.inner, n);
        }
    }

    pub fn set_level_zero_slowdown_writes_trigger(&mut self, n: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_level0_slowdown_writes_trigger(
                self.inner, n);
        }
    }

    pub fn set_level_zero_stop_writes_trigger(&mut self, n: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_level0_stop_writes_trigger(
                self.inner, n);
        }
    }

    pub fn set_compaction_style(&mut self,
                                style: rocksdb_ffi::DBCompactionStyle) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_compaction_style(self.inner,
                                                              style);
        }
    }

    pub fn set_max_background_compactions(&mut self, n: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_background_compactions(
                self.inner, n);
        }
    }

    pub fn set_max_background_flushes(&mut self, n: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_background_flushes(self.inner,
                                                                    n);
        }
    }

    pub fn set_filter_deletes(&mut self, filter: bool) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_filter_deletes(self.inner, filter);
        }
    }

    pub fn set_disable_auto_compactions(&mut self, disable: bool) {
        unsafe {
            if disable {
                rocksdb_ffi::rocksdb_options_set_disable_auto_compactions(self.inner, 1)
            } else {
                rocksdb_ffi::rocksdb_options_set_disable_auto_compactions(self.inner, 0)
            }
        }
    }

    pub fn set_block_based_table_factory(&mut self,
                                         factory: &BlockBasedOptions) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_block_based_table_factory(self.inner, factory.inner);
        }
    }

    pub fn set_report_bg_io_stats(&mut self, enable: bool) {
        unsafe {
            if enable {
                rocksdb_ffi::rocksdb_options_set_report_bg_io_stats(self.inner,
                                                                    1);
            } else {
                rocksdb_ffi::rocksdb_options_set_report_bg_io_stats(self.inner,
                                                                    0);
            }
        }
    }

    pub fn set_wal_recovery_mode(&mut self, mode: DBRecoveryMode) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_wal_recovery_mode(self.inner, mode);
        }
    }
}

impl Default for WriteOptions {
    fn default() -> WriteOptions {
        let write_opts = unsafe { rocksdb_ffi::rocksdb_writeoptions_create() };
        let rocksdb_ffi::DBWriteOptions(opt_ptr) = write_opts;
        if opt_ptr.is_null() {
            panic!("Could not create rocksdb write options".to_string());
        }
        WriteOptions { inner: write_opts }
    }
}

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

    pub fn set_sync(&mut self, sync: bool) {
        unsafe {
            rocksdb_ffi::rocksdb_writeoptions_set_sync(self.inner, sync);
        }
    }

    pub fn disable_wal(&mut self, disable: bool) {
        unsafe {
            if disable {
                rocksdb_ffi::rocksdb_writeoptions_disable_WAL(self.inner, 1);
            } else {
                rocksdb_ffi::rocksdb_writeoptions_disable_WAL(self.inner, 0);
            }
        }
    }
}
<commit_msg>add set_max_manifest_file_size for Options (#33)<commit_after>// Copyright 2014 Tyler Neely
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
use libc::{c_int, size_t};
use std::ffi::CString;
use std::mem;

use rocksdb_ffi::{self, DBCompressionType, DBRecoveryMode};
use merge_operator::{self, MergeOperatorCallback, full_merge_callback,
                     partial_merge_callback};
use comparator::{self, ComparatorCallback, compare_callback};
use merge_operator::MergeFn;

pub struct BlockBasedOptions {
    inner: rocksdb_ffi::DBBlockBasedTableOptions,
}

pub struct Options {
    pub inner: rocksdb_ffi::DBOptions,
}

pub struct WriteOptions {
    pub inner: rocksdb_ffi::DBWriteOptions,
}

impl Drop for Options {
    fn drop(&mut self) {
        unsafe {
            rocksdb_ffi::rocksdb_options_destroy(self.inner);
        }
    }
}

impl Drop for BlockBasedOptions {
    fn drop(&mut self) {
        unsafe {
            rocksdb_ffi::rocksdb_block_based_options_destroy(self.inner);
        }
    }
}

impl Drop for WriteOptions {
    fn drop(&mut self) {
        unsafe {
            rocksdb_ffi::rocksdb_writeoptions_destroy(self.inner);
        }
    }
}

impl Default for BlockBasedOptions {
    fn default() -> BlockBasedOptions {
        let block_opts =
            unsafe { rocksdb_ffi::rocksdb_block_based_options_create() };
        let rocksdb_ffi::DBBlockBasedTableOptions(opt_ptr) = block_opts;
        if opt_ptr.is_null() {
            panic!("Could not create rocksdb block based options".to_string());
        }
        BlockBasedOptions { inner: block_opts }
    }
}

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

    pub fn set_block_size(&mut self, size: usize) {
        unsafe {
            rocksdb_ffi::rocksdb_block_based_options_set_block_size(self.inner,
                                                                    size);
        }
    }

    pub fn set_lru_cache(&mut self, size: size_t) {
        let cache = rocksdb_ffi::new_cache(size);
        unsafe {
            // because cache is wrapped in shared_ptr, so we don't need to call
            // rocksdb_cache_destroy explicitly.
            rocksdb_ffi::rocksdb_block_based_options_set_block_cache(self.inner, cache);
        }
    }

    pub fn set_bloom_filter(&mut self,
                            bits_per_key: c_int,
                            block_based: bool) {
        unsafe {
            let bloom = if block_based {
                rocksdb_ffi::rocksdb_filterpolicy_create_bloom(bits_per_key)
            } else {
                rocksdb_ffi::rocksdb_filterpolicy_create_bloom_full(bits_per_key)
            };

            rocksdb_ffi::rocksdb_block_based_options_set_filter_policy(self.inner,
                                                                       bloom);
        }
    }

    pub fn set_cache_index_and_filter_blocks(&mut self, v: bool) {
        unsafe {
            rocksdb_ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks(self.inner,
                                                                                v as u8);
        }
    }
}

// TODO figure out how to create these in a Rusty way
// /pub fn set_filter(&mut self, filter: rocksdb_ffi::DBFilterPolicy) {
// /    unsafe {
// /        rocksdb_ffi::rocksdb_block_based_options_set_filter_policy(
// /            self.inner, filter);
// /    }
// /}

// /pub fn set_cache(&mut self, cache: rocksdb_ffi::DBCache) {
// /    unsafe {
// /        rocksdb_ffi::rocksdb_block_based_options_set_block_cache(
// /            self.inner, cache);
// /    }
// /}

// /pub fn set_cache_compressed(&mut self, cache: rocksdb_ffi::DBCache) {
// /    unsafe {
// /        rocksdb_ffi::
// rocksdb_block_based_options_set_block_cache_compressed(
// /            self.inner, cache);
// /    }
// /}

impl Default for Options {
    fn default() -> Options {
        unsafe {
            let opts = rocksdb_ffi::rocksdb_options_create();
            let rocksdb_ffi::DBOptions(opt_ptr) = opts;
            if opt_ptr.is_null() {
                panic!("Could not create rocksdb options".to_string());
            }
            Options { inner: opts }
        }
    }
}

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

    pub fn increase_parallelism(&mut self, parallelism: i32) {
        unsafe {
            rocksdb_ffi::rocksdb_options_increase_parallelism(self.inner,
                                                              parallelism);
        }
    }

    pub fn optimize_level_style_compaction(&mut self,
                                           memtable_memory_budget: i32) {
        unsafe {
            rocksdb_ffi::rocksdb_options_optimize_level_style_compaction(
                self.inner, memtable_memory_budget);
        }
    }

    pub fn create_if_missing(&mut self, create_if_missing: bool) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_create_if_missing(
                self.inner, create_if_missing);
        }
    }

    pub fn compression(&mut self, t: DBCompressionType) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_compression(self.inner, t);
        }
    }

    pub fn compression_per_level(&mut self,
                                 level_types: &[DBCompressionType]) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_compression_per_level(self.inner,
                                                                level_types.as_ptr(),
                                                                level_types.len() as size_t)
        }
    }

    pub fn add_merge_operator(&mut self, name: &str, merge_fn: MergeFn) {
        let cb = Box::new(MergeOperatorCallback {
            name: CString::new(name.as_bytes()).unwrap(),
            merge_fn: merge_fn,
        });

        unsafe {
            let mo = rocksdb_ffi::rocksdb_mergeoperator_create(
                mem::transmute(cb),
                merge_operator::destructor_callback,
                full_merge_callback,
                partial_merge_callback,
                None,
                merge_operator::name_callback);
            rocksdb_ffi::rocksdb_options_set_merge_operator(self.inner, mo);
        }
    }

    pub fn add_comparator(&mut self,
                          name: &str,
                          compare_fn: fn(&[u8], &[u8]) -> i32) {
        let cb = Box::new(ComparatorCallback {
            name: CString::new(name.as_bytes()).unwrap(),
            f: compare_fn,
        });

        unsafe {
            let cmp = rocksdb_ffi::rocksdb_comparator_create(
                mem::transmute(cb),
                comparator::destructor_callback,
                compare_callback,
                comparator::name_callback);
            rocksdb_ffi::rocksdb_options_set_comparator(self.inner, cmp);
        }
    }

    pub fn set_block_cache_size_mb(&mut self, cache_size: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_optimize_for_point_lookup(self.inner,
                                                                   cache_size);
        }
    }

    pub fn set_max_open_files(&mut self, nfiles: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_open_files(self.inner, nfiles);
        }
    }

    pub fn set_use_fsync(&mut self, useit: bool) {
        unsafe {
            if useit {
                rocksdb_ffi::rocksdb_options_set_use_fsync(self.inner, 1)
            } else {
                rocksdb_ffi::rocksdb_options_set_use_fsync(self.inner, 0)
            }
        }
    }

    pub fn set_bytes_per_sync(&mut self, nbytes: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_bytes_per_sync(self.inner, nbytes);
        }
    }

    pub fn set_disable_data_sync(&mut self, disable: bool) {
        unsafe {
            if disable {
                rocksdb_ffi::rocksdb_options_set_disable_data_sync(self.inner,
                                                                   1);
            } else {
                rocksdb_ffi::rocksdb_options_set_disable_data_sync(self.inner,
                                                                   0);
            }
        }
    }

    pub fn allow_os_buffer(&mut self, is_allow: bool) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_allow_os_buffer(self.inner,
                                                             is_allow);
        }
    }

    pub fn set_table_cache_num_shard_bits(&mut self, nbits: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_table_cache_numshardbits(self.inner,
                                                                      nbits);
        }
    }

    pub fn set_min_write_buffer_number(&mut self, nbuf: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_min_write_buffer_number_to_merge(
                self.inner, nbuf);
        }
    }

    pub fn set_max_write_buffer_number(&mut self, nbuf: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_write_buffer_number(self.inner,
                                                                     nbuf);
        }
    }

    pub fn set_write_buffer_size(&mut self, size: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_write_buffer_size(self.inner,
                                                               size);
        }
    }

    pub fn set_max_bytes_for_level_base(&mut self, size: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_bytes_for_level_base(self.inner, size);
        }
    }

    pub fn set_max_bytes_for_level_multiplier(&mut self, mul: i32) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_bytes_for_level_multiplier(self.inner, mul);
        }
    }

    pub fn set_max_manifest_file_size(&mut self, size: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_manifest_file_size(self.inner, size);
        }
    }

    pub fn set_target_file_size_base(&mut self, size: u64) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_target_file_size_base(self.inner,
                                                                   size);
        }
    }

    pub fn set_min_write_buffer_number_to_merge(&mut self, to_merge: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_min_write_buffer_number_to_merge(
                self.inner, to_merge);
        }
    }

    pub fn set_level_zero_file_num_compaction_trigger(&mut self, n: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_level0_file_num_compaction_trigger(
                self.inner, n);
        }
    }

    pub fn set_level_zero_slowdown_writes_trigger(&mut self, n: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_level0_slowdown_writes_trigger(
                self.inner, n);
        }
    }

    pub fn set_level_zero_stop_writes_trigger(&mut self, n: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_level0_stop_writes_trigger(
                self.inner, n);
        }
    }

    pub fn set_compaction_style(&mut self,
                                style: rocksdb_ffi::DBCompactionStyle) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_compaction_style(self.inner,
                                                              style);
        }
    }

    pub fn set_max_background_compactions(&mut self, n: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_background_compactions(
                self.inner, n);
        }
    }

    pub fn set_max_background_flushes(&mut self, n: c_int) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_max_background_flushes(self.inner,
                                                                    n);
        }
    }

    pub fn set_filter_deletes(&mut self, filter: bool) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_filter_deletes(self.inner, filter);
        }
    }

    pub fn set_disable_auto_compactions(&mut self, disable: bool) {
        unsafe {
            if disable {
                rocksdb_ffi::rocksdb_options_set_disable_auto_compactions(self.inner, 1)
            } else {
                rocksdb_ffi::rocksdb_options_set_disable_auto_compactions(self.inner, 0)
            }
        }
    }

    pub fn set_block_based_table_factory(&mut self,
                                         factory: &BlockBasedOptions) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_block_based_table_factory(self.inner, factory.inner);
        }
    }

    pub fn set_report_bg_io_stats(&mut self, enable: bool) {
        unsafe {
            if enable {
                rocksdb_ffi::rocksdb_options_set_report_bg_io_stats(self.inner,
                                                                    1);
            } else {
                rocksdb_ffi::rocksdb_options_set_report_bg_io_stats(self.inner,
                                                                    0);
            }
        }
    }

    pub fn set_wal_recovery_mode(&mut self, mode: DBRecoveryMode) {
        unsafe {
            rocksdb_ffi::rocksdb_options_set_wal_recovery_mode(self.inner, mode);
        }
    }
}

impl Default for WriteOptions {
    fn default() -> WriteOptions {
        let write_opts = unsafe { rocksdb_ffi::rocksdb_writeoptions_create() };
        let rocksdb_ffi::DBWriteOptions(opt_ptr) = write_opts;
        if opt_ptr.is_null() {
            panic!("Could not create rocksdb write options".to_string());
        }
        WriteOptions { inner: write_opts }
    }
}

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

    pub fn set_sync(&mut self, sync: bool) {
        unsafe {
            rocksdb_ffi::rocksdb_writeoptions_set_sync(self.inner, sync);
        }
    }

    pub fn disable_wal(&mut self, disable: bool) {
        unsafe {
            if disable {
                rocksdb_ffi::rocksdb_writeoptions_disable_WAL(self.inner, 1);
            } else {
                rocksdb_ffi::rocksdb_writeoptions_disable_WAL(self.inner, 0);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Options;

    #[test]
    fn test_set_max_manifest_file_size() {
        let mut opts = Options::new();
        let size = 20 * 1024 * 1024;
        opts.set_max_manifest_file_size(size)
    }
}
<|endoftext|>


<commit_before>use crate::futures;
use crate::result::TockResult;
use crate::syscalls;
use core::cell::Cell;
use core::executor;
use core::fmt;
use core::mem;

const DRIVER_NUM: usize = 0x60004;

#[non_exhaustive]
pub struct NinedofDriver;

#[derive(Copy, Clone, Default, Debug)]
pub struct NinedofReading {
    pub x: i32,
    pub y: i32,
    pub z: i32,
}

impl fmt::Display for NinedofReading {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {}, {})", self.x, self.y, self.z)
    }
}

#[derive(Default)]
struct CbData {
    res: Cell<NinedofReading>,
    ready: Cell<bool>,
}

impl NinedofDriver {
    pub fn read_acceleration(&mut self) -> TockResult<NinedofReading> {
        let res: CbData = Default::default();
        subscribe(Self::cb, unsafe { mem::transmute(&res) })?;
        start_accel_reading()?;
        unsafe { executor::block_on(futures::wait_until(|| res.ready.get())) };
        Ok(res.res.get())
    }

    pub fn read_magnetometer(&mut self) -> TockResult<NinedofReading> {
        let res: CbData = Default::default();
        subscribe(Self::cb, unsafe { mem::transmute(&res) })?;
        start_magnetometer_reading()?;
        unsafe { executor::block_on(futures::wait_until(|| res.ready.get())) };
        Ok(res.res.get())
    }

    extern "C" fn cb(x: usize, y: usize, z: usize, ptr: usize) {
        let res: &CbData = unsafe { mem::transmute(ptr) };
        res.res.set(NinedofReading {
            x: x as i32,
            y: y as i32,
            z: z as i32,
        });
        res.ready.set(true);
    }
}

impl Default for NinedofDriver {
    fn default() -> Self {
        NinedofDriver
    }
}

pub fn subscribe(cb: extern "C" fn(usize, usize, usize, usize), ud: usize) -> TockResult<()> {
    syscalls::subscribe_fn(DRIVER_NUM, 0, cb, ud)?;
    Ok(())
}

pub fn start_accel_reading() -> TockResult<()> {
    syscalls::command(DRIVER_NUM, 1, 0, 0)?;
    Ok(())
}

pub fn start_magnetometer_reading() -> TockResult<()> {
    syscalls::command(DRIVER_NUM, 100, 0, 0)?;
    Ok(())
}
<commit_msg>Remove unnecessary default implementation for driver<commit_after>use crate::futures;
use crate::result::TockResult;
use crate::syscalls;
use core::cell::Cell;
use core::executor;
use core::fmt;
use core::mem;

const DRIVER_NUM: usize = 0x60004;

#[non_exhaustive]
pub struct NinedofDriver;

#[derive(Copy, Clone, Default, Debug)]
pub struct NinedofReading {
    pub x: i32,
    pub y: i32,
    pub z: i32,
}

impl fmt::Display for NinedofReading {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {}, {})", self.x, self.y, self.z)
    }
}

#[derive(Default)]
struct CbData {
    res: Cell<NinedofReading>,
    ready: Cell<bool>,
}

impl NinedofDriver {
    pub fn read_acceleration(&mut self) -> TockResult<NinedofReading> {
        let res: CbData = Default::default();
        subscribe(Self::cb, unsafe { mem::transmute(&res) })?;
        start_accel_reading()?;
        unsafe { executor::block_on(futures::wait_until(|| res.ready.get())) };
        Ok(res.res.get())
    }

    pub fn read_magnetometer(&mut self) -> TockResult<NinedofReading> {
        let res: CbData = Default::default();
        subscribe(Self::cb, unsafe { mem::transmute(&res) })?;
        start_magnetometer_reading()?;
        unsafe { executor::block_on(futures::wait_until(|| res.ready.get())) };
        Ok(res.res.get())
    }

    extern "C" fn cb(x: usize, y: usize, z: usize, ptr: usize) {
        let res: &CbData = unsafe { mem::transmute(ptr) };
        res.res.set(NinedofReading {
            x: x as i32,
            y: y as i32,
            z: z as i32,
        });
        res.ready.set(true);
    }
}

pub fn subscribe(cb: extern "C" fn(usize, usize, usize, usize), ud: usize) -> TockResult<()> {
    syscalls::subscribe_fn(DRIVER_NUM, 0, cb, ud)?;
    Ok(())
}

pub fn start_accel_reading() -> TockResult<()> {
    syscalls::command(DRIVER_NUM, 1, 0, 0)?;
    Ok(())
}

pub fn start_magnetometer_reading() -> TockResult<()> {
    syscalls::command(DRIVER_NUM, 100, 0, 0)?;
    Ok(())
}
<|endoftext|>


<commit_before>use server::buf_read::CustomBufReader;

use std::cmp;
use std::borrow::Borrow;

use std::io;
use std::io::prelude::*;

use std::ptr;

/// A struct implementing `Read` and `BufRead` that will yield bytes until it sees a given sequence.
#[derive(Debug)]
pub struct BoundaryReader<R> {
    buffer: CustomBufReader<R>,
    boundary: Vec<u8>,
    search_idx: usize,
    boundary_read: bool,
    at_end: bool,
}

impl<R> BoundaryReader<R> where R: Read {
    #[doc(hidden)]
    pub fn from_reader<B: Into<Vec<u8>>>(reader: R, boundary: B) -> BoundaryReader<R> {
        BoundaryReader {
            buffer: CustomBufReader::new(reader),
            boundary: boundary.into(),
            search_idx: 0,
            boundary_read: false,
            at_end: false,
        }
    }

    fn read_to_boundary(&mut self) -> io::Result<&[u8]> {
        use log::LogLevel;

        let buf = try!(self.buffer.fill_buf_min(self.boundary.len()));

        while !(self.boundary_read || self.at_end) && self.search_idx < buf.len() {
            let lookahead = &buf[self.search_idx..];

            let safe_len = cmp::min(lookahead.len(), self.boundary.len());

            if &lookahead[..safe_len] == &self.boundary[..safe_len] {
                self.boundary_read = safe_len == self.boundary.len();
                break;
            }

            self.search_idx += 1;
        }

        debug!(
            "Buf len: {} Search idx: {} Boundary read: {:?}",
            buf.len(), self.search_idx, self.boundary_read
        );

        if log_enabled!(LogLevel::Info) {
            let _ = ::std::str::from_utf8(buf).map(|buf|
                info!("Buf: {:?}", buf)
            );
        }

        if self.search_idx >= 2 {
            Ok(&buf[..self.search_idx - 2])
        } else {
            Ok(&buf[..self.search_idx])
        }
    }

    #[doc(hidden)]
    pub fn consume_boundary(&mut self) -> io::Result<()> {
        while !self.boundary_read {
            let buf_len = try!(self.read_to_boundary()).len();

            if buf_len == 0 {
                break;
            }

            self.consume(buf_len);
        }

        let consume_amt = {
            let mut buf = try!(self.buffer.fill_buf_min(self.boundary.len() + 4));
            let mut consume_amt = self.boundary.len() + 2;

            if self.search_idx != 0 {
                let (before, new_buf) = buf.split_at(2);
                if before != b"\r\n" {
                    return Err(io::Error::new(
                        io::ErrorKind::Other,
                        format!("Expected {:?}, got {:?}", b"\r\n", &before)
                    ));
                }

                buf = new_buf;
                consume_amt += 2;
            }

            let (boundary, after) = buf.split_at(self.boundary.len());
            if &*self.boundary != boundary {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Expected {:?}, got {:?}", self.boundary, boundary)
                ));
            }

            if &after[..2] != b"\r\n" {
                self.at_end = after == b"--";

                if !self.at_end {
                    return Err(io::Error::new(
                        io::ErrorKind::Other,
                        format!(
                            "Expected {:?} or {:?}, got {:?}",
                                b"\r\n", b"--", after
                        )
                    ));
                }
            }

            consume_amt
        };

        self.buffer.consume(consume_amt);

        self.search_idx = 0;
        self.boundary_read = false;

        Ok(())
    }

    // Keeping this around to support nested boundaries later.
    #[allow(unused)]
    #[doc(hidden)]
    pub fn set_boundary<B: Into<Vec<u8>>>(&mut self, boundary: B) {
        self.boundary = boundary.into();
    }
}

impl<R: Read> Borrow<R> for BoundaryReader<R> {
    fn borrow(&self) -> &R {
        self.buffer.get_ref()
    }
}

impl<R> Read for BoundaryReader<R> where R: Read {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        let consume_len = {
            let buf = try!(self.read_to_boundary());
            let trunc_len = cmp::min(buf.len(), out.len());
            copy_bytes(&buf[..trunc_len], out);
            trunc_len
        };

        self.consume(consume_len);

        Ok(consume_len)
    }
}

impl<R> BufRead for BoundaryReader<R> where R: Read {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.read_to_boundary()
    }

    fn consume(&mut self, amt: usize) {
        let mut search_idx = self.search_idx;

        if search_idx >= 2 {
            search_idx -= 2;
        }

        let true_amt = cmp::min(amt, search_idx);
        self.buffer.consume(true_amt);
        self.search_idx -= true_amt;
    }
}

// copied from `std::slice::bytes` due to unstable
fn copy_bytes(src: &[u8], dst: &mut [u8]) {
    let len_src = src.len();
    assert!(dst.len() >= len_src);
    // `dst` is unaliasable, so we know statically it doesn't overlap with `src`.
    unsafe {
        ptr::copy_nonoverlapping(
            src.as_ptr(),
            dst.as_mut_ptr(),
            len_src
        );
    }
}

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

    use std::cmp;

    use std::io;
    use std::io::prelude::*;

    const BOUNDARY: &'static str = "--boundary";
    const TEST_VAL: &'static str = "--boundary\r
dashed-value-1\r
--boundary\r
dashed-value-2\r
--boundary--";

    #[test]
    fn test_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (no split)");

        let src = &mut TEST_VAL.as_bytes();
        let reader = BoundaryReader::from_reader(src, BOUNDARY);

        test_boundary_reader(reader);
    }

    struct SplitReader<'a> {
        left: &'a [u8],
        right: &'a [u8],
    }

    impl<'a> SplitReader<'a> {
        fn split(data: &'a [u8], at: usize) -> SplitReader<'a> {
            let (left, right) = data.split_at(at);

            SplitReader {
                left: left,
                right: right,
            }
        }
    }

    impl<'a> Read for SplitReader<'a> {
        fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
            fn copy_bytes_partial(src: &mut &[u8], dst: &mut [u8]) -> usize {
                let copy_amt = cmp::min(src.len(), dst.len());
                super::copy_bytes(&src[..copy_amt], dst);
                *src = &src[copy_amt..];
                copy_amt
            }

            let mut copy_amt = copy_bytes_partial(&mut self.left, dst);

            if copy_amt == 0 {
                copy_amt = copy_bytes_partial(&mut self.right, dst)
            };

            Ok(copy_amt)
        }
    }

    #[test]
    fn test_split_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (split)");

        // Substitute for `.step_by()` being unstable.
        for split_at in (0 .. TEST_VAL.len()).filter(|x| x % 2 != 0) {
            debug!("Testing split at: {}", split_at);

            let src = SplitReader::split(TEST_VAL.as_bytes(), split_at);
            let reader = BoundaryReader::from_reader(src, BOUNDARY);
            test_boundary_reader(reader);
        }

    }

    fn test_boundary_reader<R: Read>(mut reader: BoundaryReader<R>) {
        let ref mut buf = String::new();

        debug!("Read 1");
        let _ = reader.read_to_string(buf).unwrap();
        assert!(buf.is_empty(), "Buffer not empty: {:?}", buf);
        buf.clear();

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-1");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 3");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-2");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 4");
        let _ = reader.read_to_string(buf).unwrap();
        assert!(buf.is_empty(), "Buffer not empty: {:?}", buf);
    }
}
<commit_msg>Don't consume a boundary after the end<commit_after>use server::buf_read::CustomBufReader;

use std::cmp;
use std::borrow::Borrow;

use std::io;
use std::io::prelude::*;

use std::ptr;

/// A struct implementing `Read` and `BufRead` that will yield bytes until it sees a given sequence.
#[derive(Debug)]
pub struct BoundaryReader<R> {
    buffer: CustomBufReader<R>,
    boundary: Vec<u8>,
    search_idx: usize,
    boundary_read: bool,
    at_end: bool,
}

impl<R> BoundaryReader<R> where R: Read {
    #[doc(hidden)]
    pub fn from_reader<B: Into<Vec<u8>>>(reader: R, boundary: B) -> BoundaryReader<R> {
        BoundaryReader {
            buffer: CustomBufReader::new(reader),
            boundary: boundary.into(),
            search_idx: 0,
            boundary_read: false,
            at_end: false,
        }
    }

    fn read_to_boundary(&mut self) -> io::Result<&[u8]> {
        use log::LogLevel;

        let buf = try!(self.buffer.fill_buf_min(self.boundary.len()));

        while !(self.boundary_read || self.at_end) && self.search_idx < buf.len() {
            let lookahead = &buf[self.search_idx..];

            let safe_len = cmp::min(lookahead.len(), self.boundary.len());

            if &lookahead[..safe_len] == &self.boundary[..safe_len] {
                self.boundary_read = safe_len == self.boundary.len();
                break;
            }

            self.search_idx += 1;
        }

        debug!(
            "Buf len: {} Search idx: {} Boundary read: {:?}",
            buf.len(), self.search_idx, self.boundary_read
        );

        if log_enabled!(LogLevel::Info) {
            let _ = ::std::str::from_utf8(buf).map(|buf|
                info!("Buf: {:?}", buf)
            );
        }

        if self.search_idx >= 2 {
            Ok(&buf[..self.search_idx - 2])
        } else {
            Ok(&buf[..self.search_idx])
        }
    }

    #[doc(hidden)]
    pub fn consume_boundary(&mut self) -> io::Result<()> {
        if self.at_end {
            return Ok(());
        }

        while !self.boundary_read {
            let buf_len = try!(self.read_to_boundary()).len();

            if buf_len == 0 {
                break;
            }

            self.consume(buf_len);
        }

        let consume_amt = {
            let mut buf = try!(self.buffer.fill_buf_min(self.boundary.len() + 4));
            let mut consume_amt = self.boundary.len() + 2;

            if self.search_idx != 0 {
                let (before, new_buf) = buf.split_at(2);
                if before != b"\r\n" {
                    return Err(io::Error::new(
                        io::ErrorKind::Other,
                        format!("Expected {:?}, got {:?}", b"\r\n", &before)
                    ));
                }

                buf = new_buf;
                consume_amt += 2;
            }

            let (boundary, after) = buf.split_at(self.boundary.len());
            if &*self.boundary != boundary {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Expected {:?}, got {:?}", self.boundary, boundary)
                ));
            }

            if &after[..2] != b"\r\n" {
                self.at_end = after == b"--";

                if !self.at_end {
                    return Err(io::Error::new(
                        io::ErrorKind::Other,
                        format!(
                            "Expected {:?} or {:?}, got {:?}",
                                b"\r\n", b"--", after
                        )
                    ));
                }
            }

            consume_amt
        };

        self.buffer.consume(consume_amt);

        self.search_idx = 0;
        self.boundary_read = false;

        Ok(())
    }

    // Keeping this around to support nested boundaries later.
    #[allow(unused)]
    #[doc(hidden)]
    pub fn set_boundary<B: Into<Vec<u8>>>(&mut self, boundary: B) {
        self.boundary = boundary.into();
    }
}

impl<R: Read> Borrow<R> for BoundaryReader<R> {
    fn borrow(&self) -> &R {
        self.buffer.get_ref()
    }
}

impl<R> Read for BoundaryReader<R> where R: Read {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        let consume_len = {
            let buf = try!(self.read_to_boundary());
            let trunc_len = cmp::min(buf.len(), out.len());
            copy_bytes(&buf[..trunc_len], out);
            trunc_len
        };

        self.consume(consume_len);

        Ok(consume_len)
    }
}

impl<R> BufRead for BoundaryReader<R> where R: Read {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.read_to_boundary()
    }

    fn consume(&mut self, amt: usize) {
        let mut search_idx = self.search_idx;

        if search_idx >= 2 {
            search_idx -= 2;
        }

        let true_amt = cmp::min(amt, search_idx);
        self.buffer.consume(true_amt);
        self.search_idx -= true_amt;
    }
}

// copied from `std::slice::bytes` due to unstable
fn copy_bytes(src: &[u8], dst: &mut [u8]) {
    let len_src = src.len();
    assert!(dst.len() >= len_src);
    // `dst` is unaliasable, so we know statically it doesn't overlap with `src`.
    unsafe {
        ptr::copy_nonoverlapping(
            src.as_ptr(),
            dst.as_mut_ptr(),
            len_src
        );
    }
}

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

    use std::cmp;

    use std::io;
    use std::io::prelude::*;

    const BOUNDARY: &'static str = "--boundary";
    const TEST_VAL: &'static str = "--boundary\r
dashed-value-1\r
--boundary\r
dashed-value-2\r
--boundary--";

    #[test]
    fn test_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (no split)");

        let src = &mut TEST_VAL.as_bytes();
        let reader = BoundaryReader::from_reader(src, BOUNDARY);

        test_boundary_reader(reader);
    }

    struct SplitReader<'a> {
        left: &'a [u8],
        right: &'a [u8],
    }

    impl<'a> SplitReader<'a> {
        fn split(data: &'a [u8], at: usize) -> SplitReader<'a> {
            let (left, right) = data.split_at(at);

            SplitReader {
                left: left,
                right: right,
            }
        }
    }

    impl<'a> Read for SplitReader<'a> {
        fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
            fn copy_bytes_partial(src: &mut &[u8], dst: &mut [u8]) -> usize {
                let copy_amt = cmp::min(src.len(), dst.len());
                super::copy_bytes(&src[..copy_amt], dst);
                *src = &src[copy_amt..];
                copy_amt
            }

            let mut copy_amt = copy_bytes_partial(&mut self.left, dst);

            if copy_amt == 0 {
                copy_amt = copy_bytes_partial(&mut self.right, dst)
            };

            Ok(copy_amt)
        }
    }

    #[test]
    fn test_split_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (split)");

        // Substitute for `.step_by()` being unstable.
        for split_at in (0 .. TEST_VAL.len()).filter(|x| x % 2 != 0) {
            debug!("Testing split at: {}", split_at);

            let src = SplitReader::split(TEST_VAL.as_bytes(), split_at);
            let reader = BoundaryReader::from_reader(src, BOUNDARY);
            test_boundary_reader(reader);
        }

    }

    fn test_boundary_reader<R: Read>(mut reader: BoundaryReader<R>) {
        let ref mut buf = String::new();

        debug!("Read 1");
        let _ = reader.read_to_string(buf).unwrap();
        assert!(buf.is_empty(), "Buffer not empty: {:?}", buf);
        buf.clear();

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-1");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 3");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-2");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 4");
        let _ = reader.read_to_string(buf).unwrap();
        assert!(buf.is_empty(), "Buffer not empty: {:?}", buf);

        debug!("Extra Consume");
        reader.consume_boundary().unwrap();
    }
}
<|endoftext|>


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

use std::error;
use std::ffi;
use std::fmt;
use std::io;
use std::path::{self, PathBuf};
use std::result;

use api_client;
use depot_client;
use common;
use hcore;
use handlebars;
use toml;

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
#[allow(dead_code)]
pub enum Error {
    APIClient(api_client::Error),
    ArgumentError(&'static str),
    ButterflyError(String),
    CannotRemoveFromChannel((String, String)),
    CommandNotFoundInPkg((String, String)),
    CryptoCLI(String),
    DepotClient(depot_client::Error),
    DockerDaemonDown,
    DockerFileSharingNotEnabled,
    DockerImageNotFound(String),
    DockerNetworkDown(String),
    ExecCommandNotFound(PathBuf),
    FFINulError(ffi::NulError),
    FileNotFound(String),
    HabitatCommon(common::Error),
    HabitatCore(hcore::Error),
    HandlebarsRenderError(handlebars::TemplateRenderError),
    IO(io::Error),
    PackageArchiveMalformed(String),
    PathPrefixError(path::StripPrefixError),
    ProvidesError(String),
    RootRequired,
    SubcommandNotSupported(String),
    UnsupportedExportFormat(String),
    TomlDeserializeError(toml::de::Error),
    TomlSerializeError(toml::ser::Error),
    Utf8Error(String),
    InvalidOrigin,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let msg = match *self {
            Error::APIClient(ref err) => format!("{}", err),
            Error::ArgumentError(ref e) => format!("{}", e),
            Error::ButterflyError(ref e) => format!("{}", e),
            Error::CannotRemoveFromChannel((ref p, ref c)) => {
                format!("{} cannot be removed from the {} channel.", p, c)
            }
            Error::CommandNotFoundInPkg((ref p, ref c)) => {
                format!(
                    "`{}' was not found under any 'PATH' directories in the {} package",
                    c,
                    p
                )
            }
            Error::CryptoCLI(ref e) => format!("{}", e),
            Error::DepotClient(ref err) => format!("{}", err),
            Error::DockerDaemonDown => {
                format!("Can not connect to Docker. Is the Docker daemon running?")
            }
            #[cfg(not(windows))]
            Error::DockerFileSharingNotEnabled => {
                format!(
                    "File Sharing must be enabled in order to enter a studio.\nPlease enable \
                         it in the Docker preferences and share (at a minimum) your home \
                         directory."
                )
            }
            #[cfg(windows)]
            Error::DockerFileSharingNotEnabled => {
                format!(
                    "File Sharing must be enabled in order to enter a studio.\nPlease select \
                         a drive to share in the Docker preferences."
                )
            }
            Error::DockerImageNotFound(ref e) => {
                format!(
                    "The Docker image {} was not found in the docker registry.\nYou can \
                         specify your own Docker image using the HAB_DOCKER_STUDIO_IMAGE \
                         environment variable.",
                    e
                )
            }
            Error::DockerNetworkDown(ref e) => {
                format!(
                    "The Docker image {} is unreachable due to a network error.\nThe \
                         image must be reachable to ensure the versions of hab inside and \
                         outside the studio match.\nYou can specify your own Docker image using \
                         the HAB_DOCKER_STUDIO_IMAGE environment variable.",
                    e
                )
            }
            Error::ExecCommandNotFound(ref c) => {
                format!(
                    "`{}' was not found on the filesystem or in PATH",
                    c.display()
                )
            }
            Error::FFINulError(ref e) => format!("{}", e),
            Error::FileNotFound(ref e) => format!("File not found at: {}", e),
            Error::HabitatCommon(ref e) => format!("{}", e),
            Error::HabitatCore(ref e) => format!("{}", e),
            Error::HandlebarsRenderError(ref e) => format!("{}", e),
            Error::IO(ref err) => format!("{}", err),
            Error::PackageArchiveMalformed(ref e) => {
                format!(
                    "Package archive was unreadable or contained unexpected contents: {:?}",
                    e
                )
            }
            Error::PathPrefixError(ref err) => format!("{}", err),
            Error::ProvidesError(ref err) => format!("Can't find {}", err),
            Error::RootRequired => {
                "Root or administrator permissions required to complete operation".to_string()
            }
            Error::SubcommandNotSupported(ref e) => {
                format!("Subcommand `{}' not supported on this operating system", e)
            }
            Error::UnsupportedExportFormat(ref e) => format!("Unsupported export format: {}", e),
            Error::TomlDeserializeError(ref e) => format!("Can't deserialize TOML: {}", e),
            Error::TomlSerializeError(ref e) => format!("Can't serialize TOML: {}", e),
            Error::Utf8Error(ref e) => format!("Error processing a string as UTF-8: {}", e),
            Error::InvalidOrigin => {
                "Origins must contain no spaces, and begin with a lowercase letter or number.
Allowed characters include a – z, 0 – 9, _, and -. No more than 255 characters.".to_string()
            },
        };
        write!(f, "{}", msg)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::APIClient(ref err) => err.description(),
            Error::ArgumentError(_) => "There was an error parsing an error or with it's value",
            Error::ButterflyError(_) => "Butterfly has had an error",
            Error::CannotRemoveFromChannel(_) => {
                "Package cannot be removed from the specified channel"
            }
            Error::CommandNotFoundInPkg(_) => {
                "Command was not found under any 'PATH' directories in the package"
            }
            Error::CryptoCLI(_) => "A cryptographic error has occurred",
            Error::DepotClient(ref err) => err.description(),
            Error::DockerDaemonDown => "The Docker daemon could not be found.",
            Error::DockerFileSharingNotEnabled => "Docker file sharing is not enabled.",
            Error::DockerImageNotFound(_) => "The Docker image was not found.",
            Error::DockerNetworkDown(_) => "The Docker registry is unreachable.",
            Error::ExecCommandNotFound(_) => "Exec command was not found on filesystem or in PATH",
            Error::FFINulError(ref err) => err.description(),
            Error::FileNotFound(_) => "File not found",
            Error::HabitatCommon(ref err) => err.description(),
            Error::HabitatCore(ref err) => err.description(),
            Error::HandlebarsRenderError(ref err) => err.description(),
            Error::IO(ref err) => err.description(),
            Error::PackageArchiveMalformed(_) => {
                "Package archive was unreadable or had unexpected contents"
            }
            Error::PathPrefixError(ref err) => err.description(),
            Error::ProvidesError(_) => {
                "Can't find a package that provides the given search parameter"
            }
            Error::RootRequired => {
                "Root or administrator permissions required to complete operation"
            }
            Error::SubcommandNotSupported(_) => "Subcommand not supported on this operating system",
            Error::UnsupportedExportFormat(_) => "Unsupported export format",
            Error::TomlDeserializeError(_) => "Can't deserialize TOML",
            Error::TomlSerializeError(_) => "Can't serialize TOML",
            Error::Utf8Error(_) => "Error processing string as UTF-8",
            Error::InvalidOrigin => {
                "Origins must contain no spaces, and begin with a lowercase letter or number.
Allowed characters include a – z, 0 – 9, _, and -. No more than 255 characters."
            },

        }
    }
}

impl From<common::Error> for Error {
    fn from(err: common::Error) -> Error {
        Error::HabitatCommon(err)
    }
}

impl From<depot_client::Error> for Error {
    fn from(err: depot_client::Error) -> Error {
        Error::DepotClient(err)
    }
}

impl From<ffi::NulError> for Error {
    fn from(err: ffi::NulError) -> Error {
        Error::FFINulError(err)
    }
}

impl From<hcore::Error> for Error {
    fn from(err: hcore::Error) -> Error {
        Error::HabitatCore(err)
    }
}

impl From<handlebars::TemplateRenderError> for Error {
    fn from(err: handlebars::TemplateRenderError) -> Error {
        Error::HandlebarsRenderError(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl From<path::StripPrefixError> for Error {
    fn from(err: path::StripPrefixError) -> Error {
        Error::PathPrefixError(err)
    }
}

impl From<toml::de::Error> for Error {
    fn from(err: toml::de::Error) -> Self {
        Error::TomlDeserializeError(err)
    }
}
impl From<toml::ser::Error> for Error {
    fn from(err: toml::ser::Error) -> Self {
        Error::TomlSerializeError(err)
    }
}
<commit_msg>Fix linting errors<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error;
use std::ffi;
use std::fmt;
use std::io;
use std::path::{self, PathBuf};
use std::result;

use api_client;
use depot_client;
use common;
use hcore;
use handlebars;
use toml;

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
#[allow(dead_code)]
pub enum Error {
    APIClient(api_client::Error),
    ArgumentError(&'static str),
    ButterflyError(String),
    CannotRemoveFromChannel((String, String)),
    CommandNotFoundInPkg((String, String)),
    CryptoCLI(String),
    DepotClient(depot_client::Error),
    DockerDaemonDown,
    DockerFileSharingNotEnabled,
    DockerImageNotFound(String),
    DockerNetworkDown(String),
    ExecCommandNotFound(PathBuf),
    FFINulError(ffi::NulError),
    FileNotFound(String),
    HabitatCommon(common::Error),
    HabitatCore(hcore::Error),
    HandlebarsRenderError(handlebars::TemplateRenderError),
    IO(io::Error),
    PackageArchiveMalformed(String),
    PathPrefixError(path::StripPrefixError),
    ProvidesError(String),
    RootRequired,
    SubcommandNotSupported(String),
    UnsupportedExportFormat(String),
    TomlDeserializeError(toml::de::Error),
    TomlSerializeError(toml::ser::Error),
    Utf8Error(String),
    InvalidOrigin,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let msg = match *self {
            Error::APIClient(ref err) => format!("{}", err),
            Error::ArgumentError(ref e) => format!("{}", e),
            Error::ButterflyError(ref e) => format!("{}", e),
            Error::CannotRemoveFromChannel((ref p, ref c)) => {
                format!("{} cannot be removed from the {} channel.", p, c)
            }
            Error::CommandNotFoundInPkg((ref p, ref c)) => {
                format!(
                    "`{}' was not found under any 'PATH' directories in the {} package",
                    c,
                    p
                )
            }
            Error::CryptoCLI(ref e) => format!("{}", e),
            Error::DepotClient(ref err) => format!("{}", err),
            Error::DockerDaemonDown => {
                format!("Can not connect to Docker. Is the Docker daemon running?")
            }
            #[cfg(not(windows))]
            Error::DockerFileSharingNotEnabled => {
                format!(
                    "File Sharing must be enabled in order to enter a studio.\nPlease enable \
                         it in the Docker preferences and share (at a minimum) your home \
                         directory."
                )
            }
            #[cfg(windows)]
            Error::DockerFileSharingNotEnabled => {
                format!(
                    "File Sharing must be enabled in order to enter a studio.\nPlease select \
                         a drive to share in the Docker preferences."
                )
            }
            Error::DockerImageNotFound(ref e) => {
                format!(
                    "The Docker image {} was not found in the docker registry.\nYou can \
                         specify your own Docker image using the HAB_DOCKER_STUDIO_IMAGE \
                         environment variable.",
                    e
                )
            }
            Error::DockerNetworkDown(ref e) => {
                format!(
                    "The Docker image {} is unreachable due to a network error.\nThe \
                         image must be reachable to ensure the versions of hab inside and \
                         outside the studio match.\nYou can specify your own Docker image using \
                         the HAB_DOCKER_STUDIO_IMAGE environment variable.",
                    e
                )
            }
            Error::ExecCommandNotFound(ref c) => {
                format!(
                    "`{}' was not found on the filesystem or in PATH",
                    c.display()
                )
            }
            Error::FFINulError(ref e) => format!("{}", e),
            Error::FileNotFound(ref e) => format!("File not found at: {}", e),
            Error::HabitatCommon(ref e) => format!("{}", e),
            Error::HabitatCore(ref e) => format!("{}", e),
            Error::HandlebarsRenderError(ref e) => format!("{}", e),
            Error::IO(ref err) => format!("{}", err),
            Error::PackageArchiveMalformed(ref e) => {
                format!(
                    "Package archive was unreadable or contained unexpected contents: {:?}",
                    e
                )
            }
            Error::PathPrefixError(ref err) => format!("{}", err),
            Error::ProvidesError(ref err) => format!("Can't find {}", err),
            Error::RootRequired => {
                "Root or administrator permissions required to complete operation".to_string()
            }
            Error::SubcommandNotSupported(ref e) => {
                format!("Subcommand `{}' not supported on this operating system", e)
            }
            Error::UnsupportedExportFormat(ref e) => format!("Unsupported export format: {}", e),
            Error::TomlDeserializeError(ref e) => format!("Can't deserialize TOML: {}", e),
            Error::TomlSerializeError(ref e) => format!("Can't serialize TOML: {}", e),
            Error::Utf8Error(ref e) => format!("Error processing a string as UTF-8: {}", e),
            Error::InvalidOrigin => {
                "Origins must contain no spaces, and begin with a lowercase letter or number.
Allowed characters include a – z, 0 – 9, _, and -. No more than 255 characters."
                    .to_string()
            }
        };
        write!(f, "{}", msg)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::APIClient(ref err) => err.description(),
            Error::ArgumentError(_) => "There was an error parsing an error or with it's value",
            Error::ButterflyError(_) => "Butterfly has had an error",
            Error::CannotRemoveFromChannel(_) => {
                "Package cannot be removed from the specified channel"
            }
            Error::CommandNotFoundInPkg(_) => {
                "Command was not found under any 'PATH' directories in the package"
            }
            Error::CryptoCLI(_) => "A cryptographic error has occurred",
            Error::DepotClient(ref err) => err.description(),
            Error::DockerDaemonDown => "The Docker daemon could not be found.",
            Error::DockerFileSharingNotEnabled => "Docker file sharing is not enabled.",
            Error::DockerImageNotFound(_) => "The Docker image was not found.",
            Error::DockerNetworkDown(_) => "The Docker registry is unreachable.",
            Error::ExecCommandNotFound(_) => "Exec command was not found on filesystem or in PATH",
            Error::FFINulError(ref err) => err.description(),
            Error::FileNotFound(_) => "File not found",
            Error::HabitatCommon(ref err) => err.description(),
            Error::HabitatCore(ref err) => err.description(),
            Error::HandlebarsRenderError(ref err) => err.description(),
            Error::IO(ref err) => err.description(),
            Error::PackageArchiveMalformed(_) => {
                "Package archive was unreadable or had unexpected contents"
            }
            Error::PathPrefixError(ref err) => err.description(),
            Error::ProvidesError(_) => {
                "Can't find a package that provides the given search parameter"
            }
            Error::RootRequired => {
                "Root or administrator permissions required to complete operation"
            }
            Error::SubcommandNotSupported(_) => "Subcommand not supported on this operating system",
            Error::UnsupportedExportFormat(_) => "Unsupported export format",
            Error::TomlDeserializeError(_) => "Can't deserialize TOML",
            Error::TomlSerializeError(_) => "Can't serialize TOML",
            Error::Utf8Error(_) => "Error processing string as UTF-8",
            Error::InvalidOrigin => {
                "Origins must contain no spaces, and begin with a lowercase letter or number.
Allowed characters include a – z, 0 – 9, _, and -. No more than 255 characters."
            }

        }
    }
}

impl From<common::Error> for Error {
    fn from(err: common::Error) -> Error {
        Error::HabitatCommon(err)
    }
}

impl From<depot_client::Error> for Error {
    fn from(err: depot_client::Error) -> Error {
        Error::DepotClient(err)
    }
}

impl From<ffi::NulError> for Error {
    fn from(err: ffi::NulError) -> Error {
        Error::FFINulError(err)
    }
}

impl From<hcore::Error> for Error {
    fn from(err: hcore::Error) -> Error {
        Error::HabitatCore(err)
    }
}

impl From<handlebars::TemplateRenderError> for Error {
    fn from(err: handlebars::TemplateRenderError) -> Error {
        Error::HandlebarsRenderError(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl From<path::StripPrefixError> for Error {
    fn from(err: path::StripPrefixError) -> Error {
        Error::PathPrefixError(err)
    }
}

impl From<toml::de::Error> for Error {
    fn from(err: toml::de::Error) -> Self {
        Error::TomlDeserializeError(err)
    }
}
impl From<toml::ser::Error> for Error {
    fn from(err: toml::ser::Error) -> Self {
        Error::TomlSerializeError(err)
    }
}
<|endoftext|>


<commit_before>use syntax::{ast, codemap, visit};
use syntax::attr::AttrMetaMethods;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::ty::expr_ty;
use rustc::middle::{ty, def};
use rustc::middle::typeck::astconv::AstConv;
use rustc::util::ppaux::Repr;

declare_lint!(TRANSMUTE_TYPE_LINT, Allow,
              "Warn and report types being transmuted")
declare_lint!(UNROOTED_MUST_ROOT, Deny,
              "Warn and report usage of unrooted jsmanaged objects")

pub struct TransmutePass;
pub struct UnrootedPass;

impl LintPass for TransmutePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TRANSMUTE_TYPE_LINT)
    }

    fn check_expr(&mut self, cx: &Context, ex: &ast::Expr) {
        match ex.node {
            ast::ExprCall(ref expr, ref args) => {
                match expr.node {
                    ast::ExprPath(ref path) => {
                        if path.segments.last()
                                        .map_or(false, |ref segment| segment.identifier.name.as_str() == "transmute")
                           && args.len() == 1 {
                            let tcx = cx.tcx();
                            cx.span_lint(TRANSMUTE_TYPE_LINT, ex.span,
                                         format!("Transmute from {} to {} detected",
                                                 expr_ty(tcx, ex).repr(tcx),
                                                 expr_ty(tcx, &**args.get(0)).repr(tcx)
                                        ).as_slice());
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

fn lint_unrooted_ty(cx: &Context, ty: &ast::Ty, warning: &str) {
    match ty.node {
        ast::TyBox(ref t) | ast::TyUniq(ref t) |
        ast::TyVec(ref t) | ast::TyFixedLengthVec(ref t, _) |
        ast::TyPtr(ast::MutTy { ty: ref t, ..}) | ast::TyRptr(_, ast::MutTy { ty: ref t, ..}) => lint_unrooted_ty(cx, &**t, warning),
        ast::TyPath(_, _, id) => {
                match cx.tcx.def_map.borrow().get_copy(&id) {
                    def::DefTy(def_id) => {
                        if ty::has_attr(cx.tcx, def_id, "must_root") {
                            cx.span_lint(UNROOTED_MUST_ROOT, ty.span, warning);
                        }
                    }
                    _ => (),
                }
            }
            _ => (),
    };
}

impl LintPass for UnrootedPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }

    fn check_struct_def(&mut self, cx: &Context, def: &ast::StructDef, _i: ast::Ident, _gen: &ast::Generics, id: ast::NodeId) {
        if cx.tcx.map.expect_item(id).attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields.iter() {
                lint_unrooted_ty(cx, &*field.node.ty,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate");
            }
        }
    }

    fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) {
        let ref map = cx.tcx.map;
        if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) {
            match var.node.kind {
                ast::TupleVariantKind(ref vec) => {
                    for ty in vec.iter() {
                        lint_unrooted_ty(cx, &*ty.ty,
                                         "Type must be rooted, use #[must_root] on the enum definition to propagate")
                    }
                }
                _ => () // Struct variants already caught by check_struct_def
            }
        }
    }

    fn check_fn(&mut self, cx: &Context, kind: visit::FnKind, decl: &ast::FnDecl,
                block: &ast::Block, _span: codemap::Span, _id: ast::NodeId) {
        match kind {
            visit::FkItemFn(i, _, _, _) |
            visit::FkMethod(i, _, _) if i.as_str() == "new" || i.as_str() == "new_inherited" => {
                return;
            }
            _ => ()
        }
        match block.rules {
            ast::DefaultBlock => {
                for arg in decl.inputs.iter() {
                    lint_unrooted_ty(cx, &*arg.ty,
                                     "Type must be rooted, use #[must_root] on the fn definition to propagate")
                }
            }
            _ => () // fn is `unsafe`
        }
    }

    // Partially copied from rustc::middle::lint::builtin
    // Catches `let` statements which store a #[must_root] value
    // Expressions which return out of blocks eventually end up in a `let`
    // statement or a function return (which will be caught when it is used elsewhere)
    fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
        // Catch the let binding
        let expr = match s.node {
            ast::StmtDecl(ref decl, _) => match decl.node {
                ast::DeclLocal(ref loc) => match loc.init {
                        Some(ref e) => &**e,
                        _ => return
                },
                _ => return
            },
            _ => return
        };

        let t = expr_ty(cx.tcx, &*expr);
        match ty::get(t).sty {
            ty::ty_struct(did, _) |
            ty::ty_enum(did, _) => {
                if ty::has_attr(cx.tcx, did, "must_root") {
                    cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
                                 format!("Expression of type {} must be rooted", t.repr(cx.tcx)).as_slice());
                }
            }
            _ => {}
        }
    }
}<commit_msg>Add the MPL back to components/plugins/lints.rs<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/. */

use syntax::{ast, codemap, visit};
use syntax::attr::AttrMetaMethods;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::ty::expr_ty;
use rustc::middle::{ty, def};
use rustc::middle::typeck::astconv::AstConv;
use rustc::util::ppaux::Repr;

declare_lint!(TRANSMUTE_TYPE_LINT, Allow,
              "Warn and report types being transmuted")
declare_lint!(UNROOTED_MUST_ROOT, Deny,
              "Warn and report usage of unrooted jsmanaged objects")

pub struct TransmutePass;
pub struct UnrootedPass;

impl LintPass for TransmutePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TRANSMUTE_TYPE_LINT)
    }

    fn check_expr(&mut self, cx: &Context, ex: &ast::Expr) {
        match ex.node {
            ast::ExprCall(ref expr, ref args) => {
                match expr.node {
                    ast::ExprPath(ref path) => {
                        if path.segments.last()
                                        .map_or(false, |ref segment| segment.identifier.name.as_str() == "transmute")
                           && args.len() == 1 {
                            let tcx = cx.tcx();
                            cx.span_lint(TRANSMUTE_TYPE_LINT, ex.span,
                                         format!("Transmute from {} to {} detected",
                                                 expr_ty(tcx, ex).repr(tcx),
                                                 expr_ty(tcx, &**args.get(0)).repr(tcx)
                                        ).as_slice());
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

fn lint_unrooted_ty(cx: &Context, ty: &ast::Ty, warning: &str) {
    match ty.node {
        ast::TyBox(ref t) | ast::TyUniq(ref t) |
        ast::TyVec(ref t) | ast::TyFixedLengthVec(ref t, _) |
        ast::TyPtr(ast::MutTy { ty: ref t, ..}) | ast::TyRptr(_, ast::MutTy { ty: ref t, ..}) => lint_unrooted_ty(cx, &**t, warning),
        ast::TyPath(_, _, id) => {
                match cx.tcx.def_map.borrow().get_copy(&id) {
                    def::DefTy(def_id) => {
                        if ty::has_attr(cx.tcx, def_id, "must_root") {
                            cx.span_lint(UNROOTED_MUST_ROOT, ty.span, warning);
                        }
                    }
                    _ => (),
                }
            }
            _ => (),
    };
}

impl LintPass for UnrootedPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }

    fn check_struct_def(&mut self, cx: &Context, def: &ast::StructDef, _i: ast::Ident, _gen: &ast::Generics, id: ast::NodeId) {
        if cx.tcx.map.expect_item(id).attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields.iter() {
                lint_unrooted_ty(cx, &*field.node.ty,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate");
            }
        }
    }

    fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) {
        let ref map = cx.tcx.map;
        if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) {
            match var.node.kind {
                ast::TupleVariantKind(ref vec) => {
                    for ty in vec.iter() {
                        lint_unrooted_ty(cx, &*ty.ty,
                                         "Type must be rooted, use #[must_root] on the enum definition to propagate")
                    }
                }
                _ => () // Struct variants already caught by check_struct_def
            }
        }
    }

    fn check_fn(&mut self, cx: &Context, kind: visit::FnKind, decl: &ast::FnDecl,
                block: &ast::Block, _span: codemap::Span, _id: ast::NodeId) {
        match kind {
            visit::FkItemFn(i, _, _, _) |
            visit::FkMethod(i, _, _) if i.as_str() == "new" || i.as_str() == "new_inherited" => {
                return;
            }
            _ => ()
        }
        match block.rules {
            ast::DefaultBlock => {
                for arg in decl.inputs.iter() {
                    lint_unrooted_ty(cx, &*arg.ty,
                                     "Type must be rooted, use #[must_root] on the fn definition to propagate")
                }
            }
            _ => () // fn is `unsafe`
        }
    }

    // Partially copied from rustc::middle::lint::builtin
    // Catches `let` statements which store a #[must_root] value
    // Expressions which return out of blocks eventually end up in a `let`
    // statement or a function return (which will be caught when it is used elsewhere)
    fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
        // Catch the let binding
        let expr = match s.node {
            ast::StmtDecl(ref decl, _) => match decl.node {
                ast::DeclLocal(ref loc) => match loc.init {
                        Some(ref e) => &**e,
                        _ => return
                },
                _ => return
            },
            _ => return
        };

        let t = expr_ty(cx.tcx, &*expr);
        match ty::get(t).sty {
            ty::ty_struct(did, _) |
            ty::ty_enum(did, _) => {
                if ty::has_attr(cx.tcx, did, "must_root") {
                    cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
                                 format!("Expression of type {} must be rooted", t.repr(cx.tcx)).as_slice());
                }
            }
            _ => {}
        }
    }
}<|endoftext|>


<commit_before>type Link<T> = Option<Box<T>>;

struct Node<K, V> {
    key: K,
    value: V,
    left: Link<Node<K, V>>,
    right: Link<Node<K, V>>,
    level: uint
}

struct Tree<K, V> {
    root: Link<Node<K, V>>,
}

impl<K: Ord, V> Node<K, V> {
    fn new(key: K, value: V) -> Node<K, V> {
        Node { key: key, value: value, left: None, right: None, level: 1 }
    }

    fn max(&self) -> &K {
        match self.right {
            None => &self.key,
            Some(ref n) => n.max(),
        }
    }

    fn min(&self) -> &K {
        match self.left {
            None => &self.key,
            Some(ref n) => n.min(),
        }
    }

    fn is_bst(&self) -> bool {
        self.left.as_ref().map_or(true, |n| n.is_bst() && *n.max() < self.key)
        && self.right.as_ref().map_or(true, |n| n.is_bst() && *n.min() > self.key)
    }

    fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        match key.cmp(&self.key) {
            Equal => Some(&self.value),
            Less =>
                match self.left {
                    None => None,
                    Some(ref b) => b.find(key),
                },
            Greater =>
                match self.right {
                    None => None,
                    Some(ref b) => b.find(key),
                },
        }
    }

    /*

       In the below, 'o' represents black, '*' represents red.

       First, note that deleting a red leaf requires no rebalancing at all.

       ---

       There's only 1 possible AA tree of size 2:

       o
        \
         *

       Deleting the root or the leaf requires no rebalancing.

       ---

       For size 3 trees, we only have:

         o
        / \
       o   o

        - deleting left leaf means we have to decrease the level of root. this suffices to rebalance
        - deleting right leaf means we have to decrease level of root but then make left leaf the
          new root (and former root the child of new root)
        - deleting the root means right child is new root, left child becomes new root's right child

       ---

       For size 4 trees, we have either

         o       o
        / \     / \
       o   o   o   o
        \           \
         *           *

       There are 4 classes of deletion:

        - delete red leaf (see above)
        - delete red node's parent: make red a child of its former grandparent
        - delete root: in the first case, red needs to become root, so increase its level and make it
          the new root. in the second case, right child of root needs to become new root.
        - delete other child: in the first case, red needs to become root and the old root needs to
          be right child of new root. in the second case, decrease level of old root, increase level
          of right child and make old root the child of the right child (which is the new root)

       ---

       For size 5 trees, we have one of

         o        o
        / \      / \
       o   o    o   *
        \   \      / \
         *   *    o   o

       ===

       One fundamental operation we need is "promote the max from the left subtree (or min from right subtree!)
       this is used when we delete a root, for example. this seems essentially whenever we delete a node that
       has two children.

     */
}

fn main() {
}
<commit_msg>Copy over skew and split. Implement insert. Change find implementation to match style of insert (to reduce duplication)<commit_after>use std::mem::{replace, swap};

type Link<T> = Option<Box<T>>;

struct Node<K, V> {
    key: K,
    value: V,
    left: Link<Node<K, V>>,
    right: Link<Node<K, V>>,
    level: uint
}

struct Tree<K, V> {
    root: Link<Node<K, V>>,
}

impl<K: Ord, V> Node<K, V> {
    fn new(key: K, value: V) -> Node<K, V> {
        Node { key: key, value: value, left: None, right: None, level: 1 }
    }

    fn max(&self) -> &K {
        match self.right {
            None => &self.key,
            Some(ref n) => n.max(),
        }
    }

    fn min(&self) -> &K {
        match self.left {
            None => &self.key,
            Some(ref n) => n.min(),
        }
    }

    fn is_bst(&self) -> bool {
        self.left.as_ref().map_or(true, |n| n.is_bst() && *n.max() < self.key)
        && self.right.as_ref().map_or(true, |n| n.is_bst() && *n.min() > self.key)
    }

    fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        let ch = match key.cmp(&self.key) {
            Equal => return Some(&self.value),
            Less => & self.left,
            Greater => & self.right,
        };

        match *ch {
            None => None,
            Some(ref b) => b.find(key),
        }
    }

    fn insert(&mut self, key: K, value: V) -> Option<V> {
        let ch = match key.cmp(&self.key) {
            Equal => {
                self.key = key;
                return Some(replace(&mut self.value, value))
            },
            Less => &mut self.left,
            Greater => &mut self.right,
        };

        match *ch {
            None => {
                *ch = Some(box Node::new(key, value));
                None
            },
            Some(ref mut b) => {
                let inserted = b.insert(key, value);
                skew(b);
                split(b);
                inserted
            },
        }

    }

    /*

       In the below, 'o' represents black, '*' represents red.

       First, note that deleting a red leaf requires no rebalancing at all.

       ---

       There's only 1 possible AA tree of size 2:

       o
        \
         *

       Deleting the root or the leaf requires no rebalancing.

       ---

       For size 3 trees, we only have:

         o
        / \
       o   o

        - deleting left leaf means we have to decrease the level of root. this suffices to rebalance
        - deleting right leaf means we have to decrease level of root but then make left leaf the
          new root (and former root the child of new root)
        - deleting the root means right child is new root, left child becomes new root's right child

       ---

       For size 4 trees, we have either

         o       o
        / \     / \
       o   o   o   o
        \           \
         *           *

       There are 4 classes of deletion:

        - delete red leaf (see above)
        - delete red node's parent: make red a child of its former grandparent
        - delete root: in the first case, red needs to become root, so increase its level and make it
          the new root. in the second case, right child of root needs to become new root.
        - delete other child: in the first case, red needs to become root and the old root needs to
          be right child of new root. in the second case, decrease level of old root, increase level
          of right child and make old root the child of the right child (which is the new root)

       ---

       For size 5 trees, we have one of

         o        o
        / \      / \
       o   o    o   *
        \   \      / \
         *   *    o   o

       ===

       One fundamental operation we need is "promote the max from the left subtree (or min from right subtree!)
       this is used when we delete a root, for example. this seems essentially whenever we delete a node that
       has two children.

     */
}

// Remove left horizontal link by rotating right
/*
     a      b
    /        \
   b    =>    a
    \        /
     c      c

  provided that a.level == b.level
*/
fn skew<K: Ord, V>(node: &mut Box<Node<K, V>>) {
    if node.left.is_some() && node.left.get_ref().level == node.level {
        let mut save = node.left.take_unwrap();
        swap(&mut node.left, &mut save.right); // save.right now None
        swap(node, &mut save);
        node.right = Some(save);
    }
}

// Remove dual horizontal link by rotating left and increasing level of
// the parent
/*
    a            b
     \          / \
      b    =>  a   c
     / \        \
    d   c        d

  provided that a.level == c.level
*/
fn split<K: Ord, V>(node: &mut Box<Node<K, V>>) {
    if node.right.as_ref().map_or(false,
      |x| x.right.is_some() && x.right.get_ref().level == node.level) {
        let mut save = node.right.take_unwrap();
        swap(&mut node.right, &mut save.left); // save.left now None
        save.level += 1;
        swap(node, &mut save);
        node.left = Some(save);
    }
}

fn main() {
}
<|endoftext|>