<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program 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
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use super::objects::{DocType, EsId, Admin};
use chrono;
use regex;
use hyper;
use hyper::status::StatusCode;
use rs_es::error::EsError;
use rs_es;
use rs_es::EsResponse;
use serde;
use serde_json;
use rs_es::operations::search::ScanResult;

use super::objects::{AliasOperations, AliasOperation, AliasParameter};
use rs_es::units::Duration;
use std::collections::BTreeMap;

pub type AdminFromInsee = BTreeMap<String, Admin>;

// Rubber is an wrapper around elasticsearch API
pub struct Rubber {
    es_client: rs_es::Client,
    // some operation are not implemented in rs_es, we need to use a raw http client
    http_client: hyper::client::Client,
}

/// return the index associated to the given type and dataset
/// this will be an alias over another real index
fn get_main_index(doc_type: &str, dataset: &str) -> String {
    format!("munin_{}_{}", doc_type, dataset)
}

impl Rubber {
    // build a rubber with a connection string (http://host:port/)
    pub fn new(cnx: &str) -> Rubber {
        let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
        let cap = re.captures(cnx).unwrap();
        let host = cap.name("host").unwrap();
        let port = cap.name("port").unwrap().parse::<u32>().unwrap();
        info!("elastic search host {:?} port {:?}", host, port);

        Rubber {
            es_client: rs_es::Client::new(&host, port),
            http_client: hyper::client::Client::new(),
        }
    }

