<commit_before>use std::collections::HashMap;

pub trait ToOutput {
    fn to_output(&self) -> &[u8];
}

impl ToOutput for str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for String {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for Vec<u8> {
    fn to_output(&self) -> &[u8] {
        self.as_slice()
    }
}

#[derive(Debug)]
pub struct Response {
    code:       i32,
    cmsg:       String,
    ctype:      String,
    headers:    HashMap<String, String>,
    payload:    Vec<u8>,
}

impl Response {
    pub fn new() -> Response {
        let mut res = Response {
            code:       200,
            cmsg:       String::from("OK"),
            ctype:      String::from("text/plain"),
            headers:    HashMap::new(),
            payload:    Vec::new(),
        };

        res.add_header("Connection", "close");
        res.add_header("Server", "canteen/0.0.1");

        res
    }

    fn get_http_message(code: i32) -> String {
        let msg = match code {
            100 => "Continue",
            101 => "Switching Protocols",
            200 => "OK",
            201 => "Created",
            202 => "Accepted",
            203 => "Non-Authoritative Information",
            204 => "No Content",
            205 => "Reset Content",
            206 => "Partial Content",
            300 => "Multiple Choices",
            301 => "Moved Permanently",
            302 => "Found",
            303 => "See Other",
            304 => "Not Modified",
            305 => "Use Proxy",
            307 => "Temporary Redirect",
            400 => "Bad Request",
            401 => "Unauthorized",
            402 => "Payment Required",
            403 => "Forbidden",
            404 => "Not Found",
            405 => "Method Not Allowed",
            406 => "Not Acceptable",
            407 => "Proxy Authentication Required",
            408 => "Request Time Out",
            409 => "Conflict",
            410 => "Gone",
            411 => "Length Required",
            412 => "Precondition Failed",
            413 => "Request Entity Too Large",
            414 => "Request-URI Too Large",
            415 => "Unsupported Media Type",
            416 => "Requested Range Not Satisfiable",
            417 => "Expectation Failed",
            500 => "Internal Server Error",
            501 => "Not Implemented",
            502 => "Bad Gateway",
            503 => "Service Unavailable",
            504 => "Gateway Time-out",
            505 => "HTTP Version Not Supported",
            _     => "OK",
        };

        String::from(msg)
    }

    pub fn err_403(path: &str) -> Response {
        let mut res = Response::new();

        res.set_code(403);
        res.set_content_type("text/html");
        res.append(format!("\
                            \

Your request failed

forbidden: {}
", path));

        res
    }

    pub fn err_404(path: &str) -> Response {
        let mut res = Response::new();

        res.set_code(403);
        res.set_content_type("text/html");
        res.append(format!("\
                            \

Your request failed

not found: {}
", path));

        res
    }

    /* set the response code
     * ex: res.set_code(200, "OK");
     */
    pub fn set_code(&mut self, code: i32) {
        self.code = code;
        self.cmsg = Response::get_http_message(code);
    }

    /* set the content type
     * ex: res.set_content_type("text/html");
     */
    pub fn set_content_type(&mut self, ctype: &str) {
        self.ctype = String::from(ctype);
    }

    /* add an HTTP header
     * ex: res.add_header("Connection", "close");
     */
    pub fn add_header(&mut self, key: &str, value: &str) {
        if !self.headers.contains_key(key) {
            self.headers.insert(String::from(key), String::from(value));
        }
    }

    /* add data to the payload -- can take any type that has
     * implemented the canteen::response::ToOutput trait
     */
    pub fn append<T: ToOutput>(&mut self, payload: T) {
        self.payload.extend(payload.to_output().into_iter());
    }

    pub fn gen_output(&self) -> Vec<u8> {
        let mut output: Vec<u8> = Vec::new();
        let mut inter = String::new();

        inter.push_str(&format!("HTTP/1.1 {} {}\r\n", self.code, self.cmsg));

        for (key, value) in &self.headers {
            inter.push_str(&format!("{}: {}\r\n", key, value));
        }

        inter.push_str(&format!("Content-Type: {}\r\n", self.ctype));
        inter.push_str(&format!("Content-Length: {}\r\n", self.payload.len()));
        inter.push_str("\r\n");

        output.extend(inter.as_bytes());
        output.extend(self.payload.iter());

        output
    }
}
<commit_msg>add a 500 handler, and a utility function for generating error message bodies<commit_after>use std::collections::HashMap;

pub trait ToOutput {
    fn to_output(&self) -> &[u8];
}

impl ToOutput for str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for String {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for Vec<u8> {
    fn to_output(&self) -> &[u8] {
        self.as_slice()
    }
}

#[derive(Debug)]
pub struct Response {
    code:       i32,
    cmsg:       String,
    ctype:      String,
    headers:    HashMap<String, String>,
    payload:    Vec<u8>,
}

impl Response {
    pub fn new() -> Response {
        let mut res = Response {
            code:       200,
            cmsg:       String::from("OK"),
            ctype:      String::from("text/plain"),
            headers:    HashMap::new(),
            payload:    Vec::new(),
        };

        res.add_header("Connection", "close");
        res.add_header("Server", "canteen/0.0.1");

        res
    }

    fn get_http_message(code: i32) -> String {
        let msg = match code {
            100 => "Continue",
            101 => "Switching Protocols",
            200 => "OK",
            201 => "Created",
            202 => "Accepted",
            203 => "Non-Authoritative Information",
            204 => "No Content",
            205 => "Reset Content",
            206 => "Partial Content",
            300 => "Multiple Choices",
            301 => "Moved Permanently",
            302 => "Found",
            303 => "See Other",
            304 => "Not Modified",
            305 => "Use Proxy",
            307 => "Temporary Redirect",
            400 => "Bad Request",
            401 => "Unauthorized",
            402 => "Payment Required",
            403 => "Forbidden",
            404 => "Not Found",
            405 => "Method Not Allowed",
            406 => "Not Acceptable",
            407 => "Proxy Authentication Required",
            408 => "Request Time Out",
            409 => "Conflict",
            410 => "Gone",
            411 => "Length Required",
            412 => "Precondition Failed",
            413 => "Request Entity Too Large",
            414 => "Request-URI Too Large",
            415 => "Unsupported Media Type",
            416 => "Requested Range Not Satisfiable",
            417 => "Expectation Failed",
            500 => "Internal Server Error",
            501 => "Not Implemented",
            502 => "Bad Gateway",
            503 => "Service Unavailable",
            504 => "Gateway Time-out",
            505 => "HTTP Version Not Supported",
            _     => "OK",
        };

        String::from(msg)
    }

    fn err_body(message: &str, path: &str) -> String {
        format!("\
                 \

Your request failed

{}: {}
", message, path)
    }

    pub fn err_403(path: &str) -> Response {
        let mut res = Response::new();

        res.set_code(403);
        res.set_content_type("text/html");
        res.append(Response::err_body("forbidden", path));

        res
    }

    pub fn err_404(path: &str) -> Response {
        let mut res = Response::new();

        res.set_code(403);
        res.set_content_type("text/html");
        res.append(Response::err_body("not found", path));

        res
    }

    pub fn err_500(path: &str) -> Response {
        let mut res = Response::new();

        res.set_code(500);
        res.set_content_type("text/html");
        res.append(Response::err_body("internal server error", path));

        res
    }

    /* set the response code
     * ex: res.set_code(200, "OK");
     */
    pub fn set_code(&mut self, code: i32) {
        self.code = code;
        self.cmsg = Response::get_http_message(code);
    }

    /* set the content type
     * ex: res.set_content_type("text/html");
     */
    pub fn set_content_type(&mut self, ctype: &str) {
        self.ctype = String::from(ctype);
    }

    /* add an HTTP header
     * ex: res.add_header("Connection", "close");
     */
    pub fn add_header(&mut self, key: &str, value: &str) {
        if !self.headers.contains_key(key) {
            self.headers.insert(String::from(key), String::from(value));
        }
    }

    /* add data to the payload -- can take any type that has
     * implemented the canteen::response::ToOutput trait
     */
    pub fn append<T: ToOutput>(&mut self, payload: T) {
        self.payload.extend(payload.to_output().into_iter());
    }

    pub fn gen_output(&self) -> Vec<u8> {
        let mut output: Vec<u8> = Vec::new();
        let mut inter = String::new();

        inter.push_str(&format!("HTTP/1.1 {} {}\r\n", self.code, self.cmsg));

        for (key, value) in &self.headers {
            inter.push_str(&format!("{}: {}\r\n", key, value));
        }

        inter.push_str(&format!("Content-Type: {}\r\n", self.ctype));
        inter.push_str(&format!("Content-Length: {}\r\n", self.payload.len()));
        inter.push_str("\r\n");

        output.extend(inter.as_bytes());
        output.extend(self.payload.iter());

        output
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;

static NTHREADS: i32 = 3;

fn main() {
    // Channels have two endpoints: the `Sender<T>` and the `Receiver<T>`,
    // where `T` is the type of the message to be transferred
    // (type annotation is superfluous)
    let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();

    for id in 0..NTHREADS {
        // The sender endpoint can be copied
        let thread_tx = tx.clone();

        // Each thread will send its id via the channel
        thread::spawn(move || {
            // The thread takes ownership over `thread_tx`
            // Each thread queues a message in the channel
            thread_tx.send(id).unwrap();

            // Sending is a non-blocking operation, the thread will continue
            // immediately after sending its message
            println!("thread {} finished", id);
        });
    }

    // Here, all the messages are collected
    let mut ids = Vec::with_capacity(NTHREADS as usize);
    for _ in 0..NTHREADS {
        // The `recv` method picks a message from the channel
        // `recv` will block the current thread if there no messages available
        ids.push(rx.recv());
    }

    // Show the order in which the messages were sent
    println!("{:?}", ids);
}
<commit_msg>Translate examples/std_misc/channels/channels.rs<commit_after>use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;

static NTHREADS: i32 = 3;

fn main() {
    // 通道有两个端点：`Sender<T>` 和 `Receiver<T>`，其中 `T` 是要发送
    // 消息的类型（类型标注是可有可无的）
    let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();

    for id in 0..NTHREADS {
        // sender 发送端可被复制
        let thread_tx = tx.clone();

        // 每个线程都将通过通道来发送它的 id
        thread::spawn(move || {
            // 此线程取得 `thread_tx` 所有权
            // 每个线程都在通道中排队列出消息
            // （原文：The thread takes ownership over `thread_tx`
            // Each thread queues a message in the channel）
            thread_tx.send(id).unwrap();

            // 发送是一个非阻塞操作，线程将在发送完消息后继续进行
            println!("thread {} finished", id);
        });
    }

    // 所有消息都在此处被收集
    let mut ids = Vec::with_capacity(NTHREADS as usize);
    for _ in 0..NTHREADS {
        // `recv` 方法从通道中拿到一个消息
        // 若无可用消息的话，`recv` 将阻止当前线程
        ids.push(rx.recv());
    }

    // 显示已发送消息的次序
    println!("{:?}", ids);
}
<|endoftext|>


<commit_before>use derive_more::{Constructor, Deref, DerefMut};
use eyre::Result;
use inflector::cases::{camelcase::to_camel_case, snakecase::to_snake_case};
use schemars::JsonSchema;
use serde::{Deserialize, Deserializer, Serialize};
use std::any::type_name;
use std::collections::BTreeMap;
use std::{
    collections::VecDeque,
    fmt::{self, Debug},
    iter::FromIterator,
};
use strum::AsRefStr;
use thiserror::Error;

/// A slot, used as part of an [`Address`], to locate a value within a `Node` tree.
///
/// Slots can be used to identify a part of a larger object.
///
/// The `Name` variant can be used to identify:
///
/// - the property name of a `struct`
/// - the key of a `HashMap<String, ...>`
///
/// The `Integer` variant can be used to identify:
///
/// - the index of a `Vec`
/// - the index of a Unicode character in a `String`
///
/// The `None` variant is used in places where a `Slot` is required
/// but none applies to the particular type or use case.
///
/// In contrast to JSON Patch, which uses a [JSON Pointer](http://tools.ietf.org/html/rfc6901)
/// to describe the location of additions and removals, slots offer improved performance and
/// type safety.
#[derive(Debug, Clone, JsonSchema, Serialize, Deserialize, AsRefStr)]
#[serde(untagged)]
#[schemars(deny_unknown_fields)]
pub enum Slot {
    Index(usize),
    Name(String),
}

impl fmt::Display for Slot {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Slot::Name(name) => write!(formatter, "{}", name),
            Slot::Index(index) => write!(formatter, "{}", index),
        }
    }
}

/// The address, defined by a list of [`Slot`]s, of a value within `Node` tree.
///
/// Implemented as a double-ended queue. Given that addresses usually have less than
/// six slots it may be more performant to use a stack allocated `tinyvec` here instead.
///
/// Note: This could instead have be called a "Path", but that name was avoided because
/// of potential confusion with file system paths.
#[derive(Debug, Clone, Default, Constructor, Deref, DerefMut, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct Address(VecDeque<Slot>);

impl fmt::Display for Address {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        let me = self
            .iter()
            .map(|slot| slot.to_string())
            .collect::<Vec<String>>()
            .join(".");
        write!(formatter, "{}", me)
    }
}

impl Serialize for Address {
    /// Custom serialization to convert `Name` slots to camelCase
    ///
    /// This is done here for consistency with how Stencila Schema nodes are
    /// serialized using the Serde option `#[serde(rename_all = "camelCase")]`.
    ///
    /// It avoids incompatability with patches sent to the `web` module and the
    /// camelCase convention used for both DOM element attributed and JSON/JavaScript
    /// property names.
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let camel_cased: Vec<Slot> = self
            .iter()
            .map(|slot| match slot {
                Slot::Index(..) => slot.clone(),
                Slot::Name(name) => Slot::Name(to_camel_case(name)),
            })
            .collect();
        camel_cased.serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for Address {
    /// Custom deserialization to convert `Name` slots to snake_case
    ///
    /// See notes for `impl Serialize for Address`.
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let slots: Vec<Slot> = Deserialize::deserialize(deserializer)?;
        let snake_cased = slots.into_iter().map(|slot| match slot {
            Slot::Index(..) => slot,
            Slot::Name(name) => Slot::Name(to_snake_case(&name)),
        });
        Ok(Address(VecDeque::from_iter(snake_cased)))
    }
}

impl From<usize> for Address {
    fn from(index: usize) -> Address {
        Address(VecDeque::from_iter([Slot::Index(index)]))
    }
}

impl From<&str> for Address {
    fn from(name: &str) -> Address {
        Address(VecDeque::from_iter([Slot::Name(name.to_string())]))
    }
}

impl Address {
    /// Create an empty address
    pub fn empty() -> Self {
        Self::default()
    }

    /// Prepend an address with another
    pub fn prepend(&mut self, other: &Address) {
        *self = other.concat(self)
    }

    /// Concatenate an address with another into a new address
    pub fn concat(&self, other: &Address) -> Self {
        let mut concat = self.clone();
        concat.append(&mut other.clone());
        concat
    }
}

/// A map of node ids to their address
///
/// Used to enable faster access to a node based on it's id.
/// A `BTreeMap` is used instead of a `HashMap` for determinism in order
/// of entries.
pub type AddressMap = BTreeMap<String, Address>;

/// An enumeration of custom errors returned by this library
///
/// Where possible functions should return one of these errors to provide greater
/// context to the user, in particular regarding actions that can be taken to
/// resolve the error.
#[derive(Error, Debug, JsonSchema, Serialize)]
#[serde(tag = "type")]
#[schemars(deny_unknown_fields)]
pub enum Error {
    /// The user attempted to use an an address (e.g. in a patch operation) that
    /// is invalid address for the type.
    ///
    /// Does not include the address because in places that this error is used
    /// that is usually modified e.g. `pop_front`.
    #[error("Invalid address for node of type `{type_name}`: {details}")]
    InvalidAddress { type_name: String, details: String },

    /// The user attempted to use a slot with an invalid type for the
    /// node type (e.g. a `Slot::Name` on a `Vector`).
    #[error("Invalid slot type `{variant}` for node of type `{type_name}`")]
    InvalidSlotVariant { variant: String, type_name: String },

    /// The user attempted to use a slot with an invalid `Slot::Name`
    /// for the node type (e.g a key for a `HashMap` that is not occupied).
    #[error("Invalid address slot name `{name}` for node of type `{type_name}`")]
    InvalidSlotName { name: String, type_name: String },

    /// The user attempted to use a slot with an invalid `Slot::Index`
    /// for the node type (e.g an index that is greater than the size of a vector).
    #[error("Invalid address slot index `{index}` for node of type `{type_name}`")]
    InvalidSlotIndex { index: usize, type_name: String },
}

/// Create an `InvalidAddress` error
pub fn invalid_address<Type: ?Sized>(details: &str) -> Error {
    Error::InvalidAddress {
        type_name: type_name::<Type>().into(),
        details: details.into(),
    }
}

/// Create an `InvalidSlotVariant` error
pub fn invalid_slot_variant<Type: ?Sized>(slot: Slot) -> Error {
    Error::InvalidSlotVariant {
        variant: slot.as_ref().into(),
        type_name: type_name::<Type>().into(),
    }
}

/// Create an `InvalidSlotName` error
pub fn invalid_slot_name<Type: ?Sized>(name: &str) -> Error {
    Error::InvalidSlotName {
        name: name.into(),
        type_name: type_name::<Type>().into(),
    }
}

/// Create an `InvalidSlotIndex` error
pub fn invalid_slot_index<Type: ?Sized>(index: usize) -> Error {
    Error::InvalidSlotIndex {
        index,
        type_name: type_name::<Type>().into(),
    }
}
<commit_msg>feat(Node addresses): Add `add_name` and `add_index` methods<commit_after>use derive_more::{Constructor, Deref, DerefMut};
use eyre::Result;
use inflector::cases::{camelcase::to_camel_case, snakecase::to_snake_case};
use schemars::JsonSchema;
use serde::{Deserialize, Deserializer, Serialize};
use std::any::type_name;
use std::collections::BTreeMap;
use std::{
    collections::VecDeque,
    fmt::{self, Debug},
    iter::FromIterator,
};
use strum::AsRefStr;
use thiserror::Error;

/// A slot, used as part of an [`Address`], to locate a value within a `Node` tree.
///
/// Slots can be used to identify a part of a larger object.
///
/// The `Name` variant can be used to identify:
///
/// - the property name of a `struct`
/// - the key of a `HashMap<String, ...>`
///
/// The `Integer` variant can be used to identify:
///
/// - the index of a `Vec`
/// - the index of a Unicode character in a `String`
///
/// The `None` variant is used in places where a `Slot` is required
/// but none applies to the particular type or use case.
///
/// In contrast to JSON Patch, which uses a [JSON Pointer](http://tools.ietf.org/html/rfc6901)
/// to describe the location of additions and removals, slots offer improved performance and
/// type safety.
#[derive(Debug, Clone, JsonSchema, Serialize, Deserialize, AsRefStr)]
#[serde(untagged)]
#[schemars(deny_unknown_fields)]
pub enum Slot {
    Index(usize),
    Name(String),
}

impl fmt::Display for Slot {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Slot::Name(name) => write!(formatter, "{}", name),
            Slot::Index(index) => write!(formatter, "{}", index),
        }
    }
}

/// The address, defined by a list of [`Slot`]s, of a value within `Node` tree.
///
/// Implemented as a double-ended queue. Given that addresses usually have less than
/// six slots it may be more performant to use a stack allocated `tinyvec` here instead.
///
/// Note: This could instead have be called a "Path", but that name was avoided because
/// of potential confusion with file system paths.
#[derive(Debug, Clone, Default, Constructor, Deref, DerefMut, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct Address(VecDeque<Slot>);

impl fmt::Display for Address {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        let me = self
            .iter()
            .map(|slot| slot.to_string())
            .collect::<Vec<String>>()
            .join(".");
        write!(formatter, "{}", me)
    }
}

impl Serialize for Address {
    /// Custom serialization to convert `Name` slots to camelCase
    ///
    /// This is done here for consistency with how Stencila Schema nodes are
    /// serialized using the Serde option `#[serde(rename_all = "camelCase")]`.
    ///
    /// It avoids incompatability with patches sent to the `web` module and the
    /// camelCase convention used for both DOM element attributed and JSON/JavaScript
    /// property names.
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let camel_cased: Vec<Slot> = self
            .iter()
            .map(|slot| match slot {
                Slot::Index(..) => slot.clone(),
                Slot::Name(name) => Slot::Name(to_camel_case(name)),
            })
            .collect();
        camel_cased.serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for Address {
    /// Custom deserialization to convert `Name` slots to snake_case
    ///
    /// See notes for `impl Serialize for Address`.
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let slots: Vec<Slot> = Deserialize::deserialize(deserializer)?;
        let snake_cased = slots.into_iter().map(|slot| match slot {
            Slot::Index(..) => slot,
            Slot::Name(name) => Slot::Name(to_snake_case(&name)),
        });
        Ok(Address(VecDeque::from_iter(snake_cased)))
    }
}

impl From<usize> for Address {
    fn from(index: usize) -> Address {
        Address(VecDeque::from_iter([Slot::Index(index)]))
    }
}

impl From<&str> for Address {
    fn from(name: &str) -> Address {
        Address(VecDeque::from_iter([Slot::Name(name.to_string())]))
    }
}

impl Address {
    /// Create an empty address
    pub fn empty() -> Self {
        Self::default()
    }

    /// Prepend an address with another
    pub fn prepend(&mut self, other: &Self) {
        *self = other.concat(self)
    }

    /// Concatenate an address with another
    pub fn concat(&self, other: &Self) -> Self {
        let mut concat = self.clone();
        concat.append(&mut other.clone());
        concat
    }

    /// Add a name slot to an address
    pub fn add_name(&self, name: &str) -> Self {
        let mut added = self.clone();
        added.push_back(Slot::Name(name.to_string()));
        added
    }

    /// Add an index slot to an address
    pub fn add_index(&self, index: usize) -> Self {
        let mut added = self.clone();
        added.push_back(Slot::Index(index));
        added
    }
}

/// A map of node ids to their address
///
/// Used to enable faster access to a node based on it's id.
/// A `BTreeMap` is used instead of a `HashMap` for determinism in order
/// of entries.
pub type AddressMap = BTreeMap<String, Address>;

/// An enumeration of custom errors returned by this library
///
/// Where possible functions should return one of these errors to provide greater
/// context to the user, in particular regarding actions that can be taken to
/// resolve the error.
#[derive(Error, Debug, JsonSchema, Serialize)]
#[serde(tag = "type")]
#[schemars(deny_unknown_fields)]
pub enum Error {
    /// The user attempted to use an an address (e.g. in a patch operation) that
    /// is invalid address for the type.
    ///
    /// Does not include the address because in places that this error is used
    /// that is usually modified e.g. `pop_front`.
    #[error("Invalid address for node of type `{type_name}`: {details}")]
    InvalidAddress { type_name: String, details: String },

    /// The user attempted to use a slot with an invalid type for the
    /// node type (e.g. a `Slot::Name` on a `Vector`).
    #[error("Invalid slot type `{variant}` for node of type `{type_name}`")]
    InvalidSlotVariant { variant: String, type_name: String },

    /// The user attempted to use a slot with an invalid `Slot::Name`
    /// for the node type (e.g a key for a `HashMap` that is not occupied).
    #[error("Invalid address slot name `{name}` for node of type `{type_name}`")]
    InvalidSlotName { name: String, type_name: String },

    /// The user attempted to use a slot with an invalid `Slot::Index`
    /// for the node type (e.g an index that is greater than the size of a vector).
    #[error("Invalid address slot index `{index}` for node of type `{type_name}`")]
    InvalidSlotIndex { index: usize, type_name: String },
}

/// Create an `InvalidAddress` error
pub fn invalid_address<Type: ?Sized>(details: &str) -> Error {
    Error::InvalidAddress {
        type_name: type_name::<Type>().into(),
        details: details.into(),
    }
}

/// Create an `InvalidSlotVariant` error
pub fn invalid_slot_variant<Type: ?Sized>(slot: Slot) -> Error {
    Error::InvalidSlotVariant {
        variant: slot.as_ref().into(),
        type_name: type_name::<Type>().into(),
    }
}

/// Create an `InvalidSlotName` error
pub fn invalid_slot_name<Type: ?Sized>(name: &str) -> Error {
    Error::InvalidSlotName {
        name: name.into(),
        type_name: type_name::<Type>().into(),
    }
}

/// Create an `InvalidSlotIndex` error
pub fn invalid_slot_index<Type: ?Sized>(index: usize) -> Error {
    Error::InvalidSlotIndex {
        index,
        type_name: type_name::<Type>().into(),
    }
}
<|endoftext|>


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

#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

extern crate libc;

use libc::c_int;

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

#[no_mangle]
pub fn bz_internal_error(errcode: c_int) {
    panic!("bz internal error: {}", errcode);
}
<commit_msg>Conditionally define bzip2 error callback function<commit_after>// Copyright 2019 Tyler Neely, Alex Regueiro
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

extern crate libc;

use libc::c_int;

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

#[cfg(feature = "bzip2")]
#[no_mangle]
pub fn bz_internal_error(errcode: c_int) {
    panic!("bz internal error: {}", errcode);
}
<|endoftext|>


<commit_before>//! Completion for associated items in a trait implementation.
//!
//! This module adds the completion items related to implementing associated
//! items within a `impl Trait for Struct` block. The current context node
//! must be within either a `FN_DEF`, `TYPE_ALIAS_DEF`, or `CONST_DEF` node
//! and an direct child of an `IMPL_DEF`.
//!
//! # Examples
//!
//! Considering the following trait `impl`:
//!
//! ```ignore
//! trait SomeTrait {
//!     fn foo();
//! }
//!
//! impl SomeTrait for () {
//!     fn f<|>
//! }
//! ```
//!
//! may result in the completion of the following method:
//!
//! ```ignore
//! # trait SomeTrait {
//! #    fn foo();
//! # }
//!
//! impl SomeTrait for () {
//!     fn foo() {}<|>
//! }
//! ```

use hir::{self, Docs, HasSource};
use ra_assists::utils::get_missing_impl_items;
use ra_syntax::{
    ast::{self, edit, ImplDef},
    AstNode, SyntaxKind, SyntaxNode, TextRange, T,
};
use ra_text_edit::TextEdit;

use crate::{
    completion::{
        CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
    },
    display::FunctionSignature,
};

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    if let Some((trigger, impl_def)) = completion_match(ctx) {
        match trigger.kind() {
            SyntaxKind::NAME_REF => {
                get_missing_impl_items(&ctx.sema, &impl_def).iter().for_each(|item| match item {
                    hir::AssocItem::Function(fn_item) => {
                        add_function_impl(&trigger, acc, ctx, &fn_item)
                    }
                    hir::AssocItem::TypeAlias(type_item) => {
                        add_type_alias_impl(&trigger, acc, ctx, &type_item)
                    }
                    hir::AssocItem::Const(const_item) => {
                        add_const_impl(&trigger, acc, ctx, &const_item)
                    }
                })
            }

            SyntaxKind::FN_DEF => {
                for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map(
                    |item| match item {
                        hir::AssocItem::Function(fn_item) => Some(fn_item),
                        _ => None,
                    },
                ) {
                    add_function_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::TYPE_ALIAS_DEF => {
                for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map(
                    |item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None,
                    },
                ) {
                    add_type_alias_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::CONST_DEF => {
                for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map(
                    |item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None,
                    },
                ) {
                    add_const_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            _ => {}
        }
    }
}

fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, ImplDef)> {
    let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() {
        SyntaxKind::FN_DEF
        | SyntaxKind::TYPE_ALIAS_DEF
        | SyntaxKind::CONST_DEF
        | SyntaxKind::BLOCK_EXPR => Some((p, 2)),
        SyntaxKind::NAME_REF => Some((p, 5)),
        _ => None,
    })?;
    let impl_def = (0..impl_def_offset - 1)
        .try_fold(trigger.parent()?, |t, _| t.parent())
        .and_then(ast::ImplDef::cast)?;
    Some((trigger, impl_def))
}

fn add_function_impl(
    fn_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    func: &hir::Function,
) {
    let display = FunctionSignature::from_hir(ctx.db, *func);

    let fn_name = func.name(ctx.db).to_string();

    let label = if !func.params(ctx.db).is_empty() {
        format!("fn {}(..)", fn_name)
    } else {
        format!("fn {}()", fn_name)
    };

    let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
        .lookup_by(fn_name)
        .set_documentation(func.docs(ctx.db));

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };

    let snippet = format!("{} {{}}", display);

    let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end());

    builder.text_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc);
}

fn add_type_alias_impl(
    type_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: &hir::TypeAlias,
) {
    let alias_name = type_alias.name(ctx.db).to_string();

    let snippet = format!("type {} = ", alias_name);

    let range = TextRange::from_to(type_def_node.text_range().start(), ctx.source_range().end());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .text_edit(TextEdit::replace(range, snippet))
        .lookup_by(alias_name)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(
    const_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    const_: &hir::Const,
) {
    let const_name = const_.name(ctx.db).map(|n| n.to_string());

    if let Some(const_name) = const_name {
        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

        let range =
            TextRange::from_to(const_def_node.text_range().start(), ctx.source_range().end());

        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
            .text_edit(TextEdit::replace(range, snippet))
            .lookup_by(const_name)
            .kind(CompletionItemKind::Const)
            .set_documentation(const_.docs(ctx.db))
            .add_to(acc);
    }
}

fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
    let const_ = edit::remove_attrs_and_docs(const_);

    let const_start = const_.syntax().text_range().start();
    let const_end = const_.syntax().text_range().end();

    let start =
        const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start());

    let end = const_
        .syntax()
        .children_with_tokens()
        .find(|s| s.kind() == T![;] || s.kind() == T![=])
        .map_or(const_end, |f| f.text_range().start());

    let len = end - start;
    let range = TextRange::from_to(0.into(), len);

    let syntax = const_.syntax().text().slice(range).to_string();

    format!("{} = ", syntax.trim_end())
}

#[cfg(test)]
mod tests {
    use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;

    fn complete(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Magic)
    }

    #[test]
    fn name_ref_function_type_const() {
        let completions = complete(
            r"
            trait Test {
                type TestType;
                const TEST_CONST: u16;
                fn test();
            }

            struct T1;

            impl Test for T1 {
                t<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const TEST_CONST: u16 = ",
                source_range: [209; 210),
                delete: [209; 210),
                insert: "const TEST_CONST: u16 = ",
                kind: Const,
                lookup: "TEST_CONST",
            },
            CompletionItem {
                label: "fn test()",
                source_range: [209; 210),
                delete: [209; 210),
                insert: "fn test() {}",
                kind: Function,
                lookup: "test",
            },
            CompletionItem {
                label: "type TestType = ",
                source_range: [209; 210),
                delete: [209; 210),
                insert: "type TestType = ",
                kind: TypeAlias,
                lookup: "TestType",
            },
        ]
        "###);
    }

    #[test]
    fn no_nested_fn_completions() {
        let completions = complete(
            r"
            trait Test {
                fn test();
                fn test2();
            }

            struct T1;

            impl Test for T1 {
                fn test() {
                    t<|>
                }
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"[]"###);
    }

    #[test]
    fn name_ref_single_function() {
        let completions = complete(
            r"
            trait Test {
                fn test();
            }

            struct T1;

            impl Test for T1 {
                t<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn test()",
                source_range: [139; 140),
                delete: [139; 140),
                insert: "fn test() {}",
                kind: Function,
                lookup: "test",
            },
        ]
        "###);
    }

    #[test]
    fn single_function() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [141; 142),
                delete: [138; 142),
                insert: "fn foo() {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn hide_implemented_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {}

                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo_bar()",
                source_range: [200; 201),
                delete: [197; 201),
                insert: "fn foo_bar() {}",
                kind: Function,
                lookup: "foo_bar",
            },
        ]
        "###);
    }

    #[test]
    fn completes_only_on_top_level() {
        let completions = complete(
            r"
            trait Test {
                fn foo();

                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {
                    <|>
                }
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"[]"###);
    }

    #[test]
    fn generic_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [144; 145),
                delete: [141; 145),
                insert: "fn foo<T>() {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn generic_constrait_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>() where T: Into<String>;
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [166; 167),
                delete: [163; 167),
                insert: "fn foo<T>()\nwhere T: Into<String> {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn associated_type() {
        let completions = complete(
            r"
            trait Test {
                type SomeType;
            }

            impl Test for () {
                type S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "type SomeType = ",
                source_range: [124; 125),
                delete: [119; 125),
                insert: "type SomeType = ",
                kind: TypeAlias,
                lookup: "SomeType",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [133; 134),
                delete: [127; 134),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const_with_default() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16 = 42;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [138; 139),
                delete: [132; 139),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }
}
<commit_msg>Better snippet when completing trait method<commit_after>//! Completion for associated items in a trait implementation.
//!
//! This module adds the completion items related to implementing associated
//! items within a `impl Trait for Struct` block. The current context node
//! must be within either a `FN_DEF`, `TYPE_ALIAS_DEF`, or `CONST_DEF` node
//! and an direct child of an `IMPL_DEF`.
//!
//! # Examples
//!
//! Considering the following trait `impl`:
//!
//! ```ignore
//! trait SomeTrait {
//!     fn foo();
//! }
//!
//! impl SomeTrait for () {
//!     fn f<|>
//! }
//! ```
//!
//! may result in the completion of the following method:
//!
//! ```ignore
//! # trait SomeTrait {
//! #    fn foo();
//! # }
//!
//! impl SomeTrait for () {
//!     fn foo() {}<|>
//! }
//! ```

use hir::{self, Docs, HasSource};
use ra_assists::utils::get_missing_impl_items;
use ra_syntax::{
    ast::{self, edit, ImplDef},
    AstNode, SyntaxKind, SyntaxNode, TextRange, T,
};
use ra_text_edit::TextEdit;

use crate::{
    completion::{
        CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
    },
    display::FunctionSignature,
};

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    if let Some((trigger, impl_def)) = completion_match(ctx) {
        match trigger.kind() {
            SyntaxKind::NAME_REF => {
                get_missing_impl_items(&ctx.sema, &impl_def).iter().for_each(|item| match item {
                    hir::AssocItem::Function(fn_item) => {
                        add_function_impl(&trigger, acc, ctx, &fn_item)
                    }
                    hir::AssocItem::TypeAlias(type_item) => {
                        add_type_alias_impl(&trigger, acc, ctx, &type_item)
                    }
                    hir::AssocItem::Const(const_item) => {
                        add_const_impl(&trigger, acc, ctx, &const_item)
                    }
                })
            }

            SyntaxKind::FN_DEF => {
                for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map(
                    |item| match item {
                        hir::AssocItem::Function(fn_item) => Some(fn_item),
                        _ => None,
                    },
                ) {
                    add_function_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::TYPE_ALIAS_DEF => {
                for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map(
                    |item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None,
                    },
                ) {
                    add_type_alias_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::CONST_DEF => {
                for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map(
                    |item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None,
                    },
                ) {
                    add_const_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            _ => {}
        }
    }
}

fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, ImplDef)> {
    let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() {
        SyntaxKind::FN_DEF
        | SyntaxKind::TYPE_ALIAS_DEF
        | SyntaxKind::CONST_DEF
        | SyntaxKind::BLOCK_EXPR => Some((p, 2)),
        SyntaxKind::NAME_REF => Some((p, 5)),
        _ => None,
    })?;
    let impl_def = (0..impl_def_offset - 1)
        .try_fold(trigger.parent()?, |t, _| t.parent())
        .and_then(ast::ImplDef::cast)?;
    Some((trigger, impl_def))
}

fn add_function_impl(
    fn_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    func: &hir::Function,
) {
    let display = FunctionSignature::from_hir(ctx.db, *func);

    let fn_name = func.name(ctx.db).to_string();

    let label = if !func.params(ctx.db).is_empty() {
        format!("fn {}(..)", fn_name)
    } else {
        format!("fn {}()", fn_name)
    };

    let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
        .lookup_by(fn_name)
        .set_documentation(func.docs(ctx.db));

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };

    let snippet = format!("{} {{\n    $0\n}}", display);

    let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end());

    builder.snippet_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc);
}

fn add_type_alias_impl(
    type_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: &hir::TypeAlias,
) {
    let alias_name = type_alias.name(ctx.db).to_string();

    let snippet = format!("type {} = ", alias_name);

    let range = TextRange::from_to(type_def_node.text_range().start(), ctx.source_range().end());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .text_edit(TextEdit::replace(range, snippet))
        .lookup_by(alias_name)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(
    const_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    const_: &hir::Const,
) {
    let const_name = const_.name(ctx.db).map(|n| n.to_string());

    if let Some(const_name) = const_name {
        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

        let range =
            TextRange::from_to(const_def_node.text_range().start(), ctx.source_range().end());

        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
            .text_edit(TextEdit::replace(range, snippet))
            .lookup_by(const_name)
            .kind(CompletionItemKind::Const)
            .set_documentation(const_.docs(ctx.db))
            .add_to(acc);
    }
}

fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
    let const_ = edit::remove_attrs_and_docs(const_);

    let const_start = const_.syntax().text_range().start();
    let const_end = const_.syntax().text_range().end();

    let start =
        const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start());

    let end = const_
        .syntax()
        .children_with_tokens()
        .find(|s| s.kind() == T![;] || s.kind() == T![=])
        .map_or(const_end, |f| f.text_range().start());

    let len = end - start;
    let range = TextRange::from_to(0.into(), len);

    let syntax = const_.syntax().text().slice(range).to_string();

    format!("{} = ", syntax.trim_end())
}

#[cfg(test)]
mod tests {
    use insta::assert_debug_snapshot;

    use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};

    fn complete(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Magic)
    }

    #[test]
    fn name_ref_function_type_const() {
        let completions = complete(
            r"
            trait Test {
                type TestType;
                const TEST_CONST: u16;
                fn test();
            }

            struct T1;

            impl Test for T1 {
                t<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const TEST_CONST: u16 = ",
                source_range: [209; 210),
                delete: [209; 210),
                insert: "const TEST_CONST: u16 = ",
                kind: Const,
                lookup: "TEST_CONST",
            },
            CompletionItem {
                label: "fn test()",
                source_range: [209; 210),
                delete: [209; 210),
                insert: "fn test() {\n    $0\n}",
                kind: Function,
                lookup: "test",
            },
            CompletionItem {
                label: "type TestType = ",
                source_range: [209; 210),
                delete: [209; 210),
                insert: "type TestType = ",
                kind: TypeAlias,
                lookup: "TestType",
            },
        ]
        "###);
    }

    #[test]
    fn no_nested_fn_completions() {
        let completions = complete(
            r"
            trait Test {
                fn test();
                fn test2();
            }

            struct T1;

            impl Test for T1 {
                fn test() {
                    t<|>
                }
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"[]"###);
    }

    #[test]
    fn name_ref_single_function() {
        let completions = complete(
            r"
            trait Test {
                fn test();
            }

            struct T1;

            impl Test for T1 {
                t<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn test()",
                source_range: [139; 140),
                delete: [139; 140),
                insert: "fn test() {\n    $0\n}",
                kind: Function,
                lookup: "test",
            },
        ]
        "###);
    }

    #[test]
    fn single_function() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [141; 142),
                delete: [138; 142),
                insert: "fn foo() {\n    $0\n}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn hide_implemented_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {}

                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo_bar()",
                source_range: [200; 201),
                delete: [197; 201),
                insert: "fn foo_bar() {\n    $0\n}",
                kind: Function,
                lookup: "foo_bar",
            },
        ]
        "###);
    }

    #[test]
    fn completes_only_on_top_level() {
        let completions = complete(
            r"
            trait Test {
                fn foo();

                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {
                    <|>
                }
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"[]"###);
    }

    #[test]
    fn generic_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [144; 145),
                delete: [141; 145),
                insert: "fn foo<T>() {\n    $0\n}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn generic_constrait_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>() where T: Into<String>;
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [166; 167),
                delete: [163; 167),
                insert: "fn foo<T>()\nwhere T: Into<String> {\n    $0\n}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn associated_type() {
        let completions = complete(
            r"
            trait Test {
                type SomeType;
            }

            impl Test for () {
                type S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "type SomeType = ",
                source_range: [124; 125),
                delete: [119; 125),
                insert: "type SomeType = ",
                kind: TypeAlias,
                lookup: "SomeType",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [133; 134),
                delete: [127; 134),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const_with_default() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16 = 42;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [138; 139),
                delete: [132; 139),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }
}
<|endoftext|>


<commit_before>pub use self::association::{UdpAssociationManager, UdpInboundWrite};

pub mod association;

/// Packet size for all UDP associations' send queue
pub static UDP_ASSOCIATION_SEND_CHANNEL_SIZE: usize = 8192;

/// Keep-alive channel size for UDP associations' manager
pub static UDP_ASSOCIATION_KEEP_ALIVE_CHANNEL_SIZE: usize = 256;
<commit_msg>constants should be defined with const<commit_after>pub use self::association::{UdpAssociationManager, UdpInboundWrite};

pub mod association;

/// Packet size for all UDP associations' send queue
pub const UDP_ASSOCIATION_SEND_CHANNEL_SIZE: usize = 4096;

/// Keep-alive channel size for UDP associations' manager
pub const UDP_ASSOCIATION_KEEP_ALIVE_CHANNEL_SIZE: usize = 256;
<|endoftext|>


<commit_before>#[derive(Debug, Clone)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

//for red-black tree
#[derive(Debug, Clone)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug, Clone)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }
}

type ReTr<'a> = Result<&'a mut Tree, String>;

impl Tree {
    fn new(v: &i32) -> Tree {
        Tree {
            enter: Node::new(v),
            left: None,
            right: None,
        }
    }

    fn insert(&mut self, v: &i32) {
        let target = if *v > self.enter.val {
            &mut self.right
        } else {
            &mut self.left
        };
        //println!("target is -> {:?}", target);
        match target {
            Some(next) => {
                //println!("next is -> {:?}", &next);
                next.insert(v)
            }
            None => {
                let new_node = Node::new(v);
                let new_tree = Tree {
                    enter: new_node,
                    left: None,
                    right: None,
                };
                *target = Some(Box::new(new_tree));
            }
        }
    }

    fn look_up_recursive(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.left.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> ReTr {
        let mut this: &mut Self = self;
        loop {
            if *v == this.enter.val {
                return Ok(this);
            } else if *v > this.enter.val {
                if let None = this.right {
                    return Err("not find".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return Err("not find".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn look_up_father(&mut self, v: &i32) -> (ReTr, String) {
        let mut this: &mut Self = self;
        loop {
            if *v == this.right.as_ref().unwrap().enter.val {
                return (Ok(this), "right".to_string());
            } else if *v == this.right.as_ref().unwrap().enter.val {
                return (Ok(this), "left".to_string());
            } else if *v > this.enter.val {
                if let None = this.right {
                    return (Err("not find".to_string()), "Error".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return (Err("not find".to_string()), "Error".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn left_shift(&mut self, v: &i32) {}
}

fn main() {
    let mut a = Tree::new(&3);
    a.insert(&2);
    a.insert(&1);
    a.insert(&4);
    a.insert(&5);

    //println!("{:?}", a);
    //println!("{:?}", a.look_up(&1));
    println!("{:?}", a.look_up_father(&4));
    //println!("{:?}", a);
}
<commit_msg>finish left shift<commit_after>#[derive(Debug, Clone)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

//for red-black tree
#[derive(Debug, Clone)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug, Clone)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }
}

type ReTr<'a> = Result<&'a mut Tree, String>;

impl Tree {
    fn new(v: &i32) -> Tree {
        Tree {
            enter: Node::new(v),
            left: None,
            right: None,
        }
    }

    fn insert(&mut self, v: &i32) {
        let target = if *v > self.enter.val {
            &mut self.right
        } else {
            &mut self.left
        };
        //println!("target is -> {:?}", target);
        match target {
            Some(next) => {
                //println!("next is -> {:?}", &next);
                next.insert(v)
            }
            None => {
                let new_node = Node::new(v);
                let new_tree = Tree {
                    enter: new_node,
                    left: None,
                    right: None,
                };
                *target = Some(Box::new(new_tree));
            }
        }
    }

    fn look_up_recursive(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.left.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> ReTr {
        let mut this: &mut Self = self;
        loop {
            if *v == this.enter.val {
                return Ok(this);
            } else if *v > this.enter.val {
                if let None = this.right {
                    return Err("not find".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return Err("not find".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn look_up_father(&mut self, v: &i32) -> (ReTr, String) {
        let mut this: &mut Self = self;
        loop {
            if *v == this.right.as_ref().unwrap().enter.val {
                return (Ok(this), "right".to_string());
            } else if *v == this.left.as_ref().unwrap().enter.val {
                return (Ok(this), "left".to_string());
            } else if *v > this.enter.val {
                if let None = this.right {
                    return (Err("not find".to_string()), "Error".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return (Err("not find".to_string()), "Error".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn cut_left_tree(&mut self) -> Box<Self> {
        self.left.clone().unwrap()
    }

    fn cut_right_tree(&mut self) -> Box<Self> {
        self.right.clone().unwrap()
    }

    fn left_shift(&mut self, v: &i32) {
        let father = self.look_up_father(v).0.unwrap();
        let mut this = father.cut_left_tree();
        let mut son = this.cut_right_tree();
        let grand_son = son.cut_left_tree();

        this.right = Some(grand_son);
        son.left = Some(this);
        father.left = Some(son);
    }
}

fn main() {
    //let mut a = Tree::new(&3);
    //a.insert(&2);
    //a.insert(&1);
    //a.insert(&4);
    //a.insert(&5);

    //println!("{:?}", a);
    //println!("{:?}", a.look_up(&1));
    //println!("{:?}", a.look_up_father(&4));
    //println!("{:?}", a);

    let mut b = Tree::new(&10);
    b.insert(&2);
    b.insert(&1);
    b.insert(&5);
    b.insert(&3);
    b.insert(&6);
    b.insert(&11);

    //println!("{:?}", b);
    //println!("{:?}", b.look_up_father(&2));
    b.left_shift(&2);
    println!("{:?}", b);
}
<|endoftext|>


<commit_before>use super::IntegPointData;
use crate::shapes::Scratchpad;
use crate::StrError;
use russell_lab::{Matrix, Vector};

/// Implements the shape(N) times scalar(S) times shape(N) integration case 01 (boundary integral version)
///
/// Diffusion coefficients:
///
/// ```text
///       ⌠
/// Kᵐⁿ = │ Nᵐ s Nⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
///
/// The numerical integration is:
///
/// ```text
///       nip-1    →     →      →       →
/// Kᵐⁿ ≈   Σ   Nᵐ(ιᵖ) s(ιᵖ) Nⁿ(ιᵖ) |J|(ιᵖ) wᵖ
///        p=0
/// ```
///
/// # Output
///
/// ```text
///     ┌                     ┐
///     | K⁰⁰ K⁰¹ K⁰² ··· K⁰ⁿ |  ⟸  ii0
///     | K¹⁰ K¹¹ K¹² ··· K¹ⁿ |
/// K = | K²⁰ K²¹ K²² ··· K²ⁿ |
///     |  ··  ··  ·· ···  ·· |
///     | Kᵐ⁰ Kᵐ¹ Kᵐ² ··· Kᵐⁿ |  ⟸  ii
///     └                     ┘
///        ⇑                ⇑
///       jj0               jj
/// ```
///
/// * `kk` -- A matrix containing all `Kᵐⁿ` values, one after another, and
///   sequentially placed as shown above. `m` and `n` are the indices of the nodes.
///   The dimensions must be `nrow(K) ≥ ii0 + nnode` and `ncol(K) ≥ jj0 + nnode`
/// * `pad` -- Some members of the scratchpad will be modified.
///
/// # Input
///
/// * `ii0` -- Stride marking the first row in the output matrix where to add components.
/// * `jj0` -- Stride marking the first column in the output matrix where to add components.
/// * `clear_kk` -- Fills `kk` matrix with zeros, otherwise accumulate values into `kk`
/// * `ips` -- Integration points (n_integ_point)
/// * `fn_s` -- Function `f(p)` that computes `s(x(ιᵖ))` with `0 ≤ p ≤ n_integ_point`
pub fn mat_01_nsn_bry<F>(
    kk: &mut Matrix,
    pad: &mut Scratchpad,
    ii0: usize,
    jj0: usize,
    clear_kk: bool,
    ips: IntegPointData,
    fn_s: F,
) -> Result<(), StrError>
where
    F: Fn(usize) -> Result<f64, StrError>,
{
    // check
    let (space_ndim, nnode) = pad.xxt.dims();
    if space_ndim == 2 && pad.kind.ndim() != 1 {
        return Err("in 2D, geometry ndim must be 1 (a line)");
    }
    if space_ndim == 3 && pad.kind.ndim() != 2 {
        return Err("in 3D, geometry ndim must be 2 (a surface)");
    }
    let (nrow_kk, ncol_kk) = kk.dims();
    if nrow_kk < ii0 + nnode {
        return Err("nrow(K) must be ≥ ii0 + nnode");
    }
    if ncol_kk < jj0 + nnode {
        return Err("ncol(K) must be ≥ jj0 + nnode");
    }

    // allocate auxiliary vector
    let mut un = Vector::new(space_ndim); // unit normal vector

    // clear output matrix
    if clear_kk {
        kk.fill(0.0);
    }

    // loop over integration points
    for p in 0..ips.len() {
        // ksi coordinates and weight
        let iota = &ips[p];
        let weight = ips[p][3];

        // calculate interpolation functions and Jacobian
        (pad.fn_interp)(&mut pad.interp, iota);
        let mag_n = pad.calc_normal_vector(&mut un, iota)?;

        // calculate s
        let s = fn_s(p)?;

        // add contribution to K matrix
        let val = s * mag_n * weight;
        let nn = &pad.interp;
        for m in 0..nnode {
            for n in 0..nnode {
                kk[ii0 + m][jj0 + n] += nn[m] * val * nn[n];
            }
        }
    }
    Ok(())
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::integ::testing::aux;
    use crate::integ::{self, AnalyticalTri3, IP_LIN_LEGENDRE_1, IP_TRI_INTERNAL_1};
    use crate::shapes::{GeoClass, GeoKind, Scratchpad};
    use russell_chk::assert_vec_approx_eq;
    use russell_lab::Matrix;

    #[test]
    fn capture_some_errors() {
        let mut pad = aux::gen_pad_lin2(1.0);
        let mut kk = Matrix::new(2, 2);
        assert_eq!(
            integ::mat_01_nsn_bry(&mut kk, &mut pad, 1, 0, false, &[], |_| Ok(0.0)).err(),
            Some("nrow(K) must be ≥ ii0 + nnode")
        );
        assert_eq!(
            integ::mat_01_nsn_bry(&mut kk, &mut pad, 0, 1, false, &[], |_| Ok(0.0)).err(),
            Some("ncol(K) must be ≥ jj0 + nnode")
        );
        // more errors
        assert_eq!(
            integ::mat_01_nsn_bry(&mut kk, &mut pad, 0, 0, false, &IP_LIN_LEGENDRE_1, |_| Ok(0.0)).err(),
            Some("calc_gradient requires that geo_ndim = space_ndim")
        );
        let mut pad = aux::gen_pad_tri3();
        let mut kk = Matrix::new(3, 3);
        assert_eq!(
            integ::mat_01_nsn_bry(&mut kk, &mut pad, 0, 0, false, &IP_TRI_INTERNAL_1, |_| Err("stop")).err(),
            Some("stop")
        );
    }

    /// Returns the scratchpad for a Tri3's side
    ///
    /// **Important:** `side` must be 0, 1, or 2
    fn tri3_extract_pad_side(pad: &Scratchpad, side: usize) -> Scratchpad {
        let mut pad_side = Scratchpad::new(2, GeoKind::Lin2).unwrap();
        for i in 0..2 {
            let m = pad.kind.edge_node_id(side, i);
            pad_side.set_xx(i, 0, pad.xxt[0][m]);
            pad_side.set_xx(i, 1, pad.xxt[1][m]);
        }
        pad_side
    }

    #[test]
    fn mat_01_nsn_bry_tri3_works() {
        let pad = aux::gen_pad_tri3();
        let s = 12.0;
        let ana = AnalyticalTri3::new(&pad);
        let ips = integ::points(GeoClass::Lin, 2).unwrap();

        // side # 0
        let mut pad_side = tri3_extract_pad_side(&pad, 0);
        let kk_correct = ana.mat_01_nsn_bry(0, s);
        let mut kk = Matrix::new(2, 2);
        integ::mat_01_nsn_bry(&mut kk, &mut pad_side, 0, 0, true, ips, |_| Ok(s)).unwrap();
        assert_vec_approx_eq!(kk.as_data(), kk_correct.as_data(), 1e-15);

        // side # 1
        let mut pad_side = tri3_extract_pad_side(&pad, 1);
        let kk_correct = ana.mat_01_nsn_bry(1, s);
        integ::mat_01_nsn_bry(&mut kk, &mut pad_side, 0, 0, true, ips, |_| Ok(s)).unwrap();
        assert_vec_approx_eq!(kk.as_data(), kk_correct.as_data(), 1e-14);

        // side # 2
        let mut pad_side = tri3_extract_pad_side(&pad, 2);
        let kk_correct = ana.mat_01_nsn_bry(2, s);
        integ::mat_01_nsn_bry(&mut kk, &mut pad_side, 0, 0, true, ips, |_| Ok(s)).unwrap();
        assert_vec_approx_eq!(kk.as_data(), kk_correct.as_data(), 1e-14);
    }
}
<commit_msg>Add tests for mat_01_nsn_bry<commit_after>use super::IntegPointData;
use crate::shapes::Scratchpad;
use crate::StrError;
use russell_lab::{Matrix, Vector};

/// Implements the shape(N) times scalar(S) times shape(N) integration case 01 (boundary integral version)
///
/// Diffusion coefficients:
///
/// ```text
///       ⌠
/// Kᵐⁿ = │ Nᵐ s Nⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
///
/// The numerical integration is:
///
/// ```text
///       nip-1    →     →      →       →
/// Kᵐⁿ ≈   Σ   Nᵐ(ιᵖ) s(ιᵖ) Nⁿ(ιᵖ) |J|(ιᵖ) wᵖ
///        p=0
/// ```
///
/// # Output
///
/// ```text
///     ┌                     ┐
///     | K⁰⁰ K⁰¹ K⁰² ··· K⁰ⁿ |  ⟸  ii0
///     | K¹⁰ K¹¹ K¹² ··· K¹ⁿ |
/// K = | K²⁰ K²¹ K²² ··· K²ⁿ |
///     |  ··  ··  ·· ···  ·· |
///     | Kᵐ⁰ Kᵐ¹ Kᵐ² ··· Kᵐⁿ |  ⟸  ii
///     └                     ┘
///        ⇑                ⇑
///       jj0               jj
/// ```
///
/// * `kk` -- A matrix containing all `Kᵐⁿ` values, one after another, and
///   sequentially placed as shown above. `m` and `n` are the indices of the nodes.
///   The dimensions must be `nrow(K) ≥ ii0 + nnode` and `ncol(K) ≥ jj0 + nnode`
/// * `pad` -- Some members of the scratchpad will be modified.
///
/// # Input
///
/// * `ii0` -- Stride marking the first row in the output matrix where to add components.
/// * `jj0` -- Stride marking the first column in the output matrix where to add components.
/// * `clear_kk` -- Fills `kk` matrix with zeros, otherwise accumulate values into `kk`
/// * `ips` -- Integration points (n_integ_point)
/// * `fn_s` -- Function `f(p)` that computes `s(x(ιᵖ))` with `0 ≤ p ≤ n_integ_point`
pub fn mat_01_nsn_bry<F>(
    kk: &mut Matrix,
    pad: &mut Scratchpad,
    ii0: usize,
    jj0: usize,
    clear_kk: bool,
    ips: IntegPointData,
    fn_s: F,
) -> Result<(), StrError>
where
    F: Fn(usize) -> Result<f64, StrError>,
{
    // check
    let (space_ndim, nnode) = pad.xxt.dims();
    if space_ndim == 2 && pad.kind.ndim() != 1 {
        return Err("in 2D, geometry ndim must be 1 (a line)");
    }
    if space_ndim == 3 && pad.kind.ndim() != 2 {
        return Err("in 3D, geometry ndim must be 2 (a surface)");
    }
    let (nrow_kk, ncol_kk) = kk.dims();
    if nrow_kk < ii0 + nnode {
        return Err("nrow(K) must be ≥ ii0 + nnode");
    }
    if ncol_kk < jj0 + nnode {
        return Err("ncol(K) must be ≥ jj0 + nnode");
    }

    // allocate auxiliary vector
    let mut un = Vector::new(space_ndim); // unit normal vector

    // clear output matrix
    if clear_kk {
        kk.fill(0.0);
    }

    // loop over integration points
    for p in 0..ips.len() {
        // ksi coordinates and weight
        let iota = &ips[p];
        let weight = ips[p][3];

        // calculate interpolation functions and Jacobian
        (pad.fn_interp)(&mut pad.interp, iota);
        let mag_n = pad.calc_normal_vector(&mut un, iota)?;

        // calculate s
        let s = fn_s(p)?;

        // add contribution to K matrix
        let val = s * mag_n * weight;
        let nn = &pad.interp;
        for m in 0..nnode {
            for n in 0..nnode {
                kk[ii0 + m][jj0 + n] += nn[m] * val * nn[n];
            }
        }
    }
    Ok(())
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::integ::testing::aux;
    use crate::integ::{self, AnalyticalTri3, IP_TRI_INTERNAL_1};
    use crate::shapes::{GeoClass, GeoKind, Scratchpad};
    use russell_chk::assert_vec_approx_eq;
    use russell_lab::Matrix;

    #[test]
    fn capture_some_errors() {
        let mut pad = aux::gen_pad_tri3();
        let mut kk = Matrix::new(3, 3);
        assert_eq!(
            integ::mat_01_nsn_bry(&mut kk, &mut pad, 0, 0, false, &[], |_| Ok(0.0)).err(),
            Some("in 2D, geometry ndim must be 1 (a line)")
        );
        let mut pad = aux::gen_pad_tet4();
        let mut kk = Matrix::new(4, 4);
        assert_eq!(
            integ::mat_01_nsn_bry(&mut kk, &mut pad, 0, 0, false, &[], |_| Ok(0.0)).err(),
            Some("in 3D, geometry ndim must be 2 (a surface)")
        );
        let mut pad = aux::gen_pad_lin2(1.0);
        let mut kk = Matrix::new(2, 2);
        assert_eq!(
            integ::mat_01_nsn_bry(&mut kk, &mut pad, 1, 0, false, &[], |_| Ok(0.0)).err(),
            Some("nrow(K) must be ≥ ii0 + nnode")
        );
        assert_eq!(
            integ::mat_01_nsn_bry(&mut kk, &mut pad, 0, 1, false, &[], |_| Ok(0.0)).err(),
            Some("ncol(K) must be ≥ jj0 + nnode")
        );
        assert_eq!(
            integ::mat_01_nsn_bry(&mut kk, &mut pad, 0, 0, false, &IP_TRI_INTERNAL_1, |_| Err("stop")).err(),
            Some("stop")
        );
    }

    /// Returns the scratchpad for a Tri3's side
    ///
    /// **Important:** `side` must be 0, 1, or 2
    fn tri3_extract_pad_side(pad: &Scratchpad, side: usize) -> Scratchpad {
        let mut pad_side = Scratchpad::new(2, GeoKind::Lin2).unwrap();
        for i in 0..2 {
            let m = pad.kind.edge_node_id(side, i);
            pad_side.set_xx(i, 0, pad.xxt[0][m]);
            pad_side.set_xx(i, 1, pad.xxt[1][m]);
        }
        pad_side
    }

    #[test]
    fn mat_01_nsn_bry_tri3_works() {
        let pad = aux::gen_pad_tri3();
        let s = 12.0;
        let ana = AnalyticalTri3::new(&pad);
        let ips = integ::points(GeoClass::Lin, 2).unwrap();

        // side # 0
        let mut pad_side = tri3_extract_pad_side(&pad, 0);
        let kk_correct = ana.mat_01_nsn_bry(0, s);
        let mut kk = Matrix::new(2, 2);
        integ::mat_01_nsn_bry(&mut kk, &mut pad_side, 0, 0, true, ips, |_| Ok(s)).unwrap();
        assert_vec_approx_eq!(kk.as_data(), kk_correct.as_data(), 1e-15);

        // side # 1
        let mut pad_side = tri3_extract_pad_side(&pad, 1);
        let kk_correct = ana.mat_01_nsn_bry(1, s);
        integ::mat_01_nsn_bry(&mut kk, &mut pad_side, 0, 0, true, ips, |_| Ok(s)).unwrap();
        assert_vec_approx_eq!(kk.as_data(), kk_correct.as_data(), 1e-14);

        // side # 2
        let mut pad_side = tri3_extract_pad_side(&pad, 2);
        let kk_correct = ana.mat_01_nsn_bry(2, s);
        integ::mat_01_nsn_bry(&mut kk, &mut pad_side, 0, 0, true, ips, |_| Ok(s)).unwrap();
        assert_vec_approx_eq!(kk.as_data(), kk_correct.as_data(), 1e-14);
    }
}
<|endoftext|>