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

use bifrost::{conshash::ConsistentHashing, raft::client::RaftClient, rpc::RPCError};
use dovahkiin::{expr::serde::Expr, types::OwnedValue};
use futures::stream::{FuturesUnordered, StreamExt};
use itertools::Itertools;

use crate::{
    client::{client_by_server_id, client_by_server_name},
    index::{
        ranged::{client::cursor::ClientCursor, lsm::btree::Ordering},
        EntryKey, IndexerClients, SCHEMA_SCAN_PATT_SIZE,
    },
    ram::cell::{OwnedCell, ReadError},
};

const SCAN_BUFFER_SIZE: u16 = 64;

pub struct IndexedDataClient {
    conshash: Arc<ConsistentHashing>,
    index_clients: Arc<IndexerClients>,
}

pub struct DataCursor<'a> {
    index_cursor: Option<ClientCursor>,
    buffer: Vec<OwnedCell>,
    projection: Vec<u64>,
    selection: Expr,
    proc: Expr,
    client: &'a IndexedDataClient,
    pos: usize,
}

impl IndexedDataClient {
    pub fn new(conshash: &Arc<ConsistentHashing>, raft_client: &Arc<RaftClient>) -> Self {
        Self {
            conshash: conshash.clone(),
            index_clients: Arc::new(IndexerClients::new(conshash, raft_client)),
        }
    }
    pub async fn range_index_scan<'a>(
        &self,
        schema: u32,
        field: u64,
        key: u64,
        selection: OwnedValue,
        projection: OwnedValue,
    ) -> DataCursor<'a> {
        unimplemented!()
    }
    pub async fn scan_all<'a>(
        &'a self,
        schema: u32,
        projection: Vec<u64>, // Column array
        selection: Expr,      // Checker expression
        proc: Expr,
        ordering: Ordering,
    ) -> Result<DataCursor<'a>, RPCError> {
        let key = EntryKey::for_schema(schema);
        let index_cursor = self
            .index_clients
            .range_seek(
                &key,
                ordering,
                SCAN_BUFFER_SIZE,
                Some(SCHEMA_SCAN_PATT_SIZE),
            )
            .await?;
        let mut cursor = DataCursor {
            index_cursor,
            projection,
            selection,
            proc,
            client: self,
            buffer: vec![],
            pos: 0,
        };
        cursor.refresh_batch().await;
        Ok(cursor)
    }
}

impl<'a> DataCursor<'a> {
    pub async fn next(&mut self) -> Result<Option<OwnedCell>, RPCError> {
        if self.buffer.len() <= self.pos {
            if self.next_block().await? {
                if !self.refresh_batch().await {
                    return Ok(None);
                }
            } else {
                return Ok(None);
            }
        }
        let cell = mem::take(&mut self.buffer[self.pos]);
        self.pos += 1;
        return Ok(Some(cell));
    }

    pub async fn next_block(&mut self) -> Result<bool, RPCError> {
        if let Some(cursor) = &mut self.index_cursor {
            if cursor.next_block().await? {
                return Ok(true);
            }
        }
        // If cannot get next block, set the index cursor to none
        // We are done with this cursor
        self.index_cursor = None;
        self.buffer = vec![];
        self.pos = 0;
        return Ok(false);
    }

    pub async fn refresh_batch(&mut self) -> bool {
        if let Some(cursor) = &self.index_cursor {
            let all_ids = cursor.current_block();
            let mut tasks = all_ids
                .iter()
                .enumerate()
                .filter_map(|(i, id)| {
                    self.client
                        .conshash
                        .get_server_id_by(id)
                        .map(|sid| (i, sid, id))
                })
                .group_by(|(_i, sid, _id)| *sid)
                .into_iter()
                .map(|(sid, pairs)| {
                    let mut ids = vec![];
                    let mut idx = vec![];
                    for (i, _, id) in pairs {
                        idx.push(i);
                        ids.push(*id);
                    }
                    let projection = self.projection.clone();
                    let selection = self.selection.clone();
                    let proc = self.proc.clone();
                    let server_name = self.client.conshash.to_server_name(sid);
                    async move {
                        match client_by_server_name(sid, server_name).await {
                            Ok(client) => {
                                let read_res = client
                                    .read_all_cells_proced(ids, projection, selection, proc)
                                    .await
                                    .map(|v| v.into_iter().zip(idx).collect_vec());
                                match read_res {
                                    Ok(cells) => Ok(cells
                                        .into_iter()
                                        .filter_map(|(c, i)| c.ok().map(|c| (c, i)))
                                        .collect_vec()),
                                    Err(e) => return Err(e),
                                }
                            }
                            Err(e) => return Err(e),
                        }
                    }
                })
                .collect::<FuturesUnordered<_>>();
            let mut all_cells = vec![];
            while let Some(task_res) = tasks.next().await {
                if let Ok(mut cells) = task_res {
                    all_cells.append(&mut cells);
                }
            }
            all_cells.sort_by(|(_, i1), (_, i2)| i1.cmp(i2));
            self.buffer = all_cells.into_iter().map(|(c, _)| c).collect_vec();
            self.pos = 0;
            true
        } else {
            self.buffer = vec![];
            self.pos = 0;
            false
        }
    }
}

#[cfg(test)]
mod test {
    use crate::{
        client,
        index::ranged::lsm::btree::Ordering,
        query::data_client::IndexedDataClient,
        ram::{
            cell::OwnedCell,
            schema::{Field, Schema},
        },
        server::*,
    };
    use dovahkiin::{expr::serde::Expr, types::*};
    use std::sync::Arc;

    #[tokio::test(flavor = "multi_thread")]
    async fn scan_all() {
        const DATA: &'static str = "DATA";
        let _ = env_logger::try_init();
        let server_addr = String::from("127.0.0.1:6701");
        let server_group = String::from("smoke_test");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 512 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
                index_enabled: false,
                services: vec![Service::Cell, Service::Query],
            },
            &server_addr,
            &server_group,
        )
        .await;
        // Require schema to be scannable to insert special scan key to the range indexer
        let schema_id = 123;
        let schema = Schema::new_with_id(
            schema_id,
            &String::from("schema"),
            None,
            Field::new(
                "*",
                Type::Map,
                false,
                false,
                Some(vec![Field::new(
                    DATA,
                    Type::U64,
                    false,
                    false,
                    None,
                    vec![],
                )]),
                vec![],
            ),
            false,
            true, // Scannable
        );
        let client = server.data_client(&vec![server_addr]).await.unwrap();
        client.new_schema_with_id(schema).await.unwrap().unwrap();
        let num = 10240;
        for i in 0..num {
            let id = Id::new(1, i);
            let mut value = OwnedValue::Map(OwnedMap::new());
            value[DATA] = OwnedValue::U64(i);
            let cell = OwnedCell::new_with_id(schema_id, &id, value);
            client.write_cell(cell).await.unwrap().unwrap();
        }
        let idx_data_client = server.indexed_data_client();
        let cursor = idx_data_client
            .scan_all(
                schema_id,
                vec![],
                Expr::Vec(vec![]),
                Expr::Vec(vec![]),
                Ordering::Forward,
            )
            .await
            .unwrap();
    }
}
<commit_msg>a simple test case<commit_after>use std::{mem, sync::Arc};

use bifrost::{conshash::ConsistentHashing, raft::client::RaftClient, rpc::RPCError};
use dovahkiin::{expr::serde::Expr, types::OwnedValue};
use futures::stream::{FuturesUnordered, StreamExt};
use itertools::Itertools;

use crate::{
    client::{client_by_server_id, client_by_server_name},
    index::{
        ranged::{client::cursor::ClientCursor, lsm::btree::Ordering},
        EntryKey, IndexerClients, SCHEMA_SCAN_PATT_SIZE,
    },
    ram::cell::{OwnedCell, ReadError},
};

const SCAN_BUFFER_SIZE: u16 = 64;

pub struct IndexedDataClient {
    conshash: Arc<ConsistentHashing>,
    index_clients: Arc<IndexerClients>,
}

pub struct DataCursor<'a> {
    index_cursor: Option<ClientCursor>,
    buffer: Vec<OwnedCell>,
    projection: Vec<u64>,
    selection: Expr,
    proc: Expr,
    client: &'a IndexedDataClient,
    pos: usize,
}

impl IndexedDataClient {
    pub fn new(conshash: &Arc<ConsistentHashing>, raft_client: &Arc<RaftClient>) -> Self {
        Self {
            conshash: conshash.clone(),
            index_clients: Arc::new(IndexerClients::new(conshash, raft_client)),
        }
    }
    pub async fn range_index_scan<'a>(
        &self,
        schema: u32,
        field: u64,
        key: u64,
        selection: OwnedValue,
        projection: OwnedValue,
    ) -> DataCursor<'a> {
        unimplemented!()
    }
    pub async fn scan_all<'a>(
        &'a self,
        schema: u32,
        projection: Vec<u64>, // Column array
        selection: Expr,      // Checker expression
        proc: Expr,
        ordering: Ordering,
    ) -> Result<DataCursor<'a>, RPCError> {
        let key = EntryKey::for_schema(schema);
        let index_cursor = self
            .index_clients
            .range_seek(
                &key,
                ordering,
                SCAN_BUFFER_SIZE,
                Some(SCHEMA_SCAN_PATT_SIZE),
            )
            .await?;
        let mut cursor = DataCursor {
            index_cursor,
            projection,
            selection,
            proc,
            client: self,
            buffer: vec![],
            pos: 0,
        };
        cursor.refresh_batch().await;
        Ok(cursor)
    }
}

impl<'a> DataCursor<'a> {
    pub async fn next(&mut self) -> Result<Option<OwnedCell>, RPCError> {
        if self.buffer.len() <= self.pos {
            if self.next_block().await? {
                if !self.refresh_batch().await {
                    return Ok(None);
                }
            } else {
                return Ok(None);
            }
        }
        let cell = mem::take(&mut self.buffer[self.pos]);
        self.pos += 1;
        return Ok(Some(cell));
    }

    pub async fn next_block(&mut self) -> Result<bool, RPCError> {
        if let Some(cursor) = &mut self.index_cursor {
            if cursor.next_block().await? {
                return Ok(true);
            }
        }
        // If cannot get next block, set the index cursor to none
        // We are done with this cursor
        self.index_cursor = None;
        self.buffer = vec![];
        self.pos = 0;
        return Ok(false);
    }

    pub async fn refresh_batch(&mut self) -> bool {
        if let Some(cursor) = &self.index_cursor {
            let all_ids = cursor.current_block();
            let mut tasks = all_ids
                .iter()
                .enumerate()
                .filter_map(|(i, id)| {
                    self.client
                        .conshash
                        .get_server_id_by(id)
                        .map(|sid| (i, sid, id))
                })
                .group_by(|(_i, sid, _id)| *sid)
                .into_iter()
                .map(|(sid, pairs)| {
                    let mut ids = vec![];
                    let mut idx = vec![];
                    for (i, _, id) in pairs {
                        idx.push(i);
                        ids.push(*id);
                    }
                    let projection = self.projection.clone();
                    let selection = self.selection.clone();
                    let proc = self.proc.clone();
                    let server_name = self.client.conshash.to_server_name(sid);
                    async move {
                        match client_by_server_name(sid, server_name).await {
                            Ok(client) => {
                                let read_res = client
                                    .read_all_cells_proced(ids, projection, selection, proc)
                                    .await
                                    .map(|v| v.into_iter().zip(idx).collect_vec());
                                match read_res {
                                    Ok(cells) => Ok(cells
                                        .into_iter()
                                        .filter_map(|(c, i)| c.ok().map(|c| (c, i)))
                                        .collect_vec()),
                                    Err(e) => return Err(e),
                                }
                            }
                            Err(e) => return Err(e),
                        }
                    }
                })
                .collect::<FuturesUnordered<_>>();
            let mut all_cells = vec![];
            while let Some(task_res) = tasks.next().await {
                if let Ok(mut cells) = task_res {
                    all_cells.append(&mut cells);
                }
            }
            all_cells.sort_by(|(_, i1), (_, i2)| i1.cmp(i2));
            self.buffer = all_cells.into_iter().map(|(c, _)| c).collect_vec();
            self.pos = 0;
            true
        } else {
            self.buffer = vec![];
            self.pos = 0;
            false
        }
    }
}

#[cfg(test)]
mod test {
    use crate::{
        client,
        index::ranged::lsm::btree::Ordering,
        query::data_client::IndexedDataClient,
        ram::{
            cell::OwnedCell,
            schema::{Field, Schema},
        },
        server::*,
    };
    use dovahkiin::{expr::serde::Expr, types::*};
    use std::sync::Arc;

    #[tokio::test(flavor = "multi_thread")]
    async fn scan_all() {
        const DATA: &'static str = "DATA";
        let _ = env_logger::try_init();
        let server_addr = String::from("127.0.0.1:6701");
        let server_group = String::from("smoke_test");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 512 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
                index_enabled: false,
                services: vec![Service::Cell, Service::Query],
            },
            &server_addr,
            &server_group,
        )
        .await;
        // Require schema to be scannable to insert special scan key to the range indexer
        let schema_id = 123;
        let schema = Schema::new_with_id(
            schema_id,
            &String::from("schema"),
            None,
            Field::new(
                "*",
                Type::Map,
                false,
                false,
                Some(vec![Field::new(
                    DATA,
                    Type::U64,
                    false,
                    false,
                    None,
                    vec![],
                )]),
                vec![],
            ),
            false,
            true, // Scannable
        );
        let client = server.data_client(&vec![server_addr]).await.unwrap();
        client.new_schema_with_id(schema).await.unwrap().unwrap();
        let num = 10240;
        for i in 0..num {
            let id = Id::new(1, i);
            let mut value = OwnedValue::Map(OwnedMap::new());
            value[DATA] = OwnedValue::U64(i);
            let cell = OwnedCell::new_with_id(schema_id, &id, value);
            client.write_cell(cell).await.unwrap().unwrap();
        }
        let idx_data_client = server.indexed_data_client();
        let mut cursor = idx_data_client
            .scan_all(
                schema_id,
                vec![],
                Expr::nothing(),
                Expr::nothing(),
                Ordering::Forward,
            )
            .await
            .unwrap();
        for i in 0..num {
            let id = Id::new(1, i);
            let cell_res = cursor.next().await.unwrap();
            let cell = cell_res.unwrap();
            assert_eq!(id, cell.id());
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-windows failing on win32 bot
// ignore-freebsd: output doesn't match
// ignore-tidy-linelength
// ignore-lldb
// ignore-android: FIXME(#10381)
// compile-flags:-g

// This test uses some GDB Python API features (e.g. accessing anonymous fields)
// which are only available in newer GDB version. The following directive will
// case the test runner to ignore this test if an older GDB version is used:
// min-gdb-version 7.7

// gdb-command: run

// gdb-command: print regular_struct
// gdb-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false, the_fourth_field = "I'm so pretty, oh so pretty..."}

// gdb-command: print tuple
// gdb-check:$2 = {true, 103, "blub"}

// gdb-command: print tuple_struct
// gdb-check:$3 = TupleStruct = {-104.5, 105}

// gdb-command: print empty_struct
// gdb-check:$4 = EmptyStruct

// gdb-command: print c_style_enum1
// gdb-check:$5 = CStyleEnumVar1

// gdb-command: print c_style_enum2
// gdb-check:$6 = CStyleEnumVar2

// gdb-command: print c_style_enum3
// gdb-check:$7 = CStyleEnumVar3

// gdb-command: print mixed_enum_c_style_var
// gdb-check:$8 = MixedEnumCStyleVar

// gdb-command: print mixed_enum_tuple_var
// gdb-check:$9 = MixedEnumTupleVar = {106, 107, false}

// gdb-command: print mixed_enum_struct_var
// gdb-check:$10 = MixedEnumStructVar = {field1 = 108.5, field2 = 109}

// gdb-command: print some
// gdb-check:$11 = Some = {110}

// gdb-command: print none
// gdb-check:$12 = None

// gdb-command: print some_fat
// gdb-check:$13 = Some = {"abc"}

// gdb-command: print none_fat
// gdb-check:$14 = None

// gdb-command: print nested_variant1
// gdb-check:$15 = NestedVariant1 = {NestedStruct = {regular_struct = RegularStruct = {the_first_field = 111, the_second_field = 112.5, the_third_field = true, the_fourth_field = "NestedStructString1"}, tuple_struct = TupleStruct = {113.5, 114}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar2, mixed_enum = MixedEnumTupleVar = {115, 116, false}}}

// gdb-command: print nested_variant2
// gdb-check:$16 = NestedVariant2 = {abc = NestedStruct = {regular_struct = RegularStruct = {the_first_field = 117, the_second_field = 118.5, the_third_field = false, the_fourth_field = "NestedStructString10"}, tuple_struct = TupleStruct = {119.5, 120}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar3, mixed_enum = MixedEnumStructVar = {field1 = 121.5, field2 = -122}}}

// gdb-command: print none_check1
// gdb-check:$17 = None

// gdb-command: print none_check2
// gdb-check:$18 = None

#![allow(dead_code, unused_variables)]

use self::CStyleEnum::{CStyleEnumVar1, CStyleEnumVar2, CStyleEnumVar3};
use self::MixedEnum::{MixedEnumCStyleVar, MixedEnumTupleVar, MixedEnumStructVar};
use self::NestedEnum::{NestedVariant1, NestedVariant2};

struct RegularStruct {
    the_first_field: isize,
    the_second_field: f64,
    the_third_field: bool,
    the_fourth_field: &'static str,
}

struct TupleStruct(f64, i16);

struct EmptyStruct;

enum CStyleEnum {
    CStyleEnumVar1,
    CStyleEnumVar2,
    CStyleEnumVar3,
}

enum MixedEnum {
    MixedEnumCStyleVar,
    MixedEnumTupleVar(u32, u16, bool),
    MixedEnumStructVar { field1: f64, field2: i32 }
}

struct NestedStruct {
    regular_struct: RegularStruct,
    tuple_struct: TupleStruct,
    empty_struct: EmptyStruct,
    c_style_enum: CStyleEnum,
    mixed_enum: MixedEnum,
}

enum NestedEnum {
    NestedVariant1(NestedStruct),
    NestedVariant2 { abc: NestedStruct }
}

fn main() {

    let regular_struct = RegularStruct {
        the_first_field: 101,
        the_second_field: 102.5,
        the_third_field: false,
        the_fourth_field: "I'm so pretty, oh so pretty..."
    };

    let tuple = ( true, 103u32, "blub" );

    let tuple_struct = TupleStruct(-104.5, 105);

    let empty_struct = EmptyStruct;

    let c_style_enum1 = CStyleEnumVar1;
    let c_style_enum2 = CStyleEnumVar2;
    let c_style_enum3 = CStyleEnumVar3;

    let mixed_enum_c_style_var = MixedEnumCStyleVar;
    let mixed_enum_tuple_var = MixedEnumTupleVar(106, 107, false);
    let mixed_enum_struct_var = MixedEnumStructVar { field1: 108.5, field2: 109 };

    let some = Some(110_usize);
    let none: Option<isize> = None;
    let some_fat = Some("abc");
    let none_fat: Option<&'static str> = None;

    let nested_variant1 = NestedVariant1(
        NestedStruct {
            regular_struct: RegularStruct {
                the_first_field: 111,
                the_second_field: 112.5,
                the_third_field: true,
                the_fourth_field: "NestedStructString1",
            },
            tuple_struct: TupleStruct(113.5, 114),
            empty_struct: EmptyStruct,
            c_style_enum: CStyleEnumVar2,
            mixed_enum: MixedEnumTupleVar(115, 116, false)
        }
    );

    let nested_variant2 = NestedVariant2 {
        abc: NestedStruct {
            regular_struct: RegularStruct {
                the_first_field: 117,
                the_second_field: 118.5,
                the_third_field: false,
                the_fourth_field: "NestedStructString10",
            },
            tuple_struct: TupleStruct(119.5, 120),
            empty_struct: EmptyStruct,
            c_style_enum: CStyleEnumVar3,
            mixed_enum: MixedEnumStructVar {
                field1: 121.5,
                field2: -122
            }
        }
    };

    let none_check1: Option<(usize, Vec<usize>)> = None;
    let none_check2: Option<String> = None;

    zzz(); // #break
}

fn zzz() { () }
<commit_msg>test: Ignore gdb-pretty-struct-and-enums.rs<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-test also broken on nightly linux distcheck. it's just broken!
// ignore-windows failing on win32 bot
// ignore-freebsd: output doesn't match
// ignore-tidy-linelength
// ignore-lldb
// ignore-android: FIXME(#10381)
// compile-flags:-g

// This test uses some GDB Python API features (e.g. accessing anonymous fields)
// which are only available in newer GDB version. The following directive will
// case the test runner to ignore this test if an older GDB version is used:
// min-gdb-version 7.7

// gdb-command: run

// gdb-command: print regular_struct
// gdb-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false, the_fourth_field = "I'm so pretty, oh so pretty..."}

// gdb-command: print tuple
// gdb-check:$2 = {true, 103, "blub"}

// gdb-command: print tuple_struct
// gdb-check:$3 = TupleStruct = {-104.5, 105}

// gdb-command: print empty_struct
// gdb-check:$4 = EmptyStruct

// gdb-command: print c_style_enum1
// gdb-check:$5 = CStyleEnumVar1

// gdb-command: print c_style_enum2
// gdb-check:$6 = CStyleEnumVar2

// gdb-command: print c_style_enum3
// gdb-check:$7 = CStyleEnumVar3

// gdb-command: print mixed_enum_c_style_var
// gdb-check:$8 = MixedEnumCStyleVar

// gdb-command: print mixed_enum_tuple_var
// gdb-check:$9 = MixedEnumTupleVar = {106, 107, false}

// gdb-command: print mixed_enum_struct_var
// gdb-check:$10 = MixedEnumStructVar = {field1 = 108.5, field2 = 109}

// gdb-command: print some
// gdb-check:$11 = Some = {110}

// gdb-command: print none
// gdb-check:$12 = None

// gdb-command: print some_fat
// gdb-check:$13 = Some = {"abc"}

// gdb-command: print none_fat
// gdb-check:$14 = None

// gdb-command: print nested_variant1
// gdb-check:$15 = NestedVariant1 = {NestedStruct = {regular_struct = RegularStruct = {the_first_field = 111, the_second_field = 112.5, the_third_field = true, the_fourth_field = "NestedStructString1"}, tuple_struct = TupleStruct = {113.5, 114}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar2, mixed_enum = MixedEnumTupleVar = {115, 116, false}}}

// gdb-command: print nested_variant2
// gdb-check:$16 = NestedVariant2 = {abc = NestedStruct = {regular_struct = RegularStruct = {the_first_field = 117, the_second_field = 118.5, the_third_field = false, the_fourth_field = "NestedStructString10"}, tuple_struct = TupleStruct = {119.5, 120}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar3, mixed_enum = MixedEnumStructVar = {field1 = 121.5, field2 = -122}}}

// gdb-command: print none_check1
// gdb-check:$17 = None

// gdb-command: print none_check2
// gdb-check:$18 = None

#![allow(dead_code, unused_variables)]

use self::CStyleEnum::{CStyleEnumVar1, CStyleEnumVar2, CStyleEnumVar3};
use self::MixedEnum::{MixedEnumCStyleVar, MixedEnumTupleVar, MixedEnumStructVar};
use self::NestedEnum::{NestedVariant1, NestedVariant2};

struct RegularStruct {
    the_first_field: isize,
    the_second_field: f64,
    the_third_field: bool,
    the_fourth_field: &'static str,
}

struct TupleStruct(f64, i16);

struct EmptyStruct;

enum CStyleEnum {
    CStyleEnumVar1,
    CStyleEnumVar2,
    CStyleEnumVar3,
}

enum MixedEnum {
    MixedEnumCStyleVar,
    MixedEnumTupleVar(u32, u16, bool),
    MixedEnumStructVar { field1: f64, field2: i32 }
}

struct NestedStruct {
    regular_struct: RegularStruct,
    tuple_struct: TupleStruct,
    empty_struct: EmptyStruct,
    c_style_enum: CStyleEnum,
    mixed_enum: MixedEnum,
}

enum NestedEnum {
    NestedVariant1(NestedStruct),
    NestedVariant2 { abc: NestedStruct }
}

fn main() {

    let regular_struct = RegularStruct {
        the_first_field: 101,
        the_second_field: 102.5,
        the_third_field: false,
        the_fourth_field: "I'm so pretty, oh so pretty..."
    };

    let tuple = ( true, 103u32, "blub" );

    let tuple_struct = TupleStruct(-104.5, 105);

    let empty_struct = EmptyStruct;

    let c_style_enum1 = CStyleEnumVar1;
    let c_style_enum2 = CStyleEnumVar2;
    let c_style_enum3 = CStyleEnumVar3;

    let mixed_enum_c_style_var = MixedEnumCStyleVar;
    let mixed_enum_tuple_var = MixedEnumTupleVar(106, 107, false);
    let mixed_enum_struct_var = MixedEnumStructVar { field1: 108.5, field2: 109 };

    let some = Some(110_usize);
    let none: Option<isize> = None;
    let some_fat = Some("abc");
    let none_fat: Option<&'static str> = None;

    let nested_variant1 = NestedVariant1(
        NestedStruct {
            regular_struct: RegularStruct {
                the_first_field: 111,
                the_second_field: 112.5,
                the_third_field: true,
                the_fourth_field: "NestedStructString1",
            },
            tuple_struct: TupleStruct(113.5, 114),
            empty_struct: EmptyStruct,
            c_style_enum: CStyleEnumVar2,
            mixed_enum: MixedEnumTupleVar(115, 116, false)
        }
    );

    let nested_variant2 = NestedVariant2 {
        abc: NestedStruct {
            regular_struct: RegularStruct {
                the_first_field: 117,
                the_second_field: 118.5,
                the_third_field: false,
                the_fourth_field: "NestedStructString10",
            },
            tuple_struct: TupleStruct(119.5, 120),
            empty_struct: EmptyStruct,
            c_style_enum: CStyleEnumVar3,
            mixed_enum: MixedEnumStructVar {
                field1: 121.5,
                field2: -122
            }
        }
    };

    let none_check1: Option<(usize, Vec<usize>)> = None;
    let none_check2: Option<String> = None;

    zzz(); // #break
}

fn zzz() { () }
<|endoftext|>


<commit_before>//! A wrapper around a Cairo image surface.

use std::io::Write;
use std::fs::File;
use std::default::Default;

use cairo::{Format, ImageSurface};
use glib::translate::ToGlibPtr;
use rlua::{self, LightUserData, Lua, Table,
           UserData, UserDataMethods, Value};
use wlroots::{Area, Origin, Size};
use tempfile;

use common::{class::{self, Class},
             object::{self, Object},
             property::Property};
use wayland_obj::{self, XdgToplevel};
use common::signal::emit_object_signal;

#[derive(Debug)]
pub struct DrawableState {
    temp_file: File,
    wayland_shell: XdgToplevel,
    pub surface: Option<ImageSurface>,
    geo: Area,
    // TODO Use this to determine whether we draw this or not
    refreshed: bool
}

pub type Drawable<'lua> = Object<'lua, DrawableState>;

impl Default for DrawableState {
    fn default() -> Self {
        let wayland_shell = wayland_obj::create_xdg_toplevel(None)
            .expect("Could not construct an xdg toplevel for a drawable");
        // TODO Is a temp file really the best way to do this?
        let temp_file = tempfile::tempfile()
            .expect("Could not make a temp file for the buffer");
        DrawableState { temp_file,
                        wayland_shell,
                        surface: None,
                        geo: Area::default(),
                        refreshed: false }
    }
}

impl<'lua> Drawable<'lua> {
    pub fn new(lua: &Lua) -> rlua::Result<Drawable> {
        let class = class::class_setup(lua, "drawable")?;
        let builder = Drawable::allocate(lua, class)?;
        // TODO Do properly
        let table = lua.create_table()?;
        table.set("geometry", lua.create_function(geometry)?)?;
        table.set("refresh", lua.create_function(refresh)?)?;
        Ok(builder.add_to_meta(table)?.build())
    }

    pub fn get_geometry(&self) -> rlua::Result<Area> {
        let drawable = self.state()?;
        Ok(drawable.geo)
    }

    pub fn get_surface(&self) -> rlua::Result<Value<'lua>> {
        let drawable = self.state()?;
        Ok(match drawable.surface {
            None => Value::Nil,
            Some(ref image) => {
                let stash = image.to_glib_none();
                let ptr = stash.0;
                // NOTE
                // We bump the reference count because now Lua has a reference which
                // it manages via LGI.
                //
                // If there's a bug, worst case scenario there's a memory leak.
                unsafe {
                    ::cairo_sys::cairo_surface_reference(ptr);
                }
                Value::LightUserData(LightUserData(ptr as _))
            }
        })
    }

    /// Sets the geometry, and allocates a new surface.
    pub fn set_geometry(&mut self, lua: &Lua, geometry: Area) -> rlua::Result<()> {
        use rlua::Error::RuntimeError;
        let obj_clone = self.clone();
        let mut drawable = self.state_mut()?;
        let size_changed = drawable.geo != geometry;
        drawable.geo = geometry;
        if size_changed {
            drawable.refreshed = false;
            drawable.surface = None;
            // TODO The first one we create is useless.
            // How do we ensure we don't have that overhead? Option<>?
            drawable.wayland_shell = wayland_obj::create_xdg_toplevel(None)
                .expect("Could not construct an xdg toplevel for a drawable");
            let size: Size = geometry.size;

            if size.width > 0 && size.height > 0 {
                let temp_file = tempfile::tempfile()
                    .expect("Could not make new temp file");
                temp_file.set_len(size.width as u64 * size.height as u64 * 4)
                    .expect("Could not set file length");
                drawable.surface = Some(ImageSurface::create(Format::ARgb32,
                                                             size.width,
                                                             size.height)
                    .map_err(|err| RuntimeError(format!("Could not allocate {:?}", err)))?);
                drawable.wayland_shell.set_size(size);
                drawable.wayland_shell.set_surface(&temp_file, size)
                    .map_err(|_| RuntimeError(format!("Could not set surface for drawable")))?;
                drawable.temp_file = temp_file;
                emit_object_signal(lua, obj_clone.into(), "property::surface".into(), ())?;
            }
        }
        Ok(())
    }

    /// Signals that the drawable's surface was updated.
    pub fn refresh(&mut self) -> rlua::Result<()> {
        let mut drawable = self.state_mut()?;
        let drawable = &mut *drawable;
        if let Some(data) = drawable.surface.as_mut().map(get_data) {
            drawable.temp_file.write(&*data)
                .expect("Could not write data to buffer");
            drawable.temp_file.flush()
                .expect("Could not flush buffer");
            drawable.refreshed = true;
        }
        Ok(())
    }
}

impl UserData for DrawableState {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        object::default_add_methods(methods);
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class<DrawableState>> {
    Class::<DrawableState>::builder(lua, "drawable", None)?
        .method("geometry".into(), lua.create_function(geometry)?)?
        .property(Property::new("surface".into(),
                                None,
                                Some(lua.create_function(get_surface)?),
                                None))?
        .save_class("drawable")?
        .build()
}

fn get_surface<'lua>(_: &'lua Lua, drawable: Drawable<'lua>) -> rlua::Result<Value<'lua>> {
    drawable.get_surface()
}

fn geometry<'lua>(lua: &'lua Lua, drawable: Drawable<'lua>) -> rlua::Result<Table<'lua>> {
    let geometry = drawable.get_geometry()?;
    let Origin { x, y } = geometry.origin;
    let Size { width, height } = geometry.size;
    let table = lua.create_table()?;
    table.set("x", x)?;
    table.set("y", y)?;
    table.set("width", width)?;
    table.set("height", height)?;
    Ok(table)
}

fn refresh<'lua>(_: &'lua Lua, mut drawable: Drawable<'lua>) -> rlua::Result<()> {
    drawable.refresh()
}

/// Get the data associated with the ImageSurface.
fn get_data(surface: &mut ImageSurface) -> &[u8] {
    // NOTE This is safe to do because there's one thread.
    //
    // We know Lua is not modifying it because it's not running.
    use std::slice;
    use cairo_sys;
    unsafe {
        let len = surface.get_stride() as usize * surface.get_height() as usize;
        let surface = surface.to_glib_none().0;
        slice::from_raw_parts(cairo_sys::cairo_image_surface_get_data(surface as _), len)
    }
}
<commit_msg>don't init xdg top level until the first one<commit_after>//! A wrapper around a Cairo image surface.

use std::io::Write;
use std::fs::File;
use std::default::Default;

use cairo::{Format, ImageSurface};
use glib::translate::ToGlibPtr;
use rlua::{self, LightUserData, Lua, Table,
           UserData, UserDataMethods, Value};
use wlroots::{Area, Origin, Size};
use tempfile;

use common::{class::{self, Class},
             object::{self, Object},
             property::Property};
use wayland_obj::{self, XdgToplevel};
use common::signal::emit_object_signal;

#[derive(Debug)]
pub struct DrawableState {
    temp_file: File,
    wayland_shell: Option<XdgToplevel>,
    pub surface: Option<ImageSurface>,
    geo: Area,
    // TODO Use this to determine whether we draw this or not
    refreshed: bool
}

pub type Drawable<'lua> = Object<'lua, DrawableState>;

impl Default for DrawableState {
    fn default() -> Self {
        let temp_file = tempfile::tempfile()
            .expect("Could not make a temp file for the buffer");
        DrawableState { temp_file,
                        wayland_shell: None,
                        surface: None,
                        geo: Area::default(),
                        refreshed: false }
    }
}

impl<'lua> Drawable<'lua> {
    pub fn new(lua: &Lua) -> rlua::Result<Drawable> {
        let class = class::class_setup(lua, "drawable")?;
        let builder = Drawable::allocate(lua, class)?;
        // TODO Do properly
        let table = lua.create_table()?;
        table.set("geometry", lua.create_function(geometry)?)?;
        table.set("refresh", lua.create_function(refresh)?)?;
        Ok(builder.add_to_meta(table)?.build())
    }

    pub fn get_geometry(&self) -> rlua::Result<Area> {
        let drawable = self.state()?;
        Ok(drawable.geo)
    }

    pub fn get_surface(&self) -> rlua::Result<Value<'lua>> {
        let drawable = self.state()?;
        Ok(match drawable.surface {
            None => Value::Nil,
            Some(ref image) => {
                let stash = image.to_glib_none();
                let ptr = stash.0;
                // NOTE
                // We bump the reference count because now Lua has a reference which
                // it manages via LGI.
                //
                // If there's a bug, worst case scenario there's a memory leak.
                unsafe {
                    ::cairo_sys::cairo_surface_reference(ptr);
                }
                Value::LightUserData(LightUserData(ptr as _))
            }
        })
    }

    /// Sets the geometry, and allocates a new surface.
    pub fn set_geometry(&mut self, lua: &Lua, geometry: Area) -> rlua::Result<()> {
        use rlua::Error::RuntimeError;
        let obj_clone = self.clone();
        let mut drawable = self.state_mut()?;
        let size_changed = drawable.geo != geometry;
        drawable.geo = geometry;
        if size_changed {
            drawable.refreshed = false;
            drawable.surface = None;
            drawable.wayland_shell = Some(wayland_obj::create_xdg_toplevel(None)
                .expect("Could not construct an xdg toplevel for a drawable"));
            let size: Size = geometry.size;

            if size.width > 0 && size.height > 0 {
                let temp_file = tempfile::tempfile()
                    .expect("Could not make new temp file");
                temp_file.set_len(size.width as u64 * size.height as u64 * 4)
                    .expect("Could not set file length");
                drawable.surface = Some(ImageSurface::create(Format::ARgb32,
                                                             size.width,
                                                             size.height)
                    .map_err(|err| RuntimeError(format!("Could not allocate {:?}", err)))?);
                {
                    let shell = drawable.wayland_shell.as_mut().unwrap();
                    shell.set_size(size);
                    shell.set_surface(&temp_file, size)
                        .map_err(|_| RuntimeError(format!("Could not set surface for drawable")))?;
                }
                drawable.temp_file = temp_file;
                emit_object_signal(lua, obj_clone.into(), "property::surface".into(), ())?;
            }
        }
        Ok(())
    }

    /// Signals that the drawable's surface was updated.
    pub fn refresh(&mut self) -> rlua::Result<()> {
        let mut drawable = self.state_mut()?;
        let drawable = &mut *drawable;
        if let Some(data) = drawable.surface.as_mut().map(get_data) {
            drawable.temp_file.write(&*data)
                .expect("Could not write data to buffer");
            drawable.temp_file.flush()
                .expect("Could not flush buffer");
            drawable.refreshed = true;
        }
        Ok(())
    }
}

impl UserData for DrawableState {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        object::default_add_methods(methods);
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class<DrawableState>> {
    Class::<DrawableState>::builder(lua, "drawable", None)?
        .method("geometry".into(), lua.create_function(geometry)?)?
        .property(Property::new("surface".into(),
                                None,
                                Some(lua.create_function(get_surface)?),
                                None))?
        .save_class("drawable")?
        .build()
}

fn get_surface<'lua>(_: &'lua Lua, drawable: Drawable<'lua>) -> rlua::Result<Value<'lua>> {
    drawable.get_surface()
}

fn geometry<'lua>(lua: &'lua Lua, drawable: Drawable<'lua>) -> rlua::Result<Table<'lua>> {
    let geometry = drawable.get_geometry()?;
    let Origin { x, y } = geometry.origin;
    let Size { width, height } = geometry.size;
    let table = lua.create_table()?;
    table.set("x", x)?;
    table.set("y", y)?;
    table.set("width", width)?;
    table.set("height", height)?;
    Ok(table)
}

fn refresh<'lua>(_: &'lua Lua, mut drawable: Drawable<'lua>) -> rlua::Result<()> {
    drawable.refresh()
}

/// Get the data associated with the ImageSurface.
fn get_data(surface: &mut ImageSurface) -> &[u8] {
    // NOTE This is safe to do because there's one thread.
    //
    // We know Lua is not modifying it because it's not running.
    use std::slice;
    use cairo_sys;
    unsafe {
        let len = surface.get_stride() as usize * surface.get_height() as usize;
        let surface = surface.to_glib_none().0;
        slice::from_raw_parts(cairo_sys::cairo_image_surface_get_data(surface as _), len)
    }
}
<|endoftext|>


<commit_before>//! Implements some higher-level searching facilities.

use std::cmp::min;
use std::sync::Arc;
use std::time::{SystemTime, Duration};
use basetypes::*;
use tt::*;
use position::*;
use search::*;

/// Contains information about the current progress of a search.
pub struct SearchStatus {
    /// The starting time for the search.
    pub started_at: SystemTime,

    /// The root position for the search.
    pub position: Position,

    /// `true` if the search is done, `false` otherwise.
    pub done: bool,

    /// The search depth completed so far.
    pub depth: u8,

    /// The number of first moves (from the root position) that are
    /// being considered.
    pub searchmoves_count: usize,

    /// The best variations found so far, sorted by descending first
    /// move strength. (The first move in each variation will be
    /// different.)
    pub variations: Vec<Variation>,

    /// The duration of the search in milliseconds.
    pub duration_millis: u64,

    /// The number of analyzed nodes.
    pub searched_nodes: NodeCount,

    /// Average number of analyzed nodes per second.
    pub nps: NodeCount,
}

/// A thread that executes consecutive searches in different starting
/// positions.
pub struct SearchThread {
    tt: Arc<Tt>,
    status: SearchStatus,
    searcher: DeepeningSearcher<MultipvSearcher<AlphabetaSearcher>>,
}

impl SearchThread {
    /// Creates a new instance.
    pub fn new(tt: Arc<Tt>) -> SearchThread {
        SearchThread {
            tt: tt.clone(),
            status: SearchStatus {
                started_at: SystemTime::now(),
                position: Position::from_fen(START_POSITION_FEN).ok().unwrap(),
                done: true,
                depth: 0,
                variations: vec![Variation {
                                     value: VALUE_MIN,
                                     bound: BOUND_LOWER,
                                     moves: vec![],
                                 }],
                searchmoves_count: 20,
                searched_nodes: 0,
                duration_millis: 0,
                nps: 0,
            },
            searcher: DeepeningSearcher::new(tt),
        }
    }

    /// Terminates the currently running search (if any), starts a new
    /// search, updates the status.
    ///
    /// `position` is the starting position for the new
    /// search. `variation_count` specifies how many best lines of
    /// play to calculate (the first move in each line will be
    /// different). `searchmoves` restricts the analysis to the
    /// supplied list of moves only (no restrictions if the suppied
    /// list is empty). The move format is long algebraic
    /// notation. Examples: e2e4, e7e5, e1g1 (white short castling),
    /// e7e8q (for promotion).
    pub fn search(&mut self,
                  position: &Position,
                  variation_count: usize,
                  mut searchmoves: Vec<String>) {
        // Validate `searchmoves`.
        let mut moves = vec![];
        let legal_moves = position.legal_moves();
        if !searchmoves.is_empty() {
            searchmoves.sort();
            for m in legal_moves.iter() {
                if searchmoves.binary_search(&m.notation()).is_ok() {
                    moves.push(*m);
                }
            }
        };
        let searchmoves = if moves.is_empty() {
            legal_moves
        } else {
            moves
        };

        // Terminate the currently running search.
        self.stop();

        // Update the status.
        self.status = SearchStatus {
            started_at: SystemTime::now(),
            position: position.clone(),
            done: false,
            depth: 0,
            searchmoves_count: searchmoves.len(),
            variations: vec![Variation {
                                 value: VALUE_MIN,
                                 bound: BOUND_LOWER,
                                 moves: searchmoves.first().map_or(vec![], |m| vec![*m]),
                             }],
            searched_nodes: 0,
            duration_millis: 0,
            ..self.status
        };

        // Start a new search.
        self.searcher.start_search(SearchParams {
            search_id: 0,
            position: position.clone(),
            depth: MAX_DEPTH,
            lower_bound: VALUE_MIN,
            upper_bound: VALUE_MAX,
            searchmoves: searchmoves,
            variation_count: variation_count,
        });
    }

    /// Terminates the currently running search (if any), updates the
    /// status.
    pub fn stop(&mut self) {
        self.searcher.terminate_search();
        while !self.status().done {
            self.wait_status_update(Duration::from_millis(1000));
        }
    }

    /// Returns the status of the current search.
    ///
    /// **Important note:** Consecutive calls to this method will
    /// return the same unchanged result. Only after calling `search`,
    /// `stop`, or `wait_status_update`, the result returned by
    /// `status` may change.
    #[inline(always)]
    pub fn status(&self) -> &SearchStatus {
        &self.status
    }

    /// Waits for a search status update, timing out after a specified
    /// duration or earlier.
    pub fn wait_status_update(&mut self, duration: Duration) {
        self.searcher.wait_report(duration);
        while let Ok(r) = self.searcher.try_recv_report() {
            self.process_report(r)
        }
    }

    /// A helper method. It updates the current status according to
    /// the received report message.
    fn process_report(&mut self, report: Report) {
        let duration = self.status.started_at.elapsed().unwrap();
        self.status.duration_millis = 1000 * duration.as_secs() +
                                      (duration.subsec_nanos() / 1000000) as u64;
        self.status.searched_nodes = report.searched_nodes;
        self.status.nps = 1000 * (self.status.nps + self.status.searched_nodes) /
                          (1000 + self.status.duration_millis);
        if self.status.depth < report.depth {
            self.status.depth = report.depth;
            self.status.variations = vec![extract_pv(&self.tt,
                                                     &self.status.position,
                                                     report.depth)];
        }
        self.status.done = report.done;
    }
}

/// Decides when the search must be terminated.
pub struct TimeManager {
    move_time_millis: u64, // move time in milliseconds
    must_play: bool,
}

impl TimeManager {
    /// Creates a new instance.
    ///
    /// `position` gives the current position. `pondering_is_allowed`
    /// tells if the engine is allowed to use opponent's time for
    /// thinking. `wtime_millis`, `btime_millis`, `winc_millis`, and
    /// `binc_millis` specify the remaining time in milliseconds, and
    /// the number of milliseconds with which the remaining time will
    /// be incremented on each move (for black and white). `movestogo`
    /// specifies the number of moves to the next time control.
    #[allow(unused_variables)]
    pub fn new(position: &Position,
               pondering_is_allowed: bool,
               wtime_millis: Option<u64>,
               btime_millis: Option<u64>,
               winc_millis: Option<u64>,
               binc_millis: Option<u64>,
               movestogo: Option<u64>)
               -> TimeManager {
        // TODO: We ignore "pondering_is_allowed".

        let (time, inc) = if position.to_move() == WHITE {
            (wtime_millis, winc_millis.unwrap_or(0))
        } else {
            (btime_millis, binc_millis.unwrap_or(0))
        };
        let time = time.unwrap_or(0);
        let movestogo = movestogo.unwrap_or(40);
        let movetime = (time + inc * movestogo) / movestogo;
        TimeManager {
            move_time_millis: min(movetime, time / 2),
            must_play: false,
        }
    }

    /// Registers the current search status with the time manager.
    pub fn update_status(&mut self, new_status: &SearchStatus) {
        // TODO: Implement smarter time management.
        self.must_play = new_status.duration_millis >= self.move_time_millis;
    }

    /// Decides if the search must be terminated.
    #[inline]
    pub fn must_play(&self) -> bool {
        self.must_play
    }
}
<commit_msg>remove SearchStatus.position field<commit_after>//! Implements some higher-level searching facilities.

use std::cmp::min;
use std::sync::Arc;
use std::time::{SystemTime, Duration};
use basetypes::*;
use tt::*;
use position::*;
use search::*;

/// Contains information about the current progress of a search.
pub struct SearchStatus {
    /// The starting time for the search.
    pub started_at: SystemTime,

    /// `true` if the search is done, `false` otherwise.
    pub done: bool,

    /// The search depth completed so far.
    pub depth: u8,

    /// The number of different first moves (from the root position)
    /// that are being considered.
    pub searchmoves_count: usize,

    /// The best variations found so far, sorted by descending first
    /// move strength. (The first move in each variation will be
    /// different.)
    pub variations: Vec<Variation>,

    /// The duration of the search in milliseconds.
    pub duration_millis: u64,

    /// The number of analyzed nodes.
    pub searched_nodes: NodeCount,

    /// Average number of analyzed nodes per second.
    pub nps: NodeCount,
}

/// A thread that executes consecutive searches in different starting
/// positions.
pub struct SearchThread {
    tt: Arc<Tt>,
    position: Position,
    status: SearchStatus,
    searcher: DeepeningSearcher<MultipvSearcher<AlphabetaSearcher>>,
}

impl SearchThread {
    /// Creates a new instance.
    pub fn new(tt: Arc<Tt>) -> SearchThread {
        SearchThread {
            tt: tt.clone(),
            position: Position::from_fen(START_POSITION_FEN).ok().unwrap(),
            status: SearchStatus {
                started_at: SystemTime::now(),
                done: true,
                depth: 0,
                variations: vec![Variation {
                                     value: VALUE_MIN,
                                     bound: BOUND_LOWER,
                                     moves: vec![],
                                 }],
                searchmoves_count: 20,
                searched_nodes: 0,
                duration_millis: 0,
                nps: 0,
            },
            searcher: DeepeningSearcher::new(tt),
        }
    }

    /// Terminates the currently running search (if any), starts a new
    /// search, updates the status.
    ///
    /// `position` is the starting position for the new
    /// search. `variation_count` specifies how many best lines of
    /// play to calculate (the first move in each line will be
    /// different). `searchmoves` restricts the analysis to the
    /// supplied list of moves only (no restrictions if the suppied
    /// list is empty). The move format is long algebraic
    /// notation. Examples: e2e4, e7e5, e1g1 (white short castling),
    /// e7e8q (for promotion).
    pub fn search(&mut self,
                  position: &Position,
                  variation_count: usize,
                  mut searchmoves: Vec<String>) {
        // Validate `searchmoves`.
        let mut moves = vec![];
        let legal_moves = position.legal_moves();
        if !searchmoves.is_empty() {
            searchmoves.sort();
            for m in legal_moves.iter() {
                if searchmoves.binary_search(&m.notation()).is_ok() {
                    moves.push(*m);
                }
            }
        };
        let searchmoves = if moves.is_empty() {
            legal_moves
        } else {
            moves
        };

        // Terminate the currently running search.
        self.stop();

        // Update the status.
        self.status = SearchStatus {
            started_at: SystemTime::now(),
            done: false,
            depth: 0,
            searchmoves_count: searchmoves.len(),
            variations: vec![Variation {
                                 value: VALUE_MIN,
                                 bound: BOUND_LOWER,
                                 moves: searchmoves.first().map_or(vec![], |m| vec![*m]),
                             }],
            searched_nodes: 0,
            duration_millis: 0,
            ..self.status
        };

        // Start a new search.
        self.searcher.start_search(SearchParams {
            search_id: 0,
            position: position.clone(),
            depth: MAX_DEPTH,
            lower_bound: VALUE_MIN,
            upper_bound: VALUE_MAX,
            searchmoves: searchmoves,
            variation_count: variation_count,
        });
    }

    /// Terminates the currently running search (if any), updates the
    /// status.
    pub fn stop(&mut self) {
        self.searcher.terminate_search();
        while !self.status().done {
            self.wait_status_update(Duration::from_millis(1000));
        }
    }

    /// Returns the status of the current search.
    ///
    /// **Important note:** Consecutive calls to this method will
    /// return the same unchanged result. Only after calling `search`,
    /// `stop`, or `wait_status_update`, the result returned by
    /// `status` may change.
    #[inline(always)]
    pub fn status(&self) -> &SearchStatus {
        &self.status
    }

    /// Waits for a search status update, timing out after a specified
    /// duration or earlier.
    pub fn wait_status_update(&mut self, duration: Duration) {
        self.searcher.wait_report(duration);
        while let Ok(r) = self.searcher.try_recv_report() {
            self.process_report(r)
        }
    }

    /// A helper method. It updates the current status according to
    /// the received report message.
    fn process_report(&mut self, report: Report) {
        let duration = self.status.started_at.elapsed().unwrap();
        self.status.duration_millis = 1000 * duration.as_secs() +
                                      (duration.subsec_nanos() / 1000000) as u64;
        self.status.searched_nodes = report.searched_nodes;
        self.status.nps = 1000 * (self.status.nps + self.status.searched_nodes) /
                          (1000 + self.status.duration_millis);
        if self.status.depth < report.depth {
            self.status.depth = report.depth;
            self.status.variations = vec![extract_pv(&self.tt,
                                                     &self.position,
                                                     report.depth)];
        }
        self.status.done = report.done;
    }
}

/// Decides when the search must be terminated.
pub struct TimeManager {
    move_time_millis: u64, // move time in milliseconds
    must_play: bool,
}

impl TimeManager {
    /// Creates a new instance.
    ///
    /// `position` gives the current position. `pondering_is_allowed`
    /// tells if the engine is allowed to use opponent's time for
    /// thinking. `wtime_millis`, `btime_millis`, `winc_millis`, and
    /// `binc_millis` specify the remaining time in milliseconds, and
    /// the number of milliseconds with which the remaining time will
    /// be incremented on each move (for black and white). `movestogo`
    /// specifies the number of moves to the next time control.
    #[allow(unused_variables)]
    pub fn new(position: &Position,
               pondering_is_allowed: bool,
               wtime_millis: Option<u64>,
               btime_millis: Option<u64>,
               winc_millis: Option<u64>,
               binc_millis: Option<u64>,
               movestogo: Option<u64>)
               -> TimeManager {
        // TODO: We ignore "pondering_is_allowed".

        let (time, inc) = if position.to_move() == WHITE {
            (wtime_millis, winc_millis.unwrap_or(0))
        } else {
            (btime_millis, binc_millis.unwrap_or(0))
        };
        let time = time.unwrap_or(0);
        let movestogo = movestogo.unwrap_or(40);
        let movetime = (time + inc * movestogo) / movestogo;
        TimeManager {
            move_time_millis: min(movetime, time / 2),
            must_play: false,
        }
    }

    /// Registers the current search status with the time manager.
    pub fn update_status(&mut self, new_status: &SearchStatus) {
        // TODO: Implement smarter time management.
        self.must_play = new_status.duration_millis >= self.move_time_millis;
    }

    /// Decides if the search must be terminated.
    #[inline]
    pub fn must_play(&self) -> bool {
        self.must_play
    }
}
<|endoftext|>


<commit_before>use PatternValue;

use mir;
use util;

/// An adjustment to a pattern.
///
/// Not all possible patterns are an identical match to
/// the MIR. To accomodate this, we have the concept of a
/// pattern _adjustment_.
///
/// When matching patterns, we can have several adjustments
/// which define permutations that would need to be made to the
/// original pattern in order to match.
///
/// We can then look at all the adjustments and figure out which
/// pattern is the most optimal to select.
///
/// Take the case where we have
///
/// ```ignore
/// (add %a, (add %foo, %bar))
/// ```
///
/// This will likely have to have an adjustment to demote the
/// nested addition to a register, so that the code becomes.
///
/// ```ignore
/// %tmp = (add %foo, %bar)
/// (add %a, %tmp)
/// ```
#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Adjustment<V: PatternValue>
{
    /// Demotes a subnode to a register.
    DemoteToRegister {
        demotee: mir::Node,
    },
    /// Merges two virtual registers into one.
    ///
    /// This can do something like the following.
    ///
    /// ```ignore
    /// (set %a, (add %b, i5))
    /// ```
    ///
    /// ```ignore
    /// (set %a, (add %a, i5))
    /// ```
    ///
    /// So that they will always refer to the same physical register.
    MergeVirtualRegisters {
        /// The ID of the register to remove.
        from: util::Id,
        /// The ID of the register that will now be referenced.
        to: util::Id,
    },
    Target(V::Adjustment),
}

/// The result of an adjustment application.
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct AdjustmentApplication
{
    /// An adjustment may create extra nodes preceding the node
    /// that was adjusted. For example, promoting an operand
    /// to a register would a register set node to precede the adjusted node.
    pub preceding_nodes: Vec<mir::Node>,

    /// The original node that was adjusted.
    pub adjusted_node: mir::Node,
}

impl AdjustmentApplication
{
    pub fn unadjusted(node: mir::Node) -> Self {
        AdjustmentApplication {
            preceding_nodes: Vec::new(),
            adjusted_node: node,
        }
    }

    /// Gets all of the nodes (in order) that were created or modified
    /// by the adjustment.
    pub fn nodes(&self) -> Vec<mir::Node> {
        let mut nodes = self.preceding_nodes.clone();
        nodes.push(self.adjusted_node.clone());
        nodes
    }

    fn merge(mut self, other: Self) -> Self {
        self.preceding_nodes.extend(other.preceding_nodes);
        self.adjusted_node = other.adjusted_node;
        self
    }
}

impl<V: PatternValue> Adjustment<V>
{
    pub fn demote_to_register(node: &mir::Node) -> Self {
        Adjustment::DemoteToRegister {
            demotee: node.clone(),
        }
    }

    pub fn apply_several_to(root_node: mir::Node, adjustments: &[Self]) -> AdjustmentApplication {
        adjustments.iter().fold(AdjustmentApplication::unadjusted(root_node), |last_application, adjustment| {
            let current_node = last_application.adjusted_node.clone();
            last_application.merge(adjustment.apply_to(current_node))
        })
    }

    /// Applies an adjustment to a node.
    pub fn apply_to(&self, root_node: mir::Node) -> AdjustmentApplication {
        match *self {
            Adjustment::DemoteToRegister { ref demotee } => {
                let mut preceding_nodes = Vec::new();

                let adjusted_node = root_node.recursive_map(&mut |node| {
                    if node == *demotee {
                        let register_ref = mir::Node::new_register_ref(node.ty());
                        preceding_nodes.push(mir::Node::set(register_ref.clone(), node));
                        register_ref
                    } else {
                        node
                    }
                });

                AdjustmentApplication { preceding_nodes: preceding_nodes, adjusted_node: adjusted_node }
            },
            Adjustment::MergeVirtualRegisters { from, to } => {
                unimplemented!();
            },
            Adjustment::Target(ref _adjustment) => {
                unimplemented!();
            },
        }
    }
}

#[cfg(test)]
mod test
{
    mod apply_to {
        use super::super::*;
        use mir;
        use pattern::DummyPatternValue;

        #[test]
        fn demote_to_register() {
            let register_ref = mir::Node::new_register_ref(mir::Type::i8());
            let example_node = mir::Node::set(register_ref.clone(), mir::Node::i(8, 2));

            let adjustment: Adjustment<DummyPatternValue> = Adjustment::DemoteToRegister {
                demotee: mir::Node::i(8, 2)
            };

            let application = adjustment.apply_to(example_node);

            assert_eq!(application.preceding_nodes.len(), 1);

            let new_set_node = application.preceding_nodes[0].expect_branch();
            let new_register_ref = new_set_node.operands[0].clone();
            assert_eq!(new_set_node.operands[1], mir::Node::i(8, 2));

            let permuted_node = application.adjusted_node.expect_branch();
            assert_eq!(permuted_node.operands[1], new_register_ref);
        }
    }
}

<commit_msg>Revert "Add MergeVirtualRegisters adjustment"<commit_after>use PatternValue;
use mir;

/// An adjustment to a pattern.
///
/// Not all possible patterns are an identical match to
/// the MIR. To accomodate this, we have the concept of a
/// pattern _adjustment_.
///
/// When matching patterns, we can have several adjustments
/// which define permutations that would need to be made to the
/// original pattern in order to match.
///
/// We can then look at all the adjustments and figure out which
/// pattern is the most optimal to select.
///
/// Take the case where we have
///
/// ```ignore
/// (add %a, (add %foo, %bar))
/// ```
///
/// This will likely have to have an adjustment to demote the
/// nested addition to a register, so that the code becomes.
///
/// ```ignore
/// %tmp = (add %foo, %bar)
/// (add %a, %tmp)
/// ```
#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Adjustment<V: PatternValue>
{
    /// Demotes a subnode to a register.
    DemoteToRegister {
        demotee: mir::Node,
    },
    Target(V::Adjustment),
}

/// The result of an adjustment application.
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct AdjustmentApplication
{
    /// An adjustment may create extra nodes preceding the node
    /// that was adjusted. For example, promoting an operand
    /// to a register would a register set node to precede the adjusted node.
    pub preceding_nodes: Vec<mir::Node>,

    /// The original node that was adjusted.
    pub adjusted_node: mir::Node,
}

impl AdjustmentApplication
{
    pub fn unadjusted(node: mir::Node) -> Self {
        AdjustmentApplication {
            preceding_nodes: Vec::new(),
            adjusted_node: node,
        }
    }

    /// Gets all of the nodes (in order) that were created or modified
    /// by the adjustment.
    pub fn nodes(&self) -> Vec<mir::Node> {
        let mut nodes = self.preceding_nodes.clone();
        nodes.push(self.adjusted_node.clone());
        nodes
    }

    fn merge(mut self, other: Self) -> Self {
        self.preceding_nodes.extend(other.preceding_nodes);
        self.adjusted_node = other.adjusted_node;
        self
    }
}

impl<V: PatternValue> Adjustment<V>
{
    pub fn demote_to_register(node: &mir::Node) -> Self {
        Adjustment::DemoteToRegister {
            demotee: node.clone(),
        }
    }

    pub fn apply_several_to(root_node: mir::Node, adjustments: &[Self]) -> AdjustmentApplication {
        adjustments.iter().fold(AdjustmentApplication::unadjusted(root_node), |last_application, adjustment| {
            let current_node = last_application.adjusted_node.clone();
            last_application.merge(adjustment.apply_to(current_node))
        })
    }

    /// Applies an adjustment to a node.
    pub fn apply_to(&self, root_node: mir::Node) -> AdjustmentApplication {
        match *self {
            Adjustment::DemoteToRegister { ref demotee } => {
                let mut preceding_nodes = Vec::new();

                let adjusted_node = root_node.recursive_map(&mut |node| {
                    if node == *demotee {
                        let register_ref = mir::Node::new_register_ref(node.ty());
                        preceding_nodes.push(mir::Node::set(register_ref.clone(), node));
                        register_ref
                    } else {
                        node
                    }
                });

                AdjustmentApplication { preceding_nodes: preceding_nodes, adjusted_node: adjusted_node }
            },
            Adjustment::Target(ref _adjustment) => {
                unimplemented!();
            },
        }
    }
}

#[cfg(test)]
mod test
{
    mod apply_to {
        use super::super::*;
        use mir;
        use pattern::DummyPatternValue;

        #[test]
        fn demote_to_register() {
            let register_ref = mir::Node::new_register_ref(mir::Type::i8());
            let example_node = mir::Node::set(register_ref.clone(), mir::Node::i(8, 2));

            let adjustment: Adjustment<DummyPatternValue> = Adjustment::DemoteToRegister {
                demotee: mir::Node::i(8, 2)
            };

            let application = adjustment.apply_to(example_node);

            assert_eq!(application.preceding_nodes.len(), 1);

            let new_set_node = application.preceding_nodes[0].expect_branch();
            let new_register_ref = new_set_node.operands[0].clone();
            assert_eq!(new_set_node.operands[1], mir::Node::i(8, 2));

            let permuted_node = application.adjusted_node.expect_branch();
            assert_eq!(permuted_node.operands[1], new_register_ref);
        }
    }
}

<|endoftext|>


<commit_before>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

use glib;
use glib::prelude::*;

use gst;
use gst::prelude::*;

use std::env;

fn main() {
    gst::init().unwrap();

    #[cfg(debug_assertions)]
    {
        use std::path::Path;

        let mut path = Path::new("target/debug");
        if !path.exists() {
            path = Path::new("../target/debug");
        }

        gst::Registry::get().scan_path(path);
    }
    #[cfg(not(debug_assertions))]
    {
        use std::path::Path;

        let mut path = Path::new("target/release");
        if !path.exists() {
            path = Path::new("../target/release");
        }

        gst::Registry::get().scan_path(path);
    }

    let args = env::args().collect::<Vec<_>>();
    assert_eq!(args.len(), 6);
    let n_streams: u16 = args[1].parse().unwrap();
    let source = &args[2];
    let n_groups: u32 = args[3].parse().unwrap();
    let wait: u32 = args[4].parse().unwrap();

    let l = glib::MainLoop::new(None, false);
    let pipeline = gst::Pipeline::new(None);

    for i in 0..n_streams {
        let sink =
            gst::ElementFactory::make("fakesink", Some(format!("sink-{}", i).as_str())).unwrap();
        sink.set_property("sync", &false).unwrap();
        sink.set_property("async", &false).unwrap();

        let source = match source.as_str() {
            "udpsrc" => {
                let source =
                    gst::ElementFactory::make("udpsrc", Some(format!("source-{}", i).as_str()))
                        .unwrap();
                source
                    .set_property("port", &(40000i32 + (i as i32)))
                    .unwrap();
                source
                    .set_property("retrieve-sender-address", &false)
                    .unwrap();

                source
            }
            "ts-udpsrc" => {
                let source =
                    gst::ElementFactory::make("ts-udpsrc", Some(format!("source-{}", i).as_str()))
                        .unwrap();
                source
                    .set_property("port", &(40000u32 + (i as u32)))
                    .unwrap();
                source
                    .set_property("context", &format!("context-{}", (i as u32) % n_groups))
                    .unwrap();
                source.set_property("context-wait", &wait).unwrap();

                source
            }
            "ts-tcpclientsrc" => {
                let source = gst::ElementFactory::make(
                    "ts-tcpclientsrc",
                    Some(format!("source-{}", i).as_str()),
                )
                .unwrap();
                source.set_property("port", &(40000u32)).unwrap();
                source
                    .set_property("context", &format!("context-{}", (i as u32) % n_groups))
                    .unwrap();
                source.set_property("context-wait", &wait).unwrap();

                source
            }
            "tonegeneratesrc" => {
                let source = gst::ElementFactory::make(
                    "tonegeneratesrc",
                    Some(format!("source-{}", i).as_str()),
                )
                .unwrap();
                source
                    .set_property("samplesperbuffer", &((wait as i32) * 8000 / 1000))
                    .unwrap();

                sink.set_property("sync", &true).unwrap();

                source
            }
            "ts-tonesrc" => {
                let source =
                    gst::ElementFactory::make("ts-tonesrc", Some(format!("source-{}", i).as_str()))
                        .unwrap();
                source
                    .set_property("samples-per-buffer", &((wait as u32) * 8000 / 1000))
                    .unwrap();
                source
                    .set_property("context", &format!("context-{}", (i as u32) % n_groups))
                    .unwrap();
                source.set_property("context-wait", &wait).unwrap();

                source
            }
            _ => unimplemented!(),
        };

        pipeline.add_many(&[&source, &sink]).unwrap();
        source.link(&sink).unwrap();
    }

    let bus = pipeline.get_bus().unwrap();
    let l_clone = l.clone();
    bus.add_watch(move |_, msg| {
        use gst::MessageView;

        match msg.view() {
            MessageView::Eos(..) => l_clone.quit(),
            MessageView::Error(err) => {
                println!(
                    "Error from {:?}: {} ({:?})",
                    err.get_src().map(|s| s.get_path_string()),
                    err.get_error(),
                    err.get_debug()
                );
                l_clone.quit();
            }
            _ => (),
        };

        glib::Continue(true)
    })
    .expect("Failed to add bus watch");

    pipeline.set_state(gst::State::Playing).unwrap();

    println!("started");

    l.run();
}
<commit_msg>threashare: benchmark: fix target path<commit_after>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

use glib;
use glib::prelude::*;

use gst;
use gst::prelude::*;

use std::env;

fn main() {
    gst::init().unwrap();

    #[cfg(debug_assertions)]
    {
        use std::path::Path;

        let mut path = Path::new("target/debug");
        if !path.exists() {
            path = Path::new("../../target/debug");
        }

        gst::Registry::get().scan_path(path);
    }
    #[cfg(not(debug_assertions))]
    {
        use std::path::Path;

        let mut path = Path::new("target/release");
        if !path.exists() {
            path = Path::new("../../target/release");
        }

        gst::Registry::get().scan_path(path);
    }

    let args = env::args().collect::<Vec<_>>();
    assert_eq!(args.len(), 6);
    let n_streams: u16 = args[1].parse().unwrap();
    let source = &args[2];
    let n_groups: u32 = args[3].parse().unwrap();
    let wait: u32 = args[4].parse().unwrap();

    let l = glib::MainLoop::new(None, false);
    let pipeline = gst::Pipeline::new(None);

    for i in 0..n_streams {
        let sink =
            gst::ElementFactory::make("fakesink", Some(format!("sink-{}", i).as_str())).unwrap();
        sink.set_property("sync", &false).unwrap();
        sink.set_property("async", &false).unwrap();

        let source = match source.as_str() {
            "udpsrc" => {
                let source =
                    gst::ElementFactory::make("udpsrc", Some(format!("source-{}", i).as_str()))
                        .unwrap();
                source
                    .set_property("port", &(40000i32 + (i as i32)))
                    .unwrap();
                source
                    .set_property("retrieve-sender-address", &false)
                    .unwrap();

                source
            }
            "ts-udpsrc" => {
                let source =
                    gst::ElementFactory::make("ts-udpsrc", Some(format!("source-{}", i).as_str()))
                        .unwrap();
                source
                    .set_property("port", &(40000u32 + (i as u32)))
                    .unwrap();
                source
                    .set_property("context", &format!("context-{}", (i as u32) % n_groups))
                    .unwrap();
                source.set_property("context-wait", &wait).unwrap();

                source
            }
            "ts-tcpclientsrc" => {
                let source = gst::ElementFactory::make(
                    "ts-tcpclientsrc",
                    Some(format!("source-{}", i).as_str()),
                )
                .unwrap();
                source.set_property("port", &(40000u32)).unwrap();
                source
                    .set_property("context", &format!("context-{}", (i as u32) % n_groups))
                    .unwrap();
                source.set_property("context-wait", &wait).unwrap();

                source
            }
            "tonegeneratesrc" => {
                let source = gst::ElementFactory::make(
                    "tonegeneratesrc",
                    Some(format!("source-{}", i).as_str()),
                )
                .unwrap();
                source
                    .set_property("samplesperbuffer", &((wait as i32) * 8000 / 1000))
                    .unwrap();

                sink.set_property("sync", &true).unwrap();

                source
            }
            "ts-tonesrc" => {
                let source =
                    gst::ElementFactory::make("ts-tonesrc", Some(format!("source-{}", i).as_str()))
                        .unwrap();
                source
                    .set_property("samples-per-buffer", &((wait as u32) * 8000 / 1000))
                    .unwrap();
                source
                    .set_property("context", &format!("context-{}", (i as u32) % n_groups))
                    .unwrap();
                source.set_property("context-wait", &wait).unwrap();

                source
            }
            _ => unimplemented!(),
        };

        pipeline.add_many(&[&source, &sink]).unwrap();
        source.link(&sink).unwrap();
    }

    let bus = pipeline.get_bus().unwrap();
    let l_clone = l.clone();
    bus.add_watch(move |_, msg| {
        use gst::MessageView;

        match msg.view() {
            MessageView::Eos(..) => l_clone.quit(),
            MessageView::Error(err) => {
                println!(
                    "Error from {:?}: {} ({:?})",
                    err.get_src().map(|s| s.get_path_string()),
                    err.get_error(),
                    err.get_debug()
                );
                l_clone.quit();
            }
            _ => (),
        };

        glib::Continue(true)
    })
    .expect("Failed to add bus watch");

    pipeline.set_state(gst::State::Playing).unwrap();

    println!("started");

    l.run();
}
<|endoftext|>


<commit_before>use std::option::Option;
use std::sync::Arc;

use rocksdb::DB;
use rocksdb::rocksdb::Snapshot;

use proto::metapb;
use proto::raft_serverpb::RaftTruncatedState;
use raftserver::{Result, other};
use super::keys;
use super::engine;

pub const RAFT_INIT_LOG_TERM: u64 = 5;
pub const RAFT_INIT_LOG_INDEX: u64 = 10;

pub struct RegionMeta {
    engine: Arc<DB>,

    pub region_id: u64,
    pub region: metapb::Region,
    pub last_index: u64,
    pub applied_index: u64,
    pub truncated_state: Option<RaftTruncatedState>,
}

impl RegionMeta {
    pub fn is_initialized(&self) -> bool {
        self.region.get_end_key().len() > 0
    }

    pub fn get_truncated_state(&self) -> Result<RaftTruncatedState> {
        match self.truncated_state {
            None => return Err(other("un-initialized truncated state")),
            Some(ref state) => return Ok(state.clone()),
        }
    }

    pub fn get_first_index(&self) -> Result<u64> {
        self.get_truncated_state().map(|state| state.get_index() + 1)
    }

    pub fn load_truncated_state(&self) -> Result<RaftTruncatedState> {
        let res = try!(engine::get_msg::<RaftTruncatedState>(&self.engine,
                                         &keys::raft_truncated_state_key(self.region_id)));

        let (mut state, found) = match res {
            Some(state) => (state, true),
            None => (RaftTruncatedState::new(), false),
        };

        if !found {
            if self.is_initialized() {
                state.set_index(RAFT_INIT_LOG_INDEX);
                state.set_term(RAFT_INIT_LOG_TERM);
            } else {
                state.set_index(0);
                state.set_term(0);
            }
        }

        Ok(state)
    }

    pub fn load_last_index(&self) -> Result<u64> {
        let n = try!(engine::get_u64(&self.engine, &keys::raft_last_index_key(self.region_id)));
        match n {
            Some(last_index) => return Ok(last_index),
            None => {
                // Log is empty, maybe we starts from scratch or have truncated all logs.
                let state = try!(self.get_truncated_state());
                return Ok(state.get_index());
            }
        }
    }

    pub fn load_applied_index(&self) -> Result<u64> {
        let mut applied_index: u64 = 0;
        if self.is_initialized() {
            applied_index = RAFT_INIT_LOG_INDEX;
        }

        let n = try!(engine::get_u64(&self.engine, &keys::raft_applied_index_key(self.region_id)));
        Ok(n.unwrap_or(applied_index))
    }

    pub fn snap_load_applied_index(&self, snap: &Snapshot) -> Result<u64> {
        let mut applied_index: u64 = 0;
        if self.is_initialized() {
            applied_index = RAFT_INIT_LOG_INDEX;
        }

        let n = try!(engine::snap_get_u64(snap, &keys::raft_applied_index_key(self.region_id)));
        Ok(n.unwrap_or(applied_index))
    }

    // For region snapshot, we care 3 range in database for this region.
    // [region id, region id + 1) -> saving raft entries, applied index, etc.
    // [region meta start, region meta end) -> saving region information.
    // [region data start, region data end) -> saving region data.
    fn region_key_ranges(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
        // The first range starts at MIN_KEY, but it contains unnecessary local data.
        // So we should skip this.
        let mut data_start_key = self.region.get_start_key();
        if data_start_key == keys::MIN_KEY {
            data_start_key = keys::LOCAL_MAX;
        }

        vec![(keys::region_id_prefix(self.region_id),
              keys::region_id_prefix(self.region_id + 1)),
             (keys::region_meta_prefix(self.region.get_start_key()),
              keys::region_meta_prefix(self.region.get_end_key())),
             (data_start_key.to_vec(), self.region.get_end_key().to_vec())]

    }

    pub fn snap_scan_region<F>(&self, snap: &Snapshot, f: &mut F) -> Result<()>
        where F: FnMut(&[u8], &[u8]) -> Result<bool>
    {
        let ranges = self.region_key_ranges();
        for r in ranges {
            try!(engine::snap_scan(snap, &r.0, &r.1, f));
        }

        Ok(())
    }
}
<commit_msg>raftserver: Address comment.<commit_after>use std::option::Option;
use std::sync::Arc;

use rocksdb::DB;
use rocksdb::rocksdb::Snapshot;

use proto::metapb;
use proto::raft_serverpb::RaftTruncatedState;
use raftserver::{Result, other};
use super::keys;
use super::engine;

pub const RAFT_INIT_LOG_TERM: u64 = 5;
pub const RAFT_INIT_LOG_INDEX: u64 = 10;

pub struct RegionMeta {
    engine: Arc<DB>,

    pub region_id: u64,
    pub region: metapb::Region,
    pub last_index: u64,
    pub applied_index: u64,
    pub truncated_state: Option<RaftTruncatedState>,
}

impl RegionMeta {
    pub fn is_initialized(&self) -> bool {
        self.region.get_end_key().len() > 0
    }

    pub fn get_truncated_state(&self) -> Result<RaftTruncatedState> {
        match self.truncated_state {
            None => return Err(other("un-initialized truncated state")),
            Some(ref state) => return Ok(state.clone()),
        }
    }

    pub fn get_first_index(&self) -> Result<u64> {
        self.get_truncated_state().map(|state| state.get_index() + 1)
    }

    pub fn load_truncated_state(&self) -> Result<RaftTruncatedState> {
        let res = try!(engine::get_msg::<RaftTruncatedState>(&self.engine,
                                         &keys::raft_truncated_state_key(self.region_id)));

        if let Some(state) = res {
            return Ok(state);
        }

        let mut state = RaftTruncatedState::new();

        if self.is_initialized() {
            state.set_index(RAFT_INIT_LOG_INDEX);
            state.set_term(RAFT_INIT_LOG_TERM);
        } else {
            state.set_index(0);
            state.set_term(0);
        }

        Ok(state)
    }

    pub fn load_last_index(&self) -> Result<u64> {
        let n = try!(engine::get_u64(&self.engine, &keys::raft_last_index_key(self.region_id)));
        match n {
            Some(last_index) => return Ok(last_index),
            None => {
                // Log is empty, maybe we starts from scratch or have truncated all logs.
                let state = try!(self.get_truncated_state());
                return Ok(state.get_index());
            }
        }
    }

    pub fn load_applied_index(&self) -> Result<u64> {
        let mut applied_index: u64 = 0;
        if self.is_initialized() {
            applied_index = RAFT_INIT_LOG_INDEX;
        }

        let n = try!(engine::get_u64(&self.engine, &keys::raft_applied_index_key(self.region_id)));
        Ok(n.unwrap_or(applied_index))
    }

    pub fn snap_load_applied_index(&self, snap: &Snapshot) -> Result<u64> {
        let mut applied_index: u64 = 0;
        if self.is_initialized() {
            applied_index = RAFT_INIT_LOG_INDEX;
        }

        let n = try!(engine::snap_get_u64(snap, &keys::raft_applied_index_key(self.region_id)));
        Ok(n.unwrap_or(applied_index))
    }

    // For region snapshot, we care 3 range in database for this region.
    // [region id, region id + 1) -> saving raft entries, applied index, etc.
    // [region meta start, region meta end) -> saving region information.
    // [region data start, region data end) -> saving region data.
    fn region_key_ranges(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
        // The first range starts at MIN_KEY, but it contains unnecessary local data.
        // So we should skip this.
        let mut data_start_key = self.region.get_start_key();
        if data_start_key == keys::MIN_KEY {
            data_start_key = keys::LOCAL_MAX;
        }

        vec![(keys::region_id_prefix(self.region_id),
              keys::region_id_prefix(self.region_id + 1)),
             (keys::region_meta_prefix(self.region.get_start_key()),
              keys::region_meta_prefix(self.region.get_end_key())),
             (data_start_key.to_vec(), self.region.get_end_key().to_vec())]

    }

    pub fn snap_scan_region<F>(&self, snap: &Snapshot, f: &mut F) -> Result<()>
        where F: FnMut(&[u8], &[u8]) -> Result<bool>
    {
        let ranges = self.region_key_ranges();
        for r in ranges {
            try!(engine::snap_scan(snap, &r.0, &r.1, f));
        }

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


<commit_before>fn main() {
    let s1 = String::from("hello");
    // s -> s1 -> heap data, no ownership transfer
    // borrowing
    let len = calculate_length(&s1);
    println!("The length of '{}' is {}.", s1, len);

    // change(&s1); // reference is immutable by default

    // ---
    let mut s2 = String::from("hello");
    let a_r = &mut s2;
    change(a_r);
    println!("{}", a_r);    // so &mut is Copy itself

    // ---
    // let other_r = &mut s2;   // can only have one ref at a time
                                // a_r are still here so cannot has
                                // anything else &mut to s2
    // for preventing data race at **compile time**
    // see http://rust-lang.github.io/book/second-edition/ch04-02-references-and-borrowing.html#mutable-references
    // ? this way is good for? any cost?

    // ---
    // also cannot combining & and &mut, for same reason
    // let immu_r = &s2;
    // only multiple immu & is ok

    // ---
    // compiler will prevent create dangle ref
    // let ref_to_nothing = dangle();
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

/*
fn change(s: &String) {
    s.push_str(", world");
}
*/

fn change(s: &mut String) {
    s.push_str(", world");
}

/*
fn ref_to_nothing() -> &String {
    let s = String::from("hello");

    &s
}   // s gone, compiler prevent return &s
    // just return a String s to transfer ownership
*/
<commit_msg>On mut reusing: add note.<commit_after>fn main() {
    let s1 = String::from("hello");
    // s -> s1 -> heap data, no ownership transfer
    // borrowing
    let len = calculate_length(&s1);
    println!("The length of '{}' is {}.", s1, len);

    // change(&s1); // reference is immutable by default

    // ---
    let mut s2 = String::from("hello");
    let a_r = &mut s2;
    change(a_r);
    println!("{}", a_r);    // so &mut is Copy itself
    // seems not: https://www.reddit.com/r/rust/comments/46qwjv/why_can_i_use_an_mut_reference_twice/

    // ---
    // let other_r = &mut s2;   // can only have one ref at a time
                                // a_r are still here so cannot has
                                // anything else &mut to s2
    // for preventing data race at **compile time**
    // see http://rust-lang.github.io/book/second-edition/ch04-02-references-and-borrowing.html#mutable-references
    // ? this way is good for? any cost?

    // ---
    // also cannot combining & and &mut, for same reason
    // let immu_r = &s2;
    // only multiple immu & is ok

    // ---
    // compiler will prevent create dangle ref
    // let ref_to_nothing = dangle();
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

/*
fn change(s: &String) {
    s.push_str(", world");
}
*/

fn change(s: &mut String) {
    s.push_str(", world");
}

/*
fn ref_to_nothing() -> &String {
    let s = String::from("hello");

    &s
}   // s gone, compiler prevent return &s
    // just return a String s to transfer ownership
*/
<|endoftext|>


<commit_before>use std::{cmp, fmt};

pub struct Clock {
}

impl Clock {
    pub fn new(hours: i32, minutes: i32) -> Self {
        unimplemented!(
            "Construct a new Clock from {} hours and {} minutes",
            hours,
            minutes
        );
    }

    pub fn add_minutes(self, minutes: i32) -> Self {
        unimplemented!("Add {} minutes to existing Clock time", minutes);
    }

    pub fn to_string(&self) -> String {
        unimplemented!("Return String representation of a Clock");
    }
}

impl fmt::Debug for Clock {
    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
        unimplemented!("Return debug representation of a Clock");
    }
}

impl cmp::PartialEq for Clock {
    fn eq(&self, _other: &Clock) -> bool {
        unimplemented!("Implement comparison between two Clocks");
    }
}
<commit_msg>clock: Replaced explicit Debug and PartialEq implementation with 'derive'<commit_after>#[derive(Debug, PartialEq)]
pub struct Clock {}

impl Clock {
    pub fn new(hours: i32, minutes: i32) -> Self {
        unimplemented!(
            "Construct a new Clock from {} hours and {} minutes",
            hours,
            minutes
        );
    }

    pub fn add_minutes(self, minutes: i32) -> Self {
        unimplemented!("Add {} minutes to existing Clock time", minutes);
    }

    pub fn to_string(&self) -> String {
        unimplemented!("Return String representation of a Clock");
    }
}
<|endoftext|>