    pub fn get(&self, path: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a get on {}", path);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
                              .get(&url)
                              .send());
        rs_es::do_req(result)
    }
    fn put(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a put on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
                              .put(&url)
                              .body(body)
                              .send());
        rs_es::do_req(result)
    }
    fn post(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a post on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
                              .post(&url)
                              .body(body)
                              .send());
        rs_es::do_req(result)
    }

    pub fn make_index(&self, doc_type: &str, dataset: &str) -> Result<String, String> {
        let current_time = chrono::UTC::now().format("%Y%m%d_%H%M%S_%f");
        let index_name = format!("munin_{}_{}_{}", doc_type, dataset, current_time);
        info!("creating index {}", index_name);
        self.create_index(&index_name.to_string()).map(|_| index_name)
    }

    fn create_index(&self, name: &String) -> Result<(), String> {
        debug!("creating index");
        // Note: in rs_es it can be done with MappingOperation but for the moment I think
        // storing the mapping in json is more convenient
        let analysis = include_str!("../../../json/settings.json");
        self.put(name, &analysis)
            .map_err(|e| {
                info!("Error while creating new index {}", name);
                e.to_string()
            })
            .and_then(|res| {
                if res.status == StatusCode::Ok {
                    Ok(())
                } else {
                    Err(format!("cannot create index: {:?}", res))
                }
            })
    }

    fn get_last_index(&self, doc_type: &str, dataset: &str) -> Result<Vec<String>, String> {
        debug!("get last index: {base_index}/_aliases",
               base_index = get_main_index(doc_type, dataset));
        self.get(&format!("{base_index}/_aliases",
                          base_index = get_main_index(doc_type, dataset)))
            .map_err(|e| e.to_string())
            .and_then(|res| {
                match res.status {
                    StatusCode::Ok => {
                        let value: serde_json::Value = try!(res.read_response()
                                                               .map_err(|e| e.to_string()));
                        Ok(value.as_object()
                                .and_then(|aliases| Some(aliases.keys().cloned().collect()))
                                .unwrap_or_else(|| {
                                    info!("no previous index to delete for type {} and dataset {}",
                                          doc_type,
                                          dataset);
                                    vec![]
                                }))
                    }
                    StatusCode::NotFound => {
                        info!("impossible to find alias {}, no last index to remove",
                              get_main_index(doc_type, dataset));
                        Ok(vec![])
                    }
                    _ => Err(format!("invalid elasticsearch response: {:?}", res)),
                }

            })
    }

    /// publish the index as the new index for this doc_type and this dataset
    /// move the index alias of the doc_type and the dataset to point to this indexes
    /// and remove the old index
    pub fn publish_index(&mut self,
                         doc_type: &str,
                         dataset: &str,
                         index: String)
                         -> Result<(), String> {
        debug!("publishing index");
        let last_indexes = try!(self.get_last_index(doc_type, dataset));
        let main_index = get_main_index(doc_type, dataset);
        try!(self.alias(&main_index, &vec![index.clone()], &last_indexes));
        try!(self.alias("munin", &vec![main_index.to_string()], &vec![]));
        for i in last_indexes {
            try!(self.delete_index(&i));
        }
        Ok(())
    }

    pub fn is_existing_index(&self, name: &String) -> Result<bool, String> {
        self.get(&name)
            .map_err(|e| e.to_string())
            .map(|res| res.status == StatusCode::Ok)
    }

    /// add a list of new indexes to the alias
    /// remove a list of indexes from the alias
    fn alias(&self, alias: &str, add: &Vec<String>, remove: &Vec<String>) -> Result<(), String> {
        info!("for {}, adding alias {:?}, removing {:?}",
              alias,
              add,
              remove);
        let add_operations = add.iter().map(|x| {
            AliasOperation {
                remove: None,
                add: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let remove_operations = remove.iter().map(|x| {
            AliasOperation {
                add: None,
                remove: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let operations = AliasOperations {
            actions: add_operations.chain(remove_operations).collect(),
        };
        let json = serde_json::to_string(&operations).unwrap();
        self.post("_aliases", &json)
            .map_err(|e| e.to_string())
            .and_then(|res| {
                if res.status == StatusCode::Ok {
                    Ok(())
                } else {
                    error!("failed to change aliases for {}, es response: {:?}",
                           alias,
                           res);
                    Err(format!("failed to post aliases for {}: {:?}", alias, res).to_string())
                }
            })
    }

    pub fn delete_index(&mut self, index: &String) -> Result<(), String> {
        debug!("deleting index {}", &index);
        let res = self.es_client
                      .delete_index(&index)
                      .map(|res| res.acknowledged)
                      .unwrap_or(false);
        if !res {
            Err(format!("Error deleting index {}", &index).into())
        } else {
            Ok(())
        }
    }

    pub fn bulk_index<T, I>(&mut self,
                            index: &String,
                            iter: I)
                            -> Result<usize, rs_es::error::EsError>
        where T: serde::Serialize + DocType + EsId,
              I: Iterator<Item = T>
    {
        use rs_es::operations::bulk::Action;
        let mut nb = 0;
        let chunk_size = 1000;
        //fold is used for creating the action and optionally set the id of the object
        let mut actions = iter.map(|v| v.es_id()
                                        .into_iter()
                                        .fold(Action::index(v), |action, id| action.with_id(id)));
        loop {
            let chunk = actions.by_ref().take(chunk_size).collect::<Vec<_>>();
            nb += chunk.len();
            try!(self.es_client
                     .bulk(&chunk)
                     .with_index(&index)
                     .with_doc_type(T::doc_type())
                     .send());

            if chunk.len() < chunk_size {
                break;
            }
        }

        Ok(nb)
    }

    /// add all the element of 'iter' into elasticsearch
    ///
    /// To have zero downtime:
    /// first all the elements are added in a temporary index and when all has been indexed
    /// the index is published and the old index is removed
    pub fn index<T, I>(&mut self, doc_type: &str, dataset: &str, iter: I) -> Result<usize, String>
        where T: serde::Serialize + DocType + EsId,
              I: Iterator<Item = T>
    {
        // TODO better error handling
        let index = try!(self.make_index(doc_type, dataset));
        let nb_elements = try!(self.bulk_index(&index, iter).map_err(|e| e.to_string()));
        try!(self.publish_index(doc_type, dataset, index));
        Ok(nb_elements)
    }

    pub fn get_admins(&mut self, dataset: &str) -> Result<AdminFromInsee, rs_es::error::EsError> {
    	let mut result: AdminFromInsee = BTreeMap::new();
    	let index = get_main_index("admin", dataset);
    	let mut scan: ScanResult<Admin> = try!(self.es_client
    		.search_query()
    		.with_indexes(&[&index])
    		.with_size(1000)
    		.with_types(&[&"admin"])
    		.scan(&Duration::minutes(1)));
    	loop {
    		let page = try!(scan.scroll(&mut self.es_client, &Duration::minutes(1)));
    		if page.hits.hits.len() == 0 {
    			break;
    		}
    		for ad in page.hits.hits.into_iter().filter_map(|hit| hit.source) {
    			result.insert(ad.id.to_string(), *ad);
    		}
    	}
    	try!(scan.close(&mut self.es_client));
    	Ok(result)
    }
}

#[test]
pub fn test_valid_url() {
    Rubber::new("http://localhost:9200");
    Rubber::new("localhost:9200");
}

#[test]
#[should_panic]
pub fn test_invalid_url() {
    Rubber::new("http://bob");
}

#[test]
#[should_panic]
pub fn test_invalid_url_no_port() {
    Rubber::new("localhost");
}
<commit_msg>fmt passed<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program 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
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use super::objects::{DocType, EsId, Admin};
use chrono;
use regex;
use hyper;
use hyper::status::StatusCode;
use rs_es::error::EsError;
use rs_es;
use rs_es::EsResponse;
use serde;
use serde_json;
use rs_es::operations::search::ScanResult;

use super::objects::{AliasOperations, AliasOperation, AliasParameter};
use rs_es::units::Duration;
use std::collections::BTreeMap;

pub type AdminFromInsee = BTreeMap<String, Admin>;

// Rubber is an wrapper around elasticsearch API
pub struct Rubber {
    es_client: rs_es::Client,
    // some operation are not implemented in rs_es, we need to use a raw http client
    http_client: hyper::client::Client,
}

/// return the index associated to the given type and dataset
/// this will be an alias over another real index
fn get_main_index(doc_type: &str, dataset: &str) -> String {
    format!("munin_{}_{}", doc_type, dataset)
}

impl Rubber {
    // build a rubber with a connection string (http://host:port/)
    pub fn new(cnx: &str) -> Rubber {
        let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
        let cap = re.captures(cnx).unwrap();
        let host = cap.name("host").unwrap();
        let port = cap.name("port").unwrap().parse::<u32>().unwrap();
        info!("elastic search host {:?} port {:?}", host, port);

        Rubber {
            es_client: rs_es::Client::new(&host, port),
            http_client: hyper::client::Client::new(),
        }
    }

    pub fn get(&self, path: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a get on {}", path);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
                              .get(&url)
                              .send());
        rs_es::do_req(result)
    }
    fn put(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a put on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
                              .put(&url)
                              .body(body)
                              .send());
        rs_es::do_req(result)
    }
    fn post(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a post on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
                              .post(&url)
                              .body(body)
                              .send());
        rs_es::do_req(result)
    }

    pub fn make_index(&self, doc_type: &str, dataset: &str) -> Result<String, String> {
        let current_time = chrono::UTC::now().format("%Y%m%d_%H%M%S_%f");
        let index_name = format!("munin_{}_{}_{}", doc_type, dataset, current_time);
        info!("creating index {}", index_name);
        self.create_index(&index_name.to_string()).map(|_| index_name)
    }

    fn create_index(&self, name: &String) -> Result<(), String> {
        debug!("creating index");
        // Note: in rs_es it can be done with MappingOperation but for the moment I think
        // storing the mapping in json is more convenient
        let analysis = include_str!("../../../json/settings.json");
        self.put(name, &analysis)
            .map_err(|e| {
                info!("Error while creating new index {}", name);
                e.to_string()
            })
            .and_then(|res| {
                if res.status == StatusCode::Ok {
                    Ok(())
                } else {
                    Err(format!("cannot create index: {:?}", res))
                }
            })
    }

    fn get_last_index(&self, doc_type: &str, dataset: &str) -> Result<Vec<String>, String> {
        debug!("get last index: {base_index}/_aliases",
               base_index = get_main_index(doc_type, dataset));
        self.get(&format!("{base_index}/_aliases",
                          base_index = get_main_index(doc_type, dataset)))
            .map_err(|e| e.to_string())
            .and_then(|res| {
                match res.status {
                    StatusCode::Ok => {
                        let value: serde_json::Value = try!(res.read_response()
                                                               .map_err(|e| e.to_string()));
                        Ok(value.as_object()
                                .and_then(|aliases| Some(aliases.keys().cloned().collect()))
                                .unwrap_or_else(|| {
                                    info!("no previous index to delete for type {} and dataset {}",
                                          doc_type,
                                          dataset);
                                    vec![]
                                }))
                    }
                    StatusCode::NotFound => {
                        info!("impossible to find alias {}, no last index to remove",
                              get_main_index(doc_type, dataset));
                        Ok(vec![])
                    }
                    _ => Err(format!("invalid elasticsearch response: {:?}", res)),
                }

            })
    }

    /// publish the index as the new index for this doc_type and this dataset
    /// move the index alias of the doc_type and the dataset to point to this indexes
    /// and remove the old index
    pub fn publish_index(&mut self,
                         doc_type: &str,
                         dataset: &str,
                         index: String)
                         -> Result<(), String> {
        debug!("publishing index");
        let last_indexes = try!(self.get_last_index(doc_type, dataset));
        let main_index = get_main_index(doc_type, dataset);
        try!(self.alias(&main_index, &vec![index.clone()], &last_indexes));
        try!(self.alias("munin", &vec![main_index.to_string()], &vec![]));
        for i in last_indexes {
            try!(self.delete_index(&i));
        }
        Ok(())
    }

    pub fn is_existing_index(&self, name: &String) -> Result<bool, String> {
        self.get(&name)
            .map_err(|e| e.to_string())
            .map(|res| res.status == StatusCode::Ok)
    }

    /// add a list of new indexes to the alias
    /// remove a list of indexes from the alias
    fn alias(&self, alias: &str, add: &Vec<String>, remove: &Vec<String>) -> Result<(), String> {
        info!("for {}, adding alias {:?}, removing {:?}",
              alias,
              add,
              remove);
        let add_operations = add.iter().map(|x| {
            AliasOperation {
                remove: None,
                add: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let remove_operations = remove.iter().map(|x| {
            AliasOperation {
                add: None,
                remove: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let operations = AliasOperations {
            actions: add_operations.chain(remove_operations).collect(),
        };
        let json = serde_json::to_string(&operations).unwrap();
        self.post("_aliases", &json)
            .map_err(|e| e.to_string())
            .and_then(|res| {
                if res.status == StatusCode::Ok {
                    Ok(())
                } else {
                    error!("failed to change aliases for {}, es response: {:?}",
                           alias,
                           res);
                    Err(format!("failed to post aliases for {}: {:?}", alias, res).to_string())
                }
            })
    }

    pub fn delete_index(&mut self, index: &String) -> Result<(), String> {
        debug!("deleting index {}", &index);
        let res = self.es_client
                      .delete_index(&index)
                      .map(|res| res.acknowledged)
                      .unwrap_or(false);
        if !res {
            Err(format!("Error deleting index {}", &index).into())
        } else {
            Ok(())
        }
    }

    pub fn bulk_index<T, I>(&mut self,
                            index: &String,
                            iter: I)
                            -> Result<usize, rs_es::error::EsError>
        where T: serde::Serialize + DocType + EsId,
              I: Iterator<Item = T>
    {
        use rs_es::operations::bulk::Action;
        let mut nb = 0;
        let chunk_size = 1000;
        //fold is used for creating the action and optionally set the id of the object
        let mut actions = iter.map(|v| v.es_id()
                                        .into_iter()
                                        .fold(Action::index(v), |action, id| action.with_id(id)));
        loop {
            let chunk = actions.by_ref().take(chunk_size).collect::<Vec<_>>();
            nb += chunk.len();
            try!(self.es_client
                     .bulk(&chunk)
                     .with_index(&index)
                     .with_doc_type(T::doc_type())
                     .send());

            if chunk.len() < chunk_size {
                break;
            }
        }

        Ok(nb)
    }

    /// add all the element of 'iter' into elasticsearch
    ///
    /// To have zero downtime:
    /// first all the elements are added in a temporary index and when all has been indexed
    /// the index is published and the old index is removed
    pub fn index<T, I>(&mut self, doc_type: &str, dataset: &str, iter: I) -> Result<usize, String>
        where T: serde::Serialize + DocType + EsId,
              I: Iterator<Item = T>
    {
        // TODO better error handling
        let index = try!(self.make_index(doc_type, dataset));
        let nb_elements = try!(self.bulk_index(&index, iter).map_err(|e| e.to_string()));
        try!(self.publish_index(doc_type, dataset, index));
        Ok(nb_elements)
    }

    pub fn get_admins(&mut self, dataset: &str) -> Result<AdminFromInsee, rs_es::error::EsError> {
        let mut result: AdminFromInsee = BTreeMap::new();
        let index = get_main_index("admin", dataset);
        let mut scan: ScanResult<Admin> = try!(self.es_client
            .search_query()
            .with_indexes(&[&index])
            .with_size(1000)
            .with_types(&[&"admin"])
            .scan(&Duration::minutes(1)));
        loop {
            let page = try!(scan.scroll(&mut self.es_client, &Duration::minutes(1)));
            if page.hits.hits.len() == 0 {
                break;
            }
            for ad in page.hits.hits.into_iter().filter_map(|hit| hit.source) {
                result.insert(ad.id.to_string(), *ad);
            }
        }
        try!(scan.close(&mut self.es_client));
        Ok(result)
    }
}

#[test]
pub fn test_valid_url() {
    Rubber::new("http://localhost:9200");
    Rubber::new("localhost:9200");
}

#[test]
#[should_panic]
pub fn test_invalid_url() {
    Rubber::new("http://bob");
}

#[test]
#[should_panic]
pub fn test_invalid_url_no_port() {
    Rubber::new("localhost");
}
<|endoftext|>


<commit_before>extern crate fall_test;
extern crate fall_tree;

use fall_test::{json, match_ast};
use fall_tree::dump_file_ws;

fn ast(code: &str) -> String {
    dump_file_ws(&json::parse(code.to_owned()))
}

#[test]
fn obj() {
    match_ast(&ast(r##"{ "foo": [1, 2, 3] }"##), r#"
FILE
  OBJECT
    LBRACE "{"
    WHITESPACE " "
    FIELD
      STRING "\"foo\""
      COLON ":"
      WHITESPACE " "
      ARRAY
        LBRACK "["
        PRIMITIVE
          NUMBER "1"
        COMMA ","
        WHITESPACE " "
        PRIMITIVE
          NUMBER "2"
        COMMA ","
        WHITESPACE " "
        PRIMITIVE
          NUMBER "3"
        RBRACK "]"
    WHITESPACE " "
    RBRACE "}"
"#);
}

<commit_msg>More thorough test<commit_after>extern crate fall_test;
extern crate fall_tree;

use fall_test::{json, match_ast};
use fall_tree::dump_file;

fn ast(code: &str) -> String {
    dump_file(&json::parse(code.to_owned()))
}

#[test]
fn obj() {
    match_ast(&ast(r##"{ "foo": [1, 2, 3] }"##), r#"
FILE
  OBJECT
    LBRACE "{"
    FIELD
      STRING "\"foo\""
      COLON ":"
      ARRAY
        LBRACK "["
        PRIMITIVE
          NUMBER "1"
        COMMA ","
        PRIMITIVE
          NUMBER "2"
        COMMA ","
        PRIMITIVE
          NUMBER "3"
        RBRACK "]"
    RBRACE "}"
"#);
}

#[test]
fn example() {
    match_ast(&ast(r#"
{"widget": {
    "debug": "on",
    "window": {
        "title": "Sample Konfabulator Widget",
        "name": "main_window",
        "width": 500,
        "height": 500
    },
    "image": {
        "src": "Images/Sun.png",
        "name": "sun1",
        "hOffset": 250,
        "vOffset": 250,
        "alignment": "center"
    },
    "text": {
        "data": "Click Here",
        "size": 36,
        "style": "bold",
        "name": "text1",
        "hOffset": 250,
        "vOffset": 100,
        "alignment": "center",
        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
    }
}}"#), r#"
FILE
  OBJECT
    LBRACE "{"
    FIELD
      STRING "\"widget\""
      COLON ":"
      OBJECT
        LBRACE "{"
        FIELD
          STRING "\"debug\""
          COLON ":"
          PRIMITIVE
            STRING "\"on\""
        COMMA ","
        FIELD
          STRING "\"window\""
          COLON ":"
          OBJECT
            LBRACE "{"
            FIELD
              STRING "\"title\""
              COLON ":"
              PRIMITIVE
                STRING "\"Sample Konfabulator Widget\""
            COMMA ","
            FIELD
              STRING "\"name\""
              COLON ":"
              PRIMITIVE
                STRING "\"main_window\""
            COMMA ","
            FIELD
              STRING "\"width\""
              COLON ":"
              PRIMITIVE
                NUMBER "500"
            COMMA ","
            FIELD
              STRING "\"height\""
              COLON ":"
              PRIMITIVE
                NUMBER "500"
            RBRACE "}"
        COMMA ","
        FIELD
          STRING "\"image\""
          COLON ":"
          OBJECT
            LBRACE "{"
            FIELD
              STRING "\"src\""
              COLON ":"
              PRIMITIVE
                STRING "\"Images/Sun.png\""
            COMMA ","
            FIELD
              STRING "\"name\""
              COLON ":"
              PRIMITIVE
                STRING "\"sun1\""
            COMMA ","
            FIELD
              STRING "\"hOffset\""
              COLON ":"
              PRIMITIVE
                NUMBER "250"
            COMMA ","
            FIELD
              STRING "\"vOffset\""
              COLON ":"
              PRIMITIVE
                NUMBER "250"
            COMMA ","
            FIELD
              STRING "\"alignment\""
              COLON ":"
              PRIMITIVE
                STRING "\"center\""
            RBRACE "}"
        COMMA ","
        FIELD
          STRING "\"text\""
          COLON ":"
          OBJECT
            LBRACE "{"
            FIELD
              STRING "\"data\""
              COLON ":"
              PRIMITIVE
                STRING "\"Click Here\""
            COMMA ","
            FIELD
              STRING "\"size\""
              COLON ":"
              PRIMITIVE
                NUMBER "36"
            COMMA ","
            FIELD
              STRING "\"style\""
              COLON ":"
              PRIMITIVE
                STRING "\"bold\""
            COMMA ","
            FIELD
              STRING "\"name\""
              COLON ":"
              PRIMITIVE
                STRING "\"text1\""
            COMMA ","
            FIELD
              STRING "\"hOffset\""
              COLON ":"
              PRIMITIVE
                NUMBER "250"
            COMMA ","
            FIELD
              STRING "\"vOffset\""
              COLON ":"
              PRIMITIVE
                NUMBER "100"
            COMMA ","
            FIELD
              STRING "\"alignment\""
              COLON ":"
              PRIMITIVE
                STRING "\"center\""
            COMMA ","
            FIELD
              STRING "\"onMouseUp\""
              COLON ":"
              PRIMITIVE
                STRING "\"sun1.opacity = (sun1.opacity / 100) * 90;\""
            RBRACE "}"
        RBRACE "}"
    RBRACE "}"
"#)
}

<|endoftext|>


<commit_before><commit_msg>Rollup merge of #59156 - davidtwco:issue-55809, r=nikomatsakis<commit_after><|endoftext|>


<commit_before>//! An asynchronous, pipelined, PostgreSQL client.
//!
//! # Example
//!
//! ```no_run
//! use tokio_postgres::{NoTls, Error};
//!
//! # #[cfg(not(feature = "runtime"))] fn main() {}
//! # #[cfg(feature = "runtime")]
//! #[tokio::main] // By default, tokio_postgres uses the tokio crate as its runtime.
//! async fn main() -> Result<(), Error> {
//!     // Connect to the database.
//!     let (client, connection) =
//!         tokio_postgres::connect("host=localhost user=postgres", NoTls).await?;
//!
//!     // The connection object performs the actual communication with the database,
//!     // so spawn it off to run on its own.
//!     tokio::spawn(async move {
//!         if let Err(e) = connection.await {
//!             eprintln!("connection error: {}", e);
//!         }
//!     });
//!
//!     // Now we can execute a simple statement that just returns its parameter.
//!     let rows = client
//!         .query("SELECT $1::TEXT", &[&"hello world"])
//!         .await?;
//!
//!     // And then check that we got back the same string we sent over.
//!     let value: &str = rows[0].get(0);
//!     assert_eq!(value, "hello world");
//!
//!     Ok(())
//! }
//! ```
//!
//! # Behavior
//!
//! Calling a method like `Client::query` on its own does nothing. The associated request is not sent to the database
//! until the future returned by the method is first polled. Requests are executed in the order that they are first
//! polled, not in the order that their futures are created.
//!
//! # Pipelining
//!
//! The client supports *pipelined* requests. Pipelining can improve performance in use cases in which multiple,
//! independent queries need to be executed. In a traditional workflow, each query is sent to the server after the
//! previous query completes. In contrast, pipelining allows the client to send all of the queries to the server up
//! front, minimizing time spent by one side waiting for the other to finish sending data:
//!
//! ```not_rust
//!             Sequential                              Pipelined
//! | Client         | Server          |    | Client         | Server          |
//! |----------------|-----------------|    |----------------|-----------------|
//! | send query 1   |                 |    | send query 1   |                 |
//! |                | process query 1 |    | send query 2   | process query 1 |
//! | receive rows 1 |                 |    | send query 3   | process query 2 |
//! | send query 2   |                 |    | receive rows 1 | process query 3 |
//! |                | process query 2 |    | receive rows 2 |                 |
//! | receive rows 2 |                 |    | receive rows 3 |                 |
//! | send query 3   |                 |
//! |                | process query 3 |
//! | receive rows 3 |                 |
//! ```
//!
//! In both cases, the PostgreSQL server is executing the queries sequentially - pipelining just allows both sides of
//! the connection to work concurrently when possible.
//!
//! Pipelining happens automatically when futures are polled concurrently (for example, by using the futures `join`
//! combinator):
//!
//! ```rust
//! use futures::future;
//! use std::future::Future;
//! use tokio_postgres::{Client, Error, Statement};
//!
//! async fn pipelined_prepare(
//!     client: &Client,
//! ) -> Result<(Statement, Statement), Error>
//! {
//!     future::try_join(
//!         client.prepare("SELECT * FROM foo"),
//!         client.prepare("INSERT INTO bar (id, name) VALUES ($1, $2)")
//!     ).await
//! }
//! ```
//!
//! # Runtime
//!
//! The client works with arbitrary `AsyncRead + AsyncWrite` streams. Convenience APIs are provided to handle the
//! connection process, but these are gated by the `runtime` Cargo feature, which is enabled by default. If disabled,
//! all dependence on the tokio runtime is removed.
//!
//! # SSL/TLS support
//!
//! TLS support is implemented via external libraries. `Client::connect` and `Config::connect` take a TLS implementation
//! as an argument. The `NoTls` type in this crate can be used when TLS is not required. Otherwise, the
//! `postgres-openssl` and `postgres-native-tls` crates provide implementations backed by the `openssl` and `native-tls`
//! crates, respectively.
//!
//! # Features
//!
//! The following features can be enabled from `Cargo.toml`:
//!
//! | Feature | Description | Extra dependencies | Default |
//! | ------- | ----------- | ------------------ | ------- |
//! | `runtime` | Enable convenience API for the connection process based on the `tokio` crate. | [tokio](https://crates.io/crates/tokio) 1.0 with the features `net` and `time` | yes |
//! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no |
//! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no |
//! | `with-eui48-0_4` | Enable support for the 0.4 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no |
//! | `with-eui48-1` | Enable support for the 1.0 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 1.0 | no |
//! | `with-geo-types-0_6` | Enable support for the 0.6 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.6.0) 0.6 | no |
//! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no |
//! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no |
//! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no |
//! | `with-uuid-1` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 1.0 | no |
//! | `with-time-0_2` | Enable support for the 0.2 version of the `time` crate. | [time](https://crates.io/crates/time/0.2.0) 0.2 | no |
//! | `with-time-0_3` | Enable support for the 0.3 version of the `time` crate. | [time](https://crates.io/crates/time/0.3.0) 0.3 | no |
#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.7")]
#![warn(rust_2018_idioms, clippy::all, missing_docs)]

pub use crate::cancel_token::CancelToken;
pub use crate::client::Client;
pub use crate::config::Config;
pub use crate::connection::Connection;
pub use crate::copy_in::CopyInSink;
pub use crate::copy_out::CopyOutStream;
use crate::error::DbError;
pub use crate::error::Error;
pub use crate::generic_client::GenericClient;
pub use crate::portal::Portal;
pub use crate::query::RowStream;
pub use crate::row::{Row, SimpleQueryRow};
pub use crate::simple_query::SimpleQueryStream;
#[cfg(feature = "runtime")]
pub use crate::socket::Socket;
pub use crate::statement::{Column, Statement};
#[cfg(feature = "runtime")]
use crate::tls::MakeTlsConnect;
pub use crate::tls::NoTls;
pub use crate::to_statement::ToStatement;
pub use crate::transaction::Transaction;
pub use crate::transaction_builder::{IsolationLevel, TransactionBuilder};
use crate::types::ToSql;

pub mod binary_copy;
mod bind;
#[cfg(feature = "runtime")]
mod cancel_query;
mod cancel_query_raw;
mod cancel_token;
mod client;
mod codec;
pub mod config;
#[cfg(feature = "runtime")]
mod connect;
mod connect_raw;
#[cfg(feature = "runtime")]
mod connect_socket;
mod connect_tls;
mod connection;
mod copy_in;
mod copy_out;
pub mod error;
mod generic_client;
mod maybe_tls_stream;
mod portal;
mod prepare;
mod query;
pub mod row;
mod simple_query;
#[cfg(feature = "runtime")]
mod socket;
mod statement;
pub mod tls;
mod to_statement;
mod transaction;
mod transaction_builder;
pub mod types;

/// A convenience function which parses a connection string and connects to the database.
///
/// See the documentation for [`Config`] for details on the connection string format.
///
/// Requires the `runtime` Cargo feature (enabled by default).
///
/// [`Config`]: config/struct.Config.html
#[cfg(feature = "runtime")]
pub async fn connect<T>(
    config: &str,
    tls: T,
) -> Result<(Client, Connection<Socket, T::Stream>), Error>
where
    T: MakeTlsConnect<Socket>,
{
    let config = config.parse::<Config>()?;
    config.connect(tls).await
}

/// An asynchronous notification.
#[derive(Clone, Debug)]
pub struct Notification {
    process_id: i32,
    channel: String,
    payload: String,
}

impl Notification {
    /// The process ID of the notifying backend process.
    pub fn process_id(&self) -> i32 {
        self.process_id
    }

    /// The name of the channel that the notify has been raised on.
    pub fn channel(&self) -> &str {
        &self.channel
    }

    /// The "payload" string passed from the notifying process.
    pub fn payload(&self) -> &str {
        &self.payload
    }
}

/// An asynchronous message from the server.
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum AsyncMessage {
    /// A notice.
    ///
    /// Notices use the same format as errors, but aren't "errors" per-se.
    Notice(DbError),
    /// A notification.
    ///
    /// Connections can subscribe to notifications with the `LISTEN` command.
    Notification(Notification),
}

/// Message returned by the `SimpleQuery` stream.
#[non_exhaustive]
pub enum SimpleQueryMessage {
    /// A row of data.
    Row(SimpleQueryRow),
    /// A statement in the query has completed.
    ///
    /// The number of rows modified or selected is returned.
    CommandComplete(u64),
}

fn slice_iter<'a>(
    s: &'a [&'a (dyn ToSql + Sync)],
) -> impl ExactSizeIterator<Item = &'a dyn ToSql> + 'a {
    s.iter().map(|s| *s as _)
}
<commit_msg>Add `array-impls` feature in docs table<commit_after>//! An asynchronous, pipelined, PostgreSQL client.
//!
//! # Example
//!
//! ```no_run
//! use tokio_postgres::{NoTls, Error};
//!
//! # #[cfg(not(feature = "runtime"))] fn main() {}
//! # #[cfg(feature = "runtime")]
//! #[tokio::main] // By default, tokio_postgres uses the tokio crate as its runtime.
//! async fn main() -> Result<(), Error> {
//!     // Connect to the database.
//!     let (client, connection) =
//!         tokio_postgres::connect("host=localhost user=postgres", NoTls).await?;
//!
//!     // The connection object performs the actual communication with the database,
//!     // so spawn it off to run on its own.
//!     tokio::spawn(async move {
//!         if let Err(e) = connection.await {
//!             eprintln!("connection error: {}", e);
//!         }
//!     });
//!
//!     // Now we can execute a simple statement that just returns its parameter.
//!     let rows = client
//!         .query("SELECT $1::TEXT", &[&"hello world"])
//!         .await?;
//!
//!     // And then check that we got back the same string we sent over.
//!     let value: &str = rows[0].get(0);
//!     assert_eq!(value, "hello world");
//!
//!     Ok(())
//! }
//! ```
//!
//! # Behavior
//!
//! Calling a method like `Client::query` on its own does nothing. The associated request is not sent to the database
//! until the future returned by the method is first polled. Requests are executed in the order that they are first
//! polled, not in the order that their futures are created.
//!
//! # Pipelining
//!
//! The client supports *pipelined* requests. Pipelining can improve performance in use cases in which multiple,
//! independent queries need to be executed. In a traditional workflow, each query is sent to the server after the
//! previous query completes. In contrast, pipelining allows the client to send all of the queries to the server up
//! front, minimizing time spent by one side waiting for the other to finish sending data:
//!
//! ```not_rust
//!             Sequential                              Pipelined
//! | Client         | Server          |    | Client         | Server          |
//! |----------------|-----------------|    |----------------|-----------------|
//! | send query 1   |                 |    | send query 1   |                 |
//! |                | process query 1 |    | send query 2   | process query 1 |
//! | receive rows 1 |                 |    | send query 3   | process query 2 |
//! | send query 2   |                 |    | receive rows 1 | process query 3 |
//! |                | process query 2 |    | receive rows 2 |                 |
//! | receive rows 2 |                 |    | receive rows 3 |                 |
//! | send query 3   |                 |
//! |                | process query 3 |
//! | receive rows 3 |                 |
//! ```
//!
//! In both cases, the PostgreSQL server is executing the queries sequentially - pipelining just allows both sides of
//! the connection to work concurrently when possible.
//!
//! Pipelining happens automatically when futures are polled concurrently (for example, by using the futures `join`
//! combinator):
//!
//! ```rust
//! use futures::future;
//! use std::future::Future;
//! use tokio_postgres::{Client, Error, Statement};
//!
//! async fn pipelined_prepare(
//!     client: &Client,
//! ) -> Result<(Statement, Statement), Error>
//! {
//!     future::try_join(
//!         client.prepare("SELECT * FROM foo"),
//!         client.prepare("INSERT INTO bar (id, name) VALUES ($1, $2)")
//!     ).await
//! }
//! ```
//!
//! # Runtime
//!
//! The client works with arbitrary `AsyncRead + AsyncWrite` streams. Convenience APIs are provided to handle the
//! connection process, but these are gated by the `runtime` Cargo feature, which is enabled by default. If disabled,
//! all dependence on the tokio runtime is removed.
//!
//! # SSL/TLS support
//!
//! TLS support is implemented via external libraries. `Client::connect` and `Config::connect` take a TLS implementation
//! as an argument. The `NoTls` type in this crate can be used when TLS is not required. Otherwise, the
//! `postgres-openssl` and `postgres-native-tls` crates provide implementations backed by the `openssl` and `native-tls`
//! crates, respectively.
//!
//! # Features
//!
//! The following features can be enabled from `Cargo.toml`:
//!
//! | Feature | Description | Extra dependencies | Default |
//! | ------- | ----------- | ------------------ | ------- |
//! | `runtime` | Enable convenience API for the connection process based on the `tokio` crate. | [tokio](https://crates.io/crates/tokio) 1.0 with the features `net` and `time` | yes |
//! | `array-impls` | Enables `ToSql` and `FromSql` trait impls for arrays | - | no |
//! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no |
//! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no |
//! | `with-eui48-0_4` | Enable support for the 0.4 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no |
//! | `with-eui48-1` | Enable support for the 1.0 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 1.0 | no |
//! | `with-geo-types-0_6` | Enable support for the 0.6 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.6.0) 0.6 | no |
//! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no |
//! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no |
//! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no |
//! | `with-uuid-1` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 1.0 | no |
//! | `with-time-0_2` | Enable support for the 0.2 version of the `time` crate. | [time](https://crates.io/crates/time/0.2.0) 0.2 | no |
//! | `with-time-0_3` | Enable support for the 0.3 version of the `time` crate. | [time](https://crates.io/crates/time/0.3.0) 0.3 | no |
#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.7")]
#![warn(rust_2018_idioms, clippy::all, missing_docs)]

pub use crate::cancel_token::CancelToken;
pub use crate::client::Client;
pub use crate::config::Config;
pub use crate::connection::Connection;
pub use crate::copy_in::CopyInSink;
pub use crate::copy_out::CopyOutStream;
use crate::error::DbError;
pub use crate::error::Error;
pub use crate::generic_client::GenericClient;
pub use crate::portal::Portal;
pub use crate::query::RowStream;
pub use crate::row::{Row, SimpleQueryRow};
pub use crate::simple_query::SimpleQueryStream;
#[cfg(feature = "runtime")]
pub use crate::socket::Socket;
pub use crate::statement::{Column, Statement};
#[cfg(feature = "runtime")]
use crate::tls::MakeTlsConnect;
pub use crate::tls::NoTls;
pub use crate::to_statement::ToStatement;
pub use crate::transaction::Transaction;
pub use crate::transaction_builder::{IsolationLevel, TransactionBuilder};
use crate::types::ToSql;

pub mod binary_copy;
mod bind;
#[cfg(feature = "runtime")]
mod cancel_query;
mod cancel_query_raw;
mod cancel_token;
mod client;
mod codec;
pub mod config;
#[cfg(feature = "runtime")]
mod connect;
mod connect_raw;
#[cfg(feature = "runtime")]
mod connect_socket;
mod connect_tls;
mod connection;
mod copy_in;
mod copy_out;
pub mod error;
mod generic_client;
mod maybe_tls_stream;
mod portal;
mod prepare;
mod query;
pub mod row;
mod simple_query;
#[cfg(feature = "runtime")]
mod socket;
mod statement;
pub mod tls;
mod to_statement;
mod transaction;
mod transaction_builder;
pub mod types;

/// A convenience function which parses a connection string and connects to the database.
///
/// See the documentation for [`Config`] for details on the connection string format.
///
/// Requires the `runtime` Cargo feature (enabled by default).
///
/// [`Config`]: config/struct.Config.html
#[cfg(feature = "runtime")]
pub async fn connect<T>(
    config: &str,
    tls: T,
) -> Result<(Client, Connection<Socket, T::Stream>), Error>
where
    T: MakeTlsConnect<Socket>,
{
    let config = config.parse::<Config>()?;
    config.connect(tls).await
}

/// An asynchronous notification.
#[derive(Clone, Debug)]
pub struct Notification {
    process_id: i32,
    channel: String,
    payload: String,
}

impl Notification {
    /// The process ID of the notifying backend process.
    pub fn process_id(&self) -> i32 {
        self.process_id
    }

    /// The name of the channel that the notify has been raised on.
    pub fn channel(&self) -> &str {
        &self.channel
    }

    /// The "payload" string passed from the notifying process.
    pub fn payload(&self) -> &str {
        &self.payload
    }
}

/// An asynchronous message from the server.
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum AsyncMessage {
    /// A notice.
    ///
    /// Notices use the same format as errors, but aren't "errors" per-se.
    Notice(DbError),
    /// A notification.
    ///
    /// Connections can subscribe to notifications with the `LISTEN` command.
    Notification(Notification),
}

/// Message returned by the `SimpleQuery` stream.
#[non_exhaustive]
pub enum SimpleQueryMessage {
    /// A row of data.
    Row(SimpleQueryRow),
    /// A statement in the query has completed.
    ///
    /// The number of rows modified or selected is returned.
    CommandComplete(u64),
}

fn slice_iter<'a>(
    s: &'a [&'a (dyn ToSql + Sync)],
) -> impl ExactSizeIterator<Item = &'a dyn ToSql> + 'a {
    s.iter().map(|s| *s as _)
}
<|endoftext|>


<commit_before>use proc_macro2::{Ident, Span, TokenStream};
use quote::ToTokens;
use syn::LitStr;

use std::ops::{Deref, DerefMut};

/// An entity with a span attached.
#[derive(Debug, Clone)]
pub struct Sp<T> {
    span: Span,
    val: T,
}

impl<T> Sp<T> {
    pub fn new(val: T, span: Span) -> Self {
        Sp { val, span }
    }

    pub fn call_site(val: T) -> Self {
        Sp {
            val,
            span: Span::call_site(),
        }
    }

    pub fn span(&self) -> Span {
        self.span
    }
}

impl<T> Deref for Sp<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.val
    }
}

impl<T> DerefMut for Sp<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.val
    }
}

impl From<Ident> for Sp<String> {
    fn from(ident: Ident) -> Self {
        Sp {
            val: ident.to_string(),
            span: ident.span(),
        }
    }
}

impl From<LitStr> for Sp<String> {
    fn from(lit: LitStr) -> Self {
        Sp {
            val: lit.value(),
            span: lit.span(),
        }
    }
}

impl<'a> From<Sp<&'a str>> for Sp<String> {
    fn from(sp: Sp<&'a str>) -> Self {
        Sp::new(sp.val.into(), sp.span)
    }
}

impl<U, T: PartialEq<U>> PartialEq<U> for Sp<T> {
    fn eq(&self, other: &U) -> bool {
        self.val == *other
    }
}

impl<T: AsRef<str>> AsRef<str> for Sp<T> {
    fn as_ref(&self) -> &str {
        self.val.as_ref()
    }
}

impl<T: ToTokens> ToTokens for Sp<T> {
    fn to_tokens(&self, stream: &mut TokenStream) {
        // this is the simplest way out of correct ones to change span on
        // arbitrary token tree I could come up with
        let tt = self.val.to_token_stream().into_iter().map(|mut tt| {
            tt.set_span(self.span);
            tt
        });

        stream.extend(tt);
    }
}
<commit_msg>Clippy fix<commit_after>use proc_macro2::{Ident, Span, TokenStream};
use quote::ToTokens;
use syn::LitStr;

use std::ops::{Deref, DerefMut};

/// An entity with a span attached.
#[derive(Debug, Clone)]
pub struct Sp<T> {
    val: T,
    span: Span,
}

impl<T> Sp<T> {
    pub fn new(val: T, span: Span) -> Self {
        Sp { val, span }
    }

    pub fn call_site(val: T) -> Self {
        Sp {
            val,
            span: Span::call_site(),
        }
    }

    pub fn span(&self) -> Span {
        self.span
    }
}

impl<T> Deref for Sp<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.val
    }
}

impl<T> DerefMut for Sp<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.val
    }
}

impl From<Ident> for Sp<String> {
    fn from(ident: Ident) -> Self {
        Sp {
            val: ident.to_string(),
            span: ident.span(),
        }
    }
}

impl From<LitStr> for Sp<String> {
    fn from(lit: LitStr) -> Self {
        Sp {
            val: lit.value(),
            span: lit.span(),
        }
    }
}

impl<'a> From<Sp<&'a str>> for Sp<String> {
    fn from(sp: Sp<&'a str>) -> Self {
        Sp::new(sp.val.into(), sp.span)
    }
}

impl<U, T: PartialEq<U>> PartialEq<U> for Sp<T> {
    fn eq(&self, other: &U) -> bool {
        self.val == *other
    }
}

impl<T: AsRef<str>> AsRef<str> for Sp<T> {
    fn as_ref(&self) -> &str {
        self.val.as_ref()
    }
}

impl<T: ToTokens> ToTokens for Sp<T> {
    fn to_tokens(&self, stream: &mut TokenStream) {
        // this is the simplest way out of correct ones to change span on
        // arbitrary token tree I could come up with
        let tt = self.val.to_token_stream().into_iter().map(|mut tt| {
            tt.set_span(self.span);
            tt
        });

        stream.extend(tt);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 bluss and ndarray developers.
//
// 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.

use super::IntoDimension;
use super::Dimension;
use Ix;

use itertools::zip;

/// Private constructor and accessors for Dim
pub trait DimPrivate<I> {
    fn new(index: I) -> Self;
    fn ix(&self) -> &I;
    fn ixm(&mut self) -> &mut I;
}

/// Dimension description.
///
/// `Dim` describes the number of axes and the length of each axis
/// in an array. It is also used as an index type.
///
/// The commonly you want to use the methods of the `Dimension` trait. See its
/// documentation for more information.
///
/// # Examples
///
/// To create an array with a particular dimension, you'd just pass
/// a tuple (in this example (3, 2) is used), which is converted to
/// `Dim` by the array constructor.
///
/// ```
/// use ndarray::Array2;
/// use ndarray::Dim;
///
/// let mut array = Array2::zeros((3, 2));
/// array[[0, 0]] = 1.;
/// assert_eq!(array.dim(), Dim([3, 2]));
/// ```
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
pub struct Dim<I: ?Sized> {
    index: I,
}

impl<I> DimPrivate<I> for Dim<I> {
    fn new(index: I) -> Dim<I> {
        Dim {
            index: index,
        }
    }
    fn ix(&self) -> &I { &self.index }
    fn ixm(&mut self) -> &mut I { &mut self.index }
}

/// Create a new dimension value.
#[allow(non_snake_case)]
pub fn Dim<T>(index: T) -> T::Dim
    where T: IntoDimension
{
    index.into_dimension()
}

impl<I: ?Sized> PartialEq<I> for Dim<I>
    where I: PartialEq,
{
    fn eq(&self, rhs: &I) -> bool {
        self.index == *rhs
    }
}

use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign};

macro_rules! impl_op {
    ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => {
    impl<I> $op for Dim<I>
        where Dim<I>: Dimension,
    {
        type Output = Self;
        fn $op_m(mut self, rhs: Self) -> Self {
            $expr!(self, &rhs);
            self
        }
    }

    impl<I> $opassign for Dim<I>
        where Dim<I>: Dimension,
    {
        fn $opassign_m(&mut self, rhs: Self) {
            $expr!(*self, &rhs);
        }
    }

    impl<'a, I> $opassign<&'a Dim<I>> for Dim<I>
        where Dim<I>: Dimension,
    {
        fn $opassign_m(&mut self, rhs: &Self) {
            for (x, &y) in zip(self.slice_mut(), rhs.slice()) {
                $expr!(*x, y);
            }
        }
    }

    }
}

macro_rules! impl_single_op {
    ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => {
    impl $op<Ix> for Dim<[Ix; 1]>
    {
        type Output = Self;
        #[inline]
        fn $op_m(mut self, rhs: Ix) -> Self {
            $expr!(self, rhs);
            self
        }
    }

    impl $opassign<Ix> for Dim<[Ix; 1]> {
        #[inline]
        fn $opassign_m(&mut self, rhs: Ix) {
            $expr!((*self)[0], rhs);
        }
    }
    };
}

macro_rules! impl_scalar_op {
    ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => {
    impl<I> $op<Ix> for Dim<I>
        where Dim<I>: Dimension,
    {
        type Output = Self;
        fn $op_m(mut self, rhs: Ix) -> Self {
            $expr!(self, rhs);
            self
        }
    }

    impl<I> $opassign<Ix> for Dim<I>
        where Dim<I>: Dimension,
    {
        fn $opassign_m(&mut self, rhs: Ix) {
            for x in self.slice_mut() {
                $expr!(*x, rhs);
            }
        }
    }
    };
}

macro_rules! add {
    ($x:expr, $y:expr) => { $x += $y; }
}
macro_rules! sub {
    ($x:expr, $y:expr) => { $x -= $y; }
}
macro_rules! mul {
    ($x:expr, $y:expr) => { $x *= $y; }
}
impl_op!(Add, add, AddAssign, add_assign, add);
impl_single_op!(Add, add, AddAssign, add_assign, add);
impl_op!(Sub, sub, SubAssign, sub_assign, sub);
impl_single_op!(Sub, sub, SubAssign, sub_assign, sub);
impl_op!(Mul, mul, MulAssign, mul_assign, mul);
impl_scalar_op!(Mul, mul, MulAssign, mul_assign, mul);

<commit_msg>Use simpler Debug impl for Dim<commit_after>// Copyright 2016 bluss and ndarray developers.
//
// 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.

use std::fmt;
use itertools::zip;

use super::IntoDimension;
use super::Dimension;
use Ix;

/// Private constructor and accessors for Dim
pub trait DimPrivate<I> {
    fn new(index: I) -> Self;
    fn ix(&self) -> &I;
    fn ixm(&mut self) -> &mut I;
}

/// Dimension description.
///
/// `Dim` describes the number of axes and the length of each axis
/// in an array. It is also used as an index type.
///
/// The commonly you want to use the methods of the `Dimension` trait. See its
/// documentation for more information.
///
/// # Examples
///
/// To create an array with a particular dimension, you'd just pass
/// a tuple (in this example (3, 2) is used), which is converted to
/// `Dim` by the array constructor.
///
/// ```
/// use ndarray::Array2;
/// use ndarray::Dim;
///
/// let mut array = Array2::zeros((3, 2));
/// array[[0, 0]] = 1.;
/// assert_eq!(array.dim(), Dim([3, 2]));
/// ```
#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Dim<I: ?Sized> {
    index: I,
}

impl<I> DimPrivate<I> for Dim<I> {
    fn new(index: I) -> Dim<I> {
        Dim {
            index: index,
        }
    }
    fn ix(&self) -> &I { &self.index }
    fn ixm(&mut self) -> &mut I { &mut self.index }
}

/// Create a new dimension value.
#[allow(non_snake_case)]
pub fn Dim<T>(index: T) -> T::Dim
    where T: IntoDimension
{
    index.into_dimension()
}

impl<I: ?Sized> PartialEq<I> for Dim<I>
    where I: PartialEq,
{
    fn eq(&self, rhs: &I) -> bool {
        self.index == *rhs
    }
}

impl<I> fmt::Debug for Dim<I>
    where I: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.index)
    }
}

use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign};

macro_rules! impl_op {
    ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => {
    impl<I> $op for Dim<I>
        where Dim<I>: Dimension,
    {
        type Output = Self;
        fn $op_m(mut self, rhs: Self) -> Self {
            $expr!(self, &rhs);
            self
        }
    }

    impl<I> $opassign for Dim<I>
        where Dim<I>: Dimension,
    {
        fn $opassign_m(&mut self, rhs: Self) {
            $expr!(*self, &rhs);
        }
    }

    impl<'a, I> $opassign<&'a Dim<I>> for Dim<I>
        where Dim<I>: Dimension,
    {
        fn $opassign_m(&mut self, rhs: &Self) {
            for (x, &y) in zip(self.slice_mut(), rhs.slice()) {
                $expr!(*x, y);
            }
        }
    }

    }
}

macro_rules! impl_single_op {
    ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => {
    impl $op<Ix> for Dim<[Ix; 1]>
    {
        type Output = Self;
        #[inline]
        fn $op_m(mut self, rhs: Ix) -> Self {
            $expr!(self, rhs);
            self
        }
    }

    impl $opassign<Ix> for Dim<[Ix; 1]> {
        #[inline]
        fn $opassign_m(&mut self, rhs: Ix) {
            $expr!((*self)[0], rhs);
        }
    }
    };
}

macro_rules! impl_scalar_op {
    ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => {
    impl<I> $op<Ix> for Dim<I>
        where Dim<I>: Dimension,
    {
        type Output = Self;
        fn $op_m(mut self, rhs: Ix) -> Self {
            $expr!(self, rhs);
            self
        }
    }

    impl<I> $opassign<Ix> for Dim<I>
        where Dim<I>: Dimension,
    {
        fn $opassign_m(&mut self, rhs: Ix) {
            for x in self.slice_mut() {
                $expr!(*x, rhs);
            }
        }
    }
    };
}

macro_rules! add {
    ($x:expr, $y:expr) => { $x += $y; }
}
macro_rules! sub {
    ($x:expr, $y:expr) => { $x -= $y; }
}
macro_rules! mul {
    ($x:expr, $y:expr) => { $x *= $y; }
}
impl_op!(Add, add, AddAssign, add_assign, add);
impl_single_op!(Add, add, AddAssign, add_assign, add);
impl_op!(Sub, sub, SubAssign, sub_assign, sub);
impl_single_op!(Sub, sub, SubAssign, sub_assign, sub);
impl_op!(Mul, mul, MulAssign, mul_assign, mul);
impl_scalar_op!(Mul, mul, MulAssign, mul_assign, mul);

<|endoftext|>


<commit_before>use super::super::{Y, X, Coord, Grid};
use super::*;

pub struct Field {
    size: i32,
    n_alpha: i32,
    cand: Grid<Cand>,
    value: Grid<Value>,
    clue_front: Vec<Clue>,
    clue_back: Vec<Clue>,
    inconsistent: bool,
    solved: bool,
}

impl Field {
    pub fn empty_board(size: i32, n_alpha: i32) -> Field {
        assert!(n_alpha >= 2);
        Field {
            size,
            n_alpha,
            cand: Grid::new(size, size, Cand((1u32 << n_alpha) - 1)),
            value: Grid::new(size, size, UNDECIDED),
            clue_front: vec![NO_CLUE; (2 * size) as usize],
            clue_back: vec![NO_CLUE; (2 * size) as usize],
            inconsistent: false,
            solved: false,
        }
    }
    pub fn get_value(&self, cell: Coord) -> Value {
        self.value[cell]
    }
    pub fn inconsistent(&self) -> bool {
        self.inconsistent
    }
    pub fn get_clue(&self, loc: ClueLoc, idx: i32) -> Clue {
        match loc {
            ClueLoc::Left => self.clue_front[idx as usize],
            ClueLoc::Right => self.clue_back[idx as usize],
            ClueLoc::Top => self.clue_front[(idx + self.size) as usize],
            ClueLoc::Bottom => self.clue_back[(idx + self.size) as usize],
        }
    }
    pub fn set_clue(&mut self, loc: ClueLoc, idx: i32, clue: Clue) {
        let current = self.get_clue(loc, idx);
        if current != NO_CLUE {
            if current != clue {
                self.inconsistent = true;
            }
            return;
        }
        let size = self.size;
        match loc {
            ClueLoc::Left => self.clue_front[idx as usize] = clue,
            ClueLoc::Right => self.clue_back[idx as usize] = clue,
            ClueLoc::Top => self.clue_front[(idx + size) as usize] = clue,
            ClueLoc::Bottom => self.clue_back[(idx + size) as usize] = clue,
        }
        if loc == ClueLoc::Left || loc == ClueLoc::Right {
            self.inspect_row(idx);
        } else {
            self.inspect_row(idx + size);
        }
    }
    pub fn decide(&mut self, cell: Coord, val: Value) {
        let current = self.value[cell];
        if current != UNDECIDED && !(current == SOME && val != EMPTY) {
            if current != val {
                println!("err {:?} {:?} {:?}", cell, current, val);
                self.inconsistent = true;
            }
            return;
        }

        self.value[cell] = val;

        if val == EMPTY {
            self.limit_cand(cell, Cand(0));
        } else if val == SOME {
            self.inspect_cell(cell);
        } else if val != UNDECIDED {
            self.limit_cand(cell, Cand::singleton(val.0));

            let (Y(y), X(x)) = cell;
            let limit = !Cand::singleton(val.0);
            for y2 in 0..self.size {
                if y != y2 { self.limit_cand((Y(y2), X(x)), limit); }
            }
            for x2 in 0..self.size {
                if x != x2 { self.limit_cand((Y(y), X(x2)), limit); }
            }
        }
    }
    /// Returns `pos`-th cell of group `gid`.
    fn group(&self, gid: i32, pos: i32) -> Coord {
        if gid < self.size {
            (Y(gid), X(pos))
        } else {
            (Y(pos), X(gid - self.size))
        }
    }
    /// Returns `pos`-th cell of group `gid` with reversed indexing of cells when `dir` is `true`.
    fn directed_group(&self, gid: i32, pos: i32, dir: bool) -> Coord {
        self.group(gid, if dir { self.size - pos - 1 } else { pos })
    }
    fn limit_cand(&mut self, cell: Coord, lim: Cand) {
        let current_cand = self.cand[cell];

        if (current_cand & lim) == current_cand {
            return;
        }

        let new_cand = current_cand & lim;
        self.cand[cell] = new_cand;

        if self.cand[cell] == Cand(0) {
            self.decide(cell, EMPTY);
        }
        self.inspect_cell(cell);
    }
    fn inspect_cell(&mut self, cell: Coord) {
        if self.value[cell] == SOME && self.cand[cell].count_set_cands() == 1 {
            let val = Value(self.cand[cell].smallest_set_cand());
            self.decide(cell, val);
        }
        let size = self.size;
        let (Y(y), X(x)) = cell;
        self.inspect_row(y);
        self.inspect_row(x + size);
    }
    fn inspect_row(&mut self, group: i32) {
        let size = self.size;
        let n_alpha = self.n_alpha;

        let mut n_some = 0;
        let mut n_empty = 0;

        for i in 0..size {
            let v = self.value[self.group(group, i)];
            if v == EMPTY {
                n_empty += 1;
            } else if v != UNDECIDED {
                n_some += 1;
            }
        }

        if n_some == n_alpha {
            for i in 0..size {
                let c = self.group(group, i);
                if self.value[c] == UNDECIDED {
                    self.decide(c, EMPTY);
                }
            }
        }
        if n_empty == size - n_alpha {
            for i in 0..size {
                let c = self.group(group, i);
                if self.value[c] == UNDECIDED {
                    self.decide(c, SOME);
                }
            }
        }

        for a in 0..n_alpha {
            let mut loc = -1;
            for i in 0..size {
                if self.cand[self.group(group, i)].is_set(a) {
                    if loc == -1 {
                        loc = i;
                    } else {
                        loc = -2;
                        break;
                    }
                }
            }
            if loc == -1 {
                self.inconsistent = true;
                return;
            } else if loc != -2 {
                let c = self.group(group, loc);
                self.decide(c, Value(a));
            }
        }
        for &dir in [true, false].iter() {
            let clue = if !dir { self.clue_front[group as usize] } else { self.clue_back[group as usize] };
            if clue == NO_CLUE {
                continue;
            }

            let mut first_nonempty_id = -1;
            for i in 0..size {
                let v = self.value[self.directed_group(group, i, dir)];
                if v != EMPTY {
                    first_nonempty_id = i;
                    break;
                }
            }
            if first_nonempty_id == -1 {
                self.inconsistent = true;
                return;
            }
            let first_nonempty_cell = self.directed_group(group, first_nonempty_id, dir);
            self.limit_cand(first_nonempty_cell, Cand::singleton(clue.0));

            let mut first_diff_id = -1;
            for i in 0..size {
                let v = self.value[self.directed_group(group, i, dir)];
                if v == SOME && !self.cand[self.directed_group(group, i, dir)].is_set(clue.0) {
                    first_diff_id = i;
                }
            }
            if first_diff_id != -1 {
                for i in (first_diff_id + 1)..size {
                    let c = self.directed_group(group, i, dir);
                    self.limit_cand(c, !Cand::singleton(clue.0));
                }
            }

            let mut n_back_diff = n_alpha - 1;
            for i in 0..size {
                let c = self.directed_group(group, i, !dir);
                let v = self.value[c];
                if v != EMPTY {
                    self.limit_cand(c, !Cand::singleton(clue.0));
                    n_back_diff -= 1;
                    if n_back_diff == 0 { break; }
                }
            }

            let mut mask = Cand((1u32 << n_alpha) - 1) & !Cand::singleton(clue.0);
            for i in 0..size {
                let c = self.directed_group(group, i, !dir);
                self.limit_cand(c, !Cand::singleton(clue.0));
                mask &= !self.cand[c];
                if mask == Cand(0) {
                    break;
                }
            }
        }
    }
    /// Apply *fishy method* (like *X-wing* and *Sword fish* in Sudoku) to the field.
    /// Note: runs in O*(2^size) and works only if size < 32.
    pub fn fishy_method(&mut self) {
        let size = self.size;
        for i in 0..self.n_alpha {
            let mut masks = vec![];
            for y in 0..size {
                let mut mask = 0u32;
                for x in 0..size {
                    if self.cand[(Y(y), X(x))].is_set(i) {
                        mask |= 1u32 << x;
                    }
                }
                masks.push(mask);
            }
            for bits in 1..(1u32 << size) {
                let mut ors = 0u32;
                for y in 0..size {
                    if (bits & (1u32 << y)) != 0 {
                        ors |= masks[y as usize];
                    }
                }
                if bits.count_ones() > ors.count_ones() {
                    self.inconsistent = true;
                    return;
                } else if bits.count_ones() == ors.count_ones() {
                    for y in 0..size {
                        if (bits & (1u32 << y)) == 0 {
                            masks[y as usize] &= !ors;
                        }
                    }
                }
            }
            for y in 0..size {
                for x in 0..size {
                    if (masks[y as usize] & (1u32 << x)) == 0 {
                        self.limit_cand((Y(y), X(x)), !Cand::singleton(i));
                    }
                }
            }
        }
    }
}

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

    #[test]
    fn test_deduction() {
        {
            // a symbol shouldn't occur more than once in a row / a column
            let mut field = Field::empty_board(5, 3);

            assert_eq!(field.cand[(Y(0), X(0))], Cand(7));
            assert_eq!(field.cand[(Y(0), X(1))], Cand(7));
            assert_eq!(field.cand[(Y(1), X(1))], Cand(7));

            field.decide((Y(0), X(0)), Value(0));

            assert_eq!(field.inconsistent, false);
            assert_eq!(field.cand[(Y(0), X(0))], Cand(1));
            assert_eq!(field.cand[(Y(0), X(1))], Cand(6));
            assert_eq!(field.cand[(Y(1), X(0))], Cand(6));
            assert_eq!(field.cand[(Y(1), X(1))], Cand(7));
        }
        {
            // there must be exactly `n_alpha` symbols in a row / a column
            let mut field = Field::empty_board(5, 3);

            field.decide((Y(1), X(0)), SOME);
            field.decide((Y(1), X(1)), SOME);
            field.decide((Y(1), X(2)), SOME);

            assert_eq!(field.inconsistent, false);
            assert_eq!(field.value[(Y(1), X(3))], EMPTY);
        }
        {
            // there must be exactly `n_alpha` symbols in a row / a column
            let mut field = Field::empty_board(5, 3);

            field.decide((Y(3), X(2)), EMPTY);
            field.decide((Y(4), X(2)), EMPTY);

            assert_eq!(field.inconsistent, false);
            assert_eq!(field.value[(Y(1), X(2))], SOME);
        }
        {
            let mut field = Field::empty_board(5, 3);

            field.limit_cand((Y(0), X(2)), Cand(5));
            field.limit_cand((Y(2), X(2)), Cand(5));
            field.limit_cand((Y(3), X(2)), Cand(5));
            field.limit_cand((Y(4), X(2)), Cand(5));

            assert_eq!(field.inconsistent, false);
            assert_eq!(field.value[(Y(1), X(2))], Value(1));
            assert_eq!(field.cand[(Y(1), X(3))], Cand(5));
        }
    }

    #[test]
    fn test_clue() {
        {
            let mut field = Field::empty_board(5, 3);

            field.set_clue(ClueLoc::Left, 0, Clue(0));

            assert_eq!(field.cand[(Y(0), X(0))], Cand(1));
            assert_eq!(field.cand[(Y(0), X(3))], Cand(6));
            assert_eq!(field.cand[(Y(0), X(4))], Cand(6));
        }
    }
}
<commit_msg>Endview: remove debug output<commit_after>use super::super::{Y, X, Coord, Grid};
use super::*;

pub struct Field {
    size: i32,
    n_alpha: i32,
    cand: Grid<Cand>,
    value: Grid<Value>,
    clue_front: Vec<Clue>,
    clue_back: Vec<Clue>,
    inconsistent: bool,
    solved: bool,
}

impl Field {
    pub fn empty_board(size: i32, n_alpha: i32) -> Field {
        assert!(n_alpha >= 2);
        Field {
            size,
            n_alpha,
            cand: Grid::new(size, size, Cand((1u32 << n_alpha) - 1)),
            value: Grid::new(size, size, UNDECIDED),
            clue_front: vec![NO_CLUE; (2 * size) as usize],
            clue_back: vec![NO_CLUE; (2 * size) as usize],
            inconsistent: false,
            solved: false,
        }
    }
    pub fn get_value(&self, cell: Coord) -> Value {
        self.value[cell]
    }
    pub fn inconsistent(&self) -> bool {
        self.inconsistent
    }
    pub fn get_clue(&self, loc: ClueLoc, idx: i32) -> Clue {
        match loc {
            ClueLoc::Left => self.clue_front[idx as usize],
            ClueLoc::Right => self.clue_back[idx as usize],
            ClueLoc::Top => self.clue_front[(idx + self.size) as usize],
            ClueLoc::Bottom => self.clue_back[(idx + self.size) as usize],
        }
    }
    pub fn set_clue(&mut self, loc: ClueLoc, idx: i32, clue: Clue) {
        let current = self.get_clue(loc, idx);
        if current != NO_CLUE {
            if current != clue {
                self.inconsistent = true;
            }
            return;
        }
        let size = self.size;
        match loc {
            ClueLoc::Left => self.clue_front[idx as usize] = clue,
            ClueLoc::Right => self.clue_back[idx as usize] = clue,
            ClueLoc::Top => self.clue_front[(idx + size) as usize] = clue,
            ClueLoc::Bottom => self.clue_back[(idx + size) as usize] = clue,
        }
        if loc == ClueLoc::Left || loc == ClueLoc::Right {
            self.inspect_row(idx);
        } else {
            self.inspect_row(idx + size);
        }
    }
    pub fn decide(&mut self, cell: Coord, val: Value) {
        let current = self.value[cell];
        if current != UNDECIDED && !(current == SOME && val != EMPTY) {
            if current != val {
                self.inconsistent = true;
            }
            return;
        }

        self.value[cell] = val;

        if val == EMPTY {
            self.limit_cand(cell, Cand(0));
        } else if val == SOME {
            self.inspect_cell(cell);
        } else if val != UNDECIDED {
            self.limit_cand(cell, Cand::singleton(val.0));

            let (Y(y), X(x)) = cell;
            let limit = !Cand::singleton(val.0);
            for y2 in 0..self.size {
                if y != y2 { self.limit_cand((Y(y2), X(x)), limit); }
            }
            for x2 in 0..self.size {
                if x != x2 { self.limit_cand((Y(y), X(x2)), limit); }
            }
        }
    }
    /// Returns `pos`-th cell of group `gid`.
    fn group(&self, gid: i32, pos: i32) -> Coord {
        if gid < self.size {
            (Y(gid), X(pos))
        } else {
            (Y(pos), X(gid - self.size))
        }
    }
    /// Returns `pos`-th cell of group `gid` with reversed indexing of cells when `dir` is `true`.
    fn directed_group(&self, gid: i32, pos: i32, dir: bool) -> Coord {
        self.group(gid, if dir { self.size - pos - 1 } else { pos })
    }
    fn limit_cand(&mut self, cell: Coord, lim: Cand) {
        let current_cand = self.cand[cell];

        if (current_cand & lim) == current_cand {
            return;
        }

        let new_cand = current_cand & lim;
        self.cand[cell] = new_cand;

        if self.cand[cell] == Cand(0) {
            self.decide(cell, EMPTY);
        }
        self.inspect_cell(cell);
    }
    fn inspect_cell(&mut self, cell: Coord) {
        if self.value[cell] == SOME && self.cand[cell].count_set_cands() == 1 {
            let val = Value(self.cand[cell].smallest_set_cand());
            self.decide(cell, val);
        }
        let size = self.size;
        let (Y(y), X(x)) = cell;
        self.inspect_row(y);
        self.inspect_row(x + size);
    }
    fn inspect_row(&mut self, group: i32) {
        let size = self.size;
        let n_alpha = self.n_alpha;

        let mut n_some = 0;
        let mut n_empty = 0;

        for i in 0..size {
            let v = self.value[self.group(group, i)];
            if v == EMPTY {
                n_empty += 1;
            } else if v != UNDECIDED {
                n_some += 1;
            }
        }

        if n_some == n_alpha {
            for i in 0..size {
                let c = self.group(group, i);
                if self.value[c] == UNDECIDED {
                    self.decide(c, EMPTY);
                }
            }
        }
        if n_empty == size - n_alpha {
            for i in 0..size {
                let c = self.group(group, i);
                if self.value[c] == UNDECIDED {
                    self.decide(c, SOME);
                }
            }
        }

        for a in 0..n_alpha {
            let mut loc = -1;
            for i in 0..size {
                if self.cand[self.group(group, i)].is_set(a) {
                    if loc == -1 {
                        loc = i;
                    } else {
                        loc = -2;
                        break;
                    }
                }
            }
            if loc == -1 {
                self.inconsistent = true;
                return;
            } else if loc != -2 {
                let c = self.group(group, loc);
                self.decide(c, Value(a));
            }
        }
        for &dir in [true, false].iter() {
            let clue = if !dir { self.clue_front[group as usize] } else { self.clue_back[group as usize] };
            if clue == NO_CLUE {
                continue;
            }

            let mut first_nonempty_id = -1;
            for i in 0..size {
                let v = self.value[self.directed_group(group, i, dir)];
                if v != EMPTY {
                    first_nonempty_id = i;
                    break;
                }
            }
            if first_nonempty_id == -1 {
                self.inconsistent = true;
                return;
            }
            let first_nonempty_cell = self.directed_group(group, first_nonempty_id, dir);
            self.limit_cand(first_nonempty_cell, Cand::singleton(clue.0));

            let mut first_diff_id = -1;
            for i in 0..size {
                let v = self.value[self.directed_group(group, i, dir)];
                if v == SOME && !self.cand[self.directed_group(group, i, dir)].is_set(clue.0) {
                    first_diff_id = i;
                }
            }
            if first_diff_id != -1 {
                for i in (first_diff_id + 1)..size {
                    let c = self.directed_group(group, i, dir);
                    self.limit_cand(c, !Cand::singleton(clue.0));
                }
            }

            let mut n_back_diff = n_alpha - 1;
            for i in 0..size {
                let c = self.directed_group(group, i, !dir);
                let v = self.value[c];
                if v != EMPTY {
                    self.limit_cand(c, !Cand::singleton(clue.0));
                    n_back_diff -= 1;
                    if n_back_diff == 0 { break; }
                }
            }

            let mut mask = Cand((1u32 << n_alpha) - 1) & !Cand::singleton(clue.0);
            for i in 0..size {
                let c = self.directed_group(group, i, !dir);
                self.limit_cand(c, !Cand::singleton(clue.0));
                mask &= !self.cand[c];
                if mask == Cand(0) {
                    break;
                }
            }
        }
    }
    /// Apply *fishy method* (like *X-wing* and *Sword fish* in Sudoku) to the field.
    /// Note: runs in O*(2^size) and works only if size < 32.
    pub fn fishy_method(&mut self) {
        let size = self.size;
        for i in 0..self.n_alpha {
            let mut masks = vec![];
            for y in 0..size {
                let mut mask = 0u32;
                for x in 0..size {
                    if self.cand[(Y(y), X(x))].is_set(i) {
                        mask |= 1u32 << x;
                    }
                }
                masks.push(mask);
            }
            for bits in 1..(1u32 << size) {
                let mut ors = 0u32;
                for y in 0..size {
                    if (bits & (1u32 << y)) != 0 {
                        ors |= masks[y as usize];
                    }
                }
                if bits.count_ones() > ors.count_ones() {
                    self.inconsistent = true;
                    return;
                } else if bits.count_ones() == ors.count_ones() {
                    for y in 0..size {
                        if (bits & (1u32 << y)) == 0 {
                            masks[y as usize] &= !ors;
                        }
                    }
                }
            }
            for y in 0..size {
                for x in 0..size {
                    if (masks[y as usize] & (1u32 << x)) == 0 {
                        self.limit_cand((Y(y), X(x)), !Cand::singleton(i));
                    }
                }
            }
        }
    }
}

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

    #[test]
    fn test_deduction() {
        {
            // a symbol shouldn't occur more than once in a row / a column
            let mut field = Field::empty_board(5, 3);

            assert_eq!(field.cand[(Y(0), X(0))], Cand(7));
            assert_eq!(field.cand[(Y(0), X(1))], Cand(7));
            assert_eq!(field.cand[(Y(1), X(1))], Cand(7));

            field.decide((Y(0), X(0)), Value(0));

            assert_eq!(field.inconsistent, false);
            assert_eq!(field.cand[(Y(0), X(0))], Cand(1));
            assert_eq!(field.cand[(Y(0), X(1))], Cand(6));
            assert_eq!(field.cand[(Y(1), X(0))], Cand(6));
            assert_eq!(field.cand[(Y(1), X(1))], Cand(7));
        }
        {
            // there must be exactly `n_alpha` symbols in a row / a column
            let mut field = Field::empty_board(5, 3);

            field.decide((Y(1), X(0)), SOME);
            field.decide((Y(1), X(1)), SOME);
            field.decide((Y(1), X(2)), SOME);

            assert_eq!(field.inconsistent, false);
            assert_eq!(field.value[(Y(1), X(3))], EMPTY);
        }
        {
            // there must be exactly `n_alpha` symbols in a row / a column
            let mut field = Field::empty_board(5, 3);

            field.decide((Y(3), X(2)), EMPTY);
            field.decide((Y(4), X(2)), EMPTY);

            assert_eq!(field.inconsistent, false);
            assert_eq!(field.value[(Y(1), X(2))], SOME);
        }
        {
            let mut field = Field::empty_board(5, 3);

            field.limit_cand((Y(0), X(2)), Cand(5));
            field.limit_cand((Y(2), X(2)), Cand(5));
            field.limit_cand((Y(3), X(2)), Cand(5));
            field.limit_cand((Y(4), X(2)), Cand(5));

            assert_eq!(field.inconsistent, false);
            assert_eq!(field.value[(Y(1), X(2))], Value(1));
            assert_eq!(field.cand[(Y(1), X(3))], Cand(5));
        }
    }

    #[test]
    fn test_clue() {
        {
            let mut field = Field::empty_board(5, 3);

            field.set_clue(ClueLoc::Left, 0, Clue(0));

            assert_eq!(field.cand[(Y(0), X(0))], Cand(1));
            assert_eq!(field.cand[(Y(0), X(3))], Cand(6));
            assert_eq!(field.cand[(Y(0), X(4))], Cand(6));
        }
    }
}
<|endoftext|>


<commit_before>mod coordinate;

pub use self::coordinate::Coordinate;

use crusader::*;
use dps::*;

#[derive(Debug, Clone)]
pub struct Formation<'a> {
    positions: Vec<FormationPosition<'a>>,
    used_slots: Slot,
}

impl<'a> Formation<'a> {
    pub fn empty<I: IntoIterator<Item=Coordinate>>(positions: I) -> Self {
        let positions = positions.into_iter().map(FormationPosition::empty).collect();
        Formation {
            positions,
            used_slots: Slot::empty(),
        }
    }

    pub fn place_crusader(&mut self, position: usize, crusader: &'a Crusader) -> &mut Self {
        self.positions[position].crusader = Some(crusader);
        self.used_slots |= crusader.slot();
        self
    }

    pub fn total_dps(&self) -> Dps {
        self.crusaders().map(|c| {
            c.base_dps()
        }).sum()
    }

    pub fn empty_positions<'b>(&'b self) -> impl Iterator<Item=usize> + 'b {
        self.positions.iter()
            .enumerate()
            .filter(|&(_, p)| p.crusader.is_none())
            .map(|(i, _)| i)
    }

    pub fn used_slots(&self) -> Slot {
        self.used_slots
    }

    pub fn placements<'b>(&'b self)
        -> impl Iterator<Item=(Coordinate, Option<&'a Crusader>)> + 'b
    {
        self.positions.iter()
            .map(|pos| (pos.coordinate, pos.crusader))
    }

    fn crusaders<'b>(&'b self) -> impl Iterator<Item=&'a Crusader> + 'b {
        self.positions.iter().filter_map(|p| p.crusader)
    }
}

#[derive(Debug, Clone)]
pub struct FormationPosition<'a> {
    pub coordinate: Coordinate,
    pub crusader: Option<&'a Crusader>,
}

impl<'a> FormationPosition<'a> {
    fn empty(coordinate: Coordinate) -> Self {
        FormationPosition {
            coordinate,
            crusader: None,
        }
    }
}
<commit_msg>Use boxed slice instead of vec on Formation<commit_after>mod coordinate;

pub use self::coordinate::Coordinate;

use crusader::*;
use dps::*;

#[derive(Debug, Clone)]
pub struct Formation<'a> {
    positions: Box<[FormationPosition<'a>]>,
    used_slots: Slot,
}

impl<'a> Formation<'a> {
    pub fn empty<I: IntoIterator<Item=Coordinate>>(positions: I) -> Self {
        let positions = positions.into_iter().map(FormationPosition::empty)
            .collect::<Vec<_>>()
            .into_boxed_slice();
        Formation {
            positions,
            used_slots: Slot::empty(),
        }
    }

    pub fn place_crusader(&mut self, position: usize, crusader: &'a Crusader) -> &mut Self {
        self.positions[position].crusader = Some(crusader);
        self.used_slots |= crusader.slot();
        self
    }

    pub fn total_dps(&self) -> Dps {
        self.crusaders().map(|c| {
            c.base_dps()
        }).sum()
    }

    pub fn empty_positions<'b>(&'b self) -> impl Iterator<Item=usize> + 'b {
        self.positions.iter()
            .enumerate()
            .filter(|&(_, p)| p.crusader.is_none())
            .map(|(i, _)| i)
    }

    pub fn used_slots(&self) -> Slot {
        self.used_slots
    }

    pub fn placements<'b>(&'b self)
        -> impl Iterator<Item=(Coordinate, Option<&'a Crusader>)> + 'b
    {
        self.positions.iter()
            .map(|pos| (pos.coordinate, pos.crusader))
    }

    fn crusaders<'b>(&'b self) -> impl Iterator<Item=&'a Crusader> + 'b {
        self.positions.iter().filter_map(|p| p.crusader)
    }
}

#[derive(Debug, Clone)]
pub struct FormationPosition<'a> {
    pub coordinate: Coordinate,
    pub crusader: Option<&'a Crusader>,
}

impl<'a> FormationPosition<'a> {
    fn empty(coordinate: Coordinate) -> Self {
        FormationPosition {
            coordinate,
            crusader: None,
        }
    }
}
<|endoftext|>