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

use std::borrow::Cow;
use std::fmt;
use std::io::Write;
use std::mem;

use syn;

use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::dependencies::Dependencies;
use bindgen::ir::{
    AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path,
    Struct, ToCondition, Type,
};
use bindgen::library::Library;
use bindgen::writer::{Source, SourceWriter};
use bindgen::Bindings;

#[derive(Debug, Clone)]
pub enum Literal {
    Expr(String),
    BinOp {
        left: Box<Literal>,
        op: &'static str,
        right: Box<Literal>,
    },
    Struct {
        path: Path,
        export_name: String,
        fields: Vec<(String, Literal)>,
    },
}

impl Literal {
    fn replace_self_with(&mut self, self_ty: &Path) {
        match *self {
            Literal::BinOp { .. } | Literal::Expr(..) => {}
            Literal::Struct {
                ref mut path,
                ref mut export_name,
                ref mut fields,
            } => {
                if path.replace_self_with(self_ty) {
                    *export_name = self_ty.name().to_owned();
                }
                for &mut (ref _name, ref mut expr) in fields {
                    expr.replace_self_with(self_ty);
                }
            }
        }
    }

    fn is_valid(&self, bindings: &Bindings) -> bool {
        match *self {
            Literal::Expr(..) => true,
            Literal::BinOp {
                ref left,
                ref right,
                ..
            } => left.is_valid(bindings) && right.is_valid(bindings),
            Literal::Struct { ref path, .. } => bindings.struct_exists(path),
        }
    }
}

impl fmt::Display for Literal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Literal::Expr(v) => write!(f, "{}", v),
            Literal::BinOp {
                ref left,
                op,
                ref right,
            } => write!(f, "{} {} {}", left, op, right),
            Literal::Struct {
                path: _,
                export_name,
                fields,
            } => write!(
                f,
                "({}){{ {} }}",
                export_name,
                fields
                    .iter()
                    .map(|(key, lit)| format!(".{} = {}", key, lit))
                    .collect::<Vec<String>>()
                    .join(", "),
            ),
        }
    }
}

impl Literal {
    pub fn rename_for_config(&mut self, config: &Config) {
        match self {
            Literal::Struct {
                path: _,
                ref mut export_name,
                fields,
            } => {
                config.export.rename(export_name);
                for (_, lit) in fields {
                    lit.rename_for_config(config);
                }
            }
            Literal::BinOp {
                ref mut left,
                ref mut right,
                ..
            } => {
                left.rename_for_config(config);
                right.rename_for_config(config);
            }
            Literal::Expr(_) => {}
        }
    }

    pub fn load(expr: &syn::Expr) -> Result<Literal, String> {
        match *expr {
            syn::Expr::Binary(ref bin_expr) => {
                let l = Self::load(&bin_expr.left)?;
                let r = Self::load(&bin_expr.right)?;
                let op = match bin_expr.op {
                    syn::BinOp::Add(..) => "+",
                    syn::BinOp::Sub(..) => "-",
                    syn::BinOp::Mul(..) => "*",
                    syn::BinOp::Div(..) => "/",
                    syn::BinOp::Rem(..) => "%",
                    syn::BinOp::Shl(..) => "<<",
                    syn::BinOp::Shr(..) => ">>",
                    _ => return Err(format!("Unsupported binary op {:?}", bin_expr.op)),
                };
                Ok(Literal::BinOp {
                    left: Box::new(l),
                    op,
                    right: Box::new(r),
                })
            }
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Str(ref value),
                ..
            }) => Ok(Literal::Expr(format!("u8\"{}\"", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Byte(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Char(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Int(ref value),
                ..
            }) => match value.suffix() {
                syn::IntSuffix::Usize
                | syn::IntSuffix::U8
                | syn::IntSuffix::U16
                | syn::IntSuffix::U32
                | syn::IntSuffix::U64
                | syn::IntSuffix::U128
                | syn::IntSuffix::None => Ok(Literal::Expr(format!("{}", value.value()))),
                syn::IntSuffix::Isize
                | syn::IntSuffix::I8
                | syn::IntSuffix::I16
                | syn::IntSuffix::I32
                | syn::IntSuffix::I64
                | syn::IntSuffix::I128 => unsafe {
                    Ok(Literal::Expr(format!(
                        "{}",
                        mem::transmute::<u64, i64>(value.value())
                    )))
                },
            },
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Float(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Bool(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value))),

            syn::Expr::Struct(syn::ExprStruct {
                ref path,
                ref fields,
                ..
            }) => {
                let struct_name = path.segments[0].ident.to_string();
                let mut field_pairs: Vec<(String, Literal)> = Vec::new();
                for field in fields {
                    let ident = match field.member {
                        syn::Member::Named(ref name) => name.to_string(),
                        syn::Member::Unnamed(ref index) => format!("_{}", index.index),
                    };
                    let key = ident.to_string();
                    let value = Literal::load(&field.expr)?;
                    field_pairs.push((key, value));
                }
                Ok(Literal::Struct {
                    path: Path::new(struct_name.clone()),
                    export_name: struct_name,
                    fields: field_pairs,
                })
            }
            _ => Err("Unsupported literal expression.".to_owned()),
        }
    }
}

#[derive(Debug, Clone)]
pub struct Constant {
    pub path: Path,
    pub export_name: String,
    pub ty: Type,
    pub value: Literal,
    pub cfg: Option<Cfg>,
    pub annotations: AnnotationSet,
    pub documentation: Documentation,
    pub associated_to: Option<Path>,
}

fn can_handle(ty: &Type, expr: &syn::Expr) -> bool {
    if ty.is_primitive_or_ptr_primitive() {
        return true;
    }
    match *expr {
        syn::Expr::Struct(_) => true,
        _ => false,
    }
}

impl Constant {
    pub fn load(
        path: Path,
        mod_cfg: Option<&Cfg>,
        ty: &syn::Type,
        expr: &syn::Expr,
        attrs: &[syn::Attribute],
        associated_to: Option<Path>,
    ) -> Result<Constant, String> {
        let ty = Type::load(ty)?;
        let mut ty = match ty {
            Some(ty) => ty,
            None => {
                return Err("Cannot have a zero sized const definition.".to_owned());
            }
        };

        if !can_handle(&ty, expr) {
            return Err("Unhandled const definition".to_owned());
        }

        let mut lit = Literal::load(&expr)?;

        if let Some(ref associated_to) = associated_to {
            ty.replace_self_with(associated_to);
            lit.replace_self_with(associated_to);
        }

        Ok(Constant::new(
            path,
            ty,
            lit,
            Cfg::append(mod_cfg, Cfg::load(attrs)),
            AnnotationSet::load(attrs)?,
            Documentation::load(attrs),
            associated_to,
        ))
    }

    pub fn new(
        path: Path,
        ty: Type,
        value: Literal,
        cfg: Option<Cfg>,
        annotations: AnnotationSet,
        documentation: Documentation,
        associated_to: Option<Path>,
    ) -> Self {
        let export_name = path.name().to_owned();
        Self {
            path,
            export_name,
            ty,
            value,
            cfg,
            annotations,
            documentation,
            associated_to,
        }
    }
}

impl Item for Constant {
    fn path(&self) -> &Path {
        &self.path
    }

    fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
        self.ty.add_dependencies(library, out);
    }

    fn export_name(&self) -> &str {
        &self.export_name
    }

    fn cfg(&self) -> Option<&Cfg> {
        self.cfg.as_ref()
    }

    fn annotations(&self) -> &AnnotationSet {
        &self.annotations
    }

    fn annotations_mut(&mut self) -> &mut AnnotationSet {
        &mut self.annotations
    }

    fn container(&self) -> ItemContainer {
        ItemContainer::Constant(self.clone())
    }

    fn rename_for_config(&mut self, config: &Config) {
        if self.associated_to.is_none() {
            config.export.rename(&mut self.export_name);
        }
        self.value.rename_for_config(config);
        self.ty.rename_for_config(config, &GenericParams::default()); // FIXME: should probably propagate something here
    }

    fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
        self.ty.resolve_declaration_types(resolver);
    }
}

impl Constant {
    pub fn write_declaration<F: Write>(
        &self,
        config: &Config,
        out: &mut SourceWriter<F>,
        associated_to_struct: &Struct,
    ) {
        debug_assert!(self.associated_to.is_some());
        debug_assert!(config.language == Language::Cxx);
        debug_assert!(!associated_to_struct.is_transparent);
        debug_assert!(config.structure.associated_constants_in_body);
        debug_assert!(config.constant.allow_static_const);

        if let Type::ConstPtr(..) = self.ty {
            out.write("static ");
        } else {
            out.write("static const ");
        }
        self.ty.write(config, out);
        write!(out, " {};", self.export_name())
    }

    pub fn write<F: Write>(
        &self,
        config: &Config,
        out: &mut SourceWriter<F>,
        associated_to_struct: Option<&Struct>,
    ) {
        if let Some(assoc) = associated_to_struct {
            if assoc.is_generic() {
                return; // Not tested / implemented yet, so bail out.
            }
        }

        if !self.value.is_valid(out.bindings()) {
            return;
        }

        let associated_to_transparent = associated_to_struct.map_or(false, |s| s.is_transparent);

        let in_body = associated_to_struct.is_some()
            && config.language == Language::Cxx
            && config.structure.associated_constants_in_body
            && config.constant.allow_static_const
            && !associated_to_transparent;

        let condition = (&self.cfg).to_condition(config);
        condition.write_before(config, out);

        let name = if in_body {
            Cow::Owned(format!(
                "{}::{}",
                associated_to_struct.unwrap().export_name(),
                self.export_name(),
            ))
        } else if self.associated_to.is_none() {
            Cow::Borrowed(self.export_name())
        } else {
            let associated_name = match associated_to_struct {
                Some(s) => Cow::Borrowed(s.export_name()),
                None => {
                    let mut name = self.associated_to.as_ref().unwrap().name().to_owned();
                    config.export.rename(&mut name);
                    Cow::Owned(name)
                }
            };

            Cow::Owned(format!("{}_{}", associated_name, self.export_name()))
        };

        let value = match self.value {
            Literal::Struct {
                ref fields,
                ref path,
                ..
            } if out.bindings().struct_is_transparent(path) => &fields[0].1,
            _ => &self.value,
        };

        if config.constant.allow_static_const && config.language == Language::Cxx {
            out.write(if in_body { "inline " } else { "static " });
            if let Type::ConstPtr(..) = self.ty {
                // Nothing.
            } else {
                out.write("const ");
            }
            self.ty.write(config, out);
            write!(out, " {} = {};", name, value)
        } else {
            write!(out, "#define {} {}", name, value)
        }
        condition.write_after(config, out);
    }
}
<commit_msg>put apostrophe around char constant<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::borrow::Cow;
use std::fmt;
use std::io::Write;
use std::mem;

use syn;

use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::dependencies::Dependencies;
use bindgen::ir::{
    AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path,
    Struct, ToCondition, Type,
};
use bindgen::library::Library;
use bindgen::writer::{Source, SourceWriter};
use bindgen::Bindings;

#[derive(Debug, Clone)]
pub enum Literal {
    Expr(String),
    BinOp {
        left: Box<Literal>,
        op: &'static str,
        right: Box<Literal>,
    },
    Struct {
        path: Path,
        export_name: String,
        fields: Vec<(String, Literal)>,
    },
}

impl Literal {
    fn replace_self_with(&mut self, self_ty: &Path) {
        match *self {
            Literal::BinOp { .. } | Literal::Expr(..) => {}
            Literal::Struct {
                ref mut path,
                ref mut export_name,
                ref mut fields,
            } => {
                if path.replace_self_with(self_ty) {
                    *export_name = self_ty.name().to_owned();
                }
                for &mut (ref _name, ref mut expr) in fields {
                    expr.replace_self_with(self_ty);
                }
            }
        }
    }

    fn is_valid(&self, bindings: &Bindings) -> bool {
        match *self {
            Literal::Expr(..) => true,
            Literal::BinOp {
                ref left,
                ref right,
                ..
            } => left.is_valid(bindings) && right.is_valid(bindings),
            Literal::Struct { ref path, .. } => bindings.struct_exists(path),
        }
    }
}

impl fmt::Display for Literal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Literal::Expr(v) => write!(f, "{}", v),
            Literal::BinOp {
                ref left,
                op,
                ref right,
            } => write!(f, "{} {} {}", left, op, right),
            Literal::Struct {
                path: _,
                export_name,
                fields,
            } => write!(
                f,
                "({}){{ {} }}",
                export_name,
                fields
                    .iter()
                    .map(|(key, lit)| format!(".{} = {}", key, lit))
                    .collect::<Vec<String>>()
                    .join(", "),
            ),
        }
    }
}

impl Literal {
    pub fn rename_for_config(&mut self, config: &Config) {
        match self {
            Literal::Struct {
                path: _,
                ref mut export_name,
                fields,
            } => {
                config.export.rename(export_name);
                for (_, lit) in fields {
                    lit.rename_for_config(config);
                }
            }
            Literal::BinOp {
                ref mut left,
                ref mut right,
                ..
            } => {
                left.rename_for_config(config);
                right.rename_for_config(config);
            }
            Literal::Expr(_) => {}
        }
    }

    pub fn load(expr: &syn::Expr) -> Result<Literal, String> {
        match *expr {
            syn::Expr::Binary(ref bin_expr) => {
                let l = Self::load(&bin_expr.left)?;
                let r = Self::load(&bin_expr.right)?;
                let op = match bin_expr.op {
                    syn::BinOp::Add(..) => "+",
                    syn::BinOp::Sub(..) => "-",
                    syn::BinOp::Mul(..) => "*",
                    syn::BinOp::Div(..) => "/",
                    syn::BinOp::Rem(..) => "%",
                    syn::BinOp::Shl(..) => "<<",
                    syn::BinOp::Shr(..) => ">>",
                    _ => return Err(format!("Unsupported binary op {:?}", bin_expr.op)),
                };
                Ok(Literal::BinOp {
                    left: Box::new(l),
                    op,
                    right: Box::new(r),
                })
            }
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Str(ref value),
                ..
            }) => Ok(Literal::Expr(format!("u8\"{}\"", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Byte(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Char(ref value),
                ..
            }) => Ok(Literal::Expr(format!("'{}'", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Int(ref value),
                ..
            }) => match value.suffix() {
                syn::IntSuffix::Usize
                | syn::IntSuffix::U8
                | syn::IntSuffix::U16
                | syn::IntSuffix::U32
                | syn::IntSuffix::U64
                | syn::IntSuffix::U128
                | syn::IntSuffix::None => Ok(Literal::Expr(format!("{}", value.value()))),
                syn::IntSuffix::Isize
                | syn::IntSuffix::I8
                | syn::IntSuffix::I16
                | syn::IntSuffix::I32
                | syn::IntSuffix::I64
                | syn::IntSuffix::I128 => unsafe {
                    Ok(Literal::Expr(format!(
                        "{}",
                        mem::transmute::<u64, i64>(value.value())
                    )))
                },
            },
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Float(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Bool(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value))),

            syn::Expr::Struct(syn::ExprStruct {
                ref path,
                ref fields,
                ..
            }) => {
                let struct_name = path.segments[0].ident.to_string();
                let mut field_pairs: Vec<(String, Literal)> = Vec::new();
                for field in fields {
                    let ident = match field.member {
                        syn::Member::Named(ref name) => name.to_string(),
                        syn::Member::Unnamed(ref index) => format!("_{}", index.index),
                    };
                    let key = ident.to_string();
                    let value = Literal::load(&field.expr)?;
                    field_pairs.push((key, value));
                }
                Ok(Literal::Struct {
                    path: Path::new(struct_name.clone()),
                    export_name: struct_name,
                    fields: field_pairs,
                })
            }
            _ => Err("Unsupported literal expression.".to_owned()),
        }
    }
}

#[derive(Debug, Clone)]
pub struct Constant {
    pub path: Path,
    pub export_name: String,
    pub ty: Type,
    pub value: Literal,
    pub cfg: Option<Cfg>,
    pub annotations: AnnotationSet,
    pub documentation: Documentation,
    pub associated_to: Option<Path>,
}

fn can_handle(ty: &Type, expr: &syn::Expr) -> bool {
    if ty.is_primitive_or_ptr_primitive() {
        return true;
    }
    match *expr {
        syn::Expr::Struct(_) => true,
        _ => false,
    }
}

impl Constant {
    pub fn load(
        path: Path,
        mod_cfg: Option<&Cfg>,
        ty: &syn::Type,
        expr: &syn::Expr,
        attrs: &[syn::Attribute],
        associated_to: Option<Path>,
    ) -> Result<Constant, String> {
        let ty = Type::load(ty)?;
        let mut ty = match ty {
            Some(ty) => ty,
            None => {
                return Err("Cannot have a zero sized const definition.".to_owned());
            }
        };

        if !can_handle(&ty, expr) {
            return Err("Unhandled const definition".to_owned());
        }

        let mut lit = Literal::load(&expr)?;

        if let Some(ref associated_to) = associated_to {
            ty.replace_self_with(associated_to);
            lit.replace_self_with(associated_to);
        }

        Ok(Constant::new(
            path,
            ty,
            lit,
            Cfg::append(mod_cfg, Cfg::load(attrs)),
            AnnotationSet::load(attrs)?,
            Documentation::load(attrs),
            associated_to,
        ))
    }

    pub fn new(
        path: Path,
        ty: Type,
        value: Literal,
        cfg: Option<Cfg>,
        annotations: AnnotationSet,
        documentation: Documentation,
        associated_to: Option<Path>,
    ) -> Self {
        let export_name = path.name().to_owned();
        Self {
            path,
            export_name,
            ty,
            value,
            cfg,
            annotations,
            documentation,
            associated_to,
        }
    }
}

impl Item for Constant {
    fn path(&self) -> &Path {
        &self.path
    }

    fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
        self.ty.add_dependencies(library, out);
    }

    fn export_name(&self) -> &str {
        &self.export_name
    }

    fn cfg(&self) -> Option<&Cfg> {
        self.cfg.as_ref()
    }

    fn annotations(&self) -> &AnnotationSet {
        &self.annotations
    }

    fn annotations_mut(&mut self) -> &mut AnnotationSet {
        &mut self.annotations
    }

    fn container(&self) -> ItemContainer {
        ItemContainer::Constant(self.clone())
    }

    fn rename_for_config(&mut self, config: &Config) {
        if self.associated_to.is_none() {
            config.export.rename(&mut self.export_name);
        }
        self.value.rename_for_config(config);
        self.ty.rename_for_config(config, &GenericParams::default()); // FIXME: should probably propagate something here
    }

    fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
        self.ty.resolve_declaration_types(resolver);
    }
}

impl Constant {
    pub fn write_declaration<F: Write>(
        &self,
        config: &Config,
        out: &mut SourceWriter<F>,
        associated_to_struct: &Struct,
    ) {
        debug_assert!(self.associated_to.is_some());
        debug_assert!(config.language == Language::Cxx);
        debug_assert!(!associated_to_struct.is_transparent);
        debug_assert!(config.structure.associated_constants_in_body);
        debug_assert!(config.constant.allow_static_const);

        if let Type::ConstPtr(..) = self.ty {
            out.write("static ");
        } else {
            out.write("static const ");
        }
        self.ty.write(config, out);
        write!(out, " {};", self.export_name())
    }

    pub fn write<F: Write>(
        &self,
        config: &Config,
        out: &mut SourceWriter<F>,
        associated_to_struct: Option<&Struct>,
    ) {
        if let Some(assoc) = associated_to_struct {
            if assoc.is_generic() {
                return; // Not tested / implemented yet, so bail out.
            }
        }

        if !self.value.is_valid(out.bindings()) {
            return;
        }

        let associated_to_transparent = associated_to_struct.map_or(false, |s| s.is_transparent);

        let in_body = associated_to_struct.is_some()
            && config.language == Language::Cxx
            && config.structure.associated_constants_in_body
            && config.constant.allow_static_const
            && !associated_to_transparent;

        let condition = (&self.cfg).to_condition(config);
        condition.write_before(config, out);

        let name = if in_body {
            Cow::Owned(format!(
                "{}::{}",
                associated_to_struct.unwrap().export_name(),
                self.export_name(),
            ))
        } else if self.associated_to.is_none() {
            Cow::Borrowed(self.export_name())
        } else {
            let associated_name = match associated_to_struct {
                Some(s) => Cow::Borrowed(s.export_name()),
                None => {
                    let mut name = self.associated_to.as_ref().unwrap().name().to_owned();
                    config.export.rename(&mut name);
                    Cow::Owned(name)
                }
            };

            Cow::Owned(format!("{}_{}", associated_name, self.export_name()))
        };

        let value = match self.value {
            Literal::Struct {
                ref fields,
                ref path,
                ..
            } if out.bindings().struct_is_transparent(path) => &fields[0].1,
            _ => &self.value,
        };

        if config.constant.allow_static_const && config.language == Language::Cxx {
            out.write(if in_body { "inline " } else { "static " });
            if let Type::ConstPtr(..) = self.ty {
                // Nothing.
            } else {
                out.write("const ");
            }
            self.ty.write(config, out);
            write!(out, " {} = {};", name, value)
        } else {
            write!(out, "#define {} {}", name, value)
        }
        condition.write_after(config, out);
    }
}
<|endoftext|>


<commit_before>use std::{
    net::SocketAddr,
    pin::Pin,
    task::{Context, Poll},
};
use lazy_static::lazy_static;
use tokio::{
    io::{AsyncRead, AsyncWrite},
    net::TcpStream,
};

#[cfg(feature = "tls-native")]
use tokio_tls::TlsStream;
#[cfg(feature = "tls-rustls")]
use tokio_rustls::client::TlsStream;

#[cfg(feature = "tls-native")]
lazy_static! {
    static ref TLS_CONNECTOR: tokio_tls::TlsConnector =
        tokio_tls::TlsConnector::from(native_tls::TlsConnector::builder().build().unwrap());
}

#[cfg(feature = "tls-rustls")]
lazy_static! {
    static ref TLS_CONNECTOR: tokio_rustls::TlsConnector = {
        let mut config = tokio_rustls::rustls::ClientConfig::default();
        config.root_store = rustls_native_certs::load_native_certs().unwrap();
        tokio_rustls::TlsConnector::from(std::sync::Arc::new(config))
    };
}

#[derive(Debug)]
pub(crate) enum Stream {
    TcpStream(TcpStream),
    TlsStream(TlsStream<TcpStream>),
}

#[cfg(feature = "tls-native")]
pub(crate) type TlsError = native_tls::Error;
#[cfg(feature = "tls-rustls")]
pub(crate) type TlsError = tokio_rustls::rustls::TLSError;

pub(crate) enum StreamError {
    TlsError(TlsError),
    IoError(std::io::Error),
}

impl From<TlsError> for StreamError {
    fn from(err: TlsError) -> Self {
        StreamError::TlsError(err)
    }
}

impl From<std::io::Error> for StreamError {
    fn from(err: std::io::Error) -> Self {
        StreamError::IoError(err)
    }
}

impl Stream {
    pub(crate) async fn new_tcp(addr: SocketAddr) -> Result<Stream, StreamError> {
        Ok(Stream::TcpStream(TcpStream::connect(addr).await?))
    }

    #[cfg(feature = "tls-native")]
    pub(crate) async fn new_tls(addr: SocketAddr, host_name: &str) -> Result<Stream, StreamError> {
        let tcp_stream = TcpStream::connect(addr).await?;
        let tls_stream = TLS_CONNECTOR.connect(host_name, tcp_stream).await?;
        Ok(Stream::TlsStream(tls_stream))
    }

    #[cfg(feature = "tls-rustls")]
    pub(crate) async fn new_tls(addr: SocketAddr, host_name: &str) -> Result<Stream, StreamError> {
        let tcp_stream = TcpStream::connect(addr).await?;
        let name = tokio_rustls::webpki::DNSNameRef::try_from_ascii_str(host_name)
            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
        let tls_stream = TLS_CONNECTOR.connect(name, tcp_stream).await?;
        Ok(Stream::TlsStream(tls_stream))
    }
}

//
// Boilerplate
//

impl AsyncRead for Stream {
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context,
        buf: &mut [u8],
    ) -> Poll<Result<usize, std::io::Error>> {
        match *self {
            Stream::TcpStream(ref mut tcp_stream) => Pin::new(tcp_stream).poll_read(cx, buf),
            Stream::TlsStream(ref mut tls_stream) => Pin::new(tls_stream).poll_read(cx, buf),
        }
    }
}

impl AsyncWrite for Stream {
    fn poll_write(
        mut self: Pin<&mut Self>,
        cx: &mut Context,
        buf: &[u8],
    ) -> Poll<Result<usize, std::io::Error>> {
        match *self {
            Stream::TcpStream(ref mut tcp_stream) => Pin::new(tcp_stream).poll_write(cx, buf),
            Stream::TlsStream(ref mut tls_stream) => Pin::new(tls_stream).poll_write(cx, buf),
        }
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), std::io::Error>> {
        match *self {
            Stream::TcpStream(ref mut tcp_stream) => Pin::new(tcp_stream).poll_flush(cx),
            Stream::TlsStream(ref mut tls_stream) => Pin::new(tls_stream).poll_flush(cx),
        }
    }

    fn poll_shutdown(
        mut self: Pin<&mut Self>,
        cx: &mut Context,
    ) -> Poll<Result<(), std::io::Error>> {
        match *self {
            Stream::TcpStream(ref mut tcp_stream) => Pin::new(tcp_stream).poll_shutdown(cx),
            Stream::TlsStream(ref mut tls_stream) => Pin::new(tls_stream).poll_shutdown(cx),
        }
    }
}
<commit_msg>Formatting only<commit_after>use lazy_static::lazy_static;
use std::{
    net::SocketAddr,
    pin::Pin,
    task::{Context, Poll},
};
use tokio::{
    io::{AsyncRead, AsyncWrite},
    net::TcpStream,
};

#[cfg(feature = "tls-rustls")]
use tokio_rustls::client::TlsStream;
#[cfg(feature = "tls-native")]
use tokio_tls::TlsStream;

#[cfg(feature = "tls-native")]
lazy_static! {
    static ref TLS_CONNECTOR: tokio_tls::TlsConnector =
        tokio_tls::TlsConnector::from(native_tls::TlsConnector::builder().build().unwrap());
}

#[cfg(feature = "tls-rustls")]
lazy_static! {
    static ref TLS_CONNECTOR: tokio_rustls::TlsConnector = {
        let mut config = tokio_rustls::rustls::ClientConfig::default();
        config.root_store = rustls_native_certs::load_native_certs().unwrap();
        tokio_rustls::TlsConnector::from(std::sync::Arc::new(config))
    };
}

#[derive(Debug)]
pub(crate) enum Stream {
    TcpStream(TcpStream),
    TlsStream(TlsStream<TcpStream>),
}

#[cfg(feature = "tls-native")]
pub(crate) type TlsError = native_tls::Error;
#[cfg(feature = "tls-rustls")]
pub(crate) type TlsError = tokio_rustls::rustls::TLSError;

pub(crate) enum StreamError {
    TlsError(TlsError),
    IoError(std::io::Error),
}

impl From<TlsError> for StreamError {
    fn from(err: TlsError) -> Self {
        StreamError::TlsError(err)
    }
}

impl From<std::io::Error> for StreamError {
    fn from(err: std::io::Error) -> Self {
        StreamError::IoError(err)
    }
}

impl Stream {
    pub(crate) async fn new_tcp(addr: SocketAddr) -> Result<Stream, StreamError> {
        Ok(Stream::TcpStream(TcpStream::connect(addr).await?))
    }

    #[cfg(feature = "tls-native")]
    pub(crate) async fn new_tls(addr: SocketAddr, host_name: &str) -> Result<Stream, StreamError> {
        let tcp_stream = TcpStream::connect(addr).await?;
        let tls_stream = TLS_CONNECTOR.connect(host_name, tcp_stream).await?;
        Ok(Stream::TlsStream(tls_stream))
    }

    #[cfg(feature = "tls-rustls")]
    pub(crate) async fn new_tls(addr: SocketAddr, host_name: &str) -> Result<Stream, StreamError> {
        let tcp_stream = TcpStream::connect(addr).await?;
        let name = tokio_rustls::webpki::DNSNameRef::try_from_ascii_str(host_name)
            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
        let tls_stream = TLS_CONNECTOR.connect(name, tcp_stream).await?;
        Ok(Stream::TlsStream(tls_stream))
    }
}

//
// Boilerplate
//

impl AsyncRead for Stream {
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context,
        buf: &mut [u8],
    ) -> Poll<Result<usize, std::io::Error>> {
        match *self {
            Stream::TcpStream(ref mut tcp_stream) => Pin::new(tcp_stream).poll_read(cx, buf),
            Stream::TlsStream(ref mut tls_stream) => Pin::new(tls_stream).poll_read(cx, buf),
        }
    }
}

impl AsyncWrite for Stream {
    fn poll_write(
        mut self: Pin<&mut Self>,
        cx: &mut Context,
        buf: &[u8],
    ) -> Poll<Result<usize, std::io::Error>> {
        match *self {
            Stream::TcpStream(ref mut tcp_stream) => Pin::new(tcp_stream).poll_write(cx, buf),
            Stream::TlsStream(ref mut tls_stream) => Pin::new(tls_stream).poll_write(cx, buf),
        }
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), std::io::Error>> {
        match *self {
            Stream::TcpStream(ref mut tcp_stream) => Pin::new(tcp_stream).poll_flush(cx),
            Stream::TlsStream(ref mut tls_stream) => Pin::new(tls_stream).poll_flush(cx),
        }
    }

    fn poll_shutdown(
        mut self: Pin<&mut Self>,
        cx: &mut Context,
    ) -> Poll<Result<(), std::io::Error>> {
        match *self {
            Stream::TcpStream(ref mut tcp_stream) => Pin::new(tcp_stream).poll_shutdown(cx),
            Stream::TlsStream(ref mut tls_stream) => Pin::new(tls_stream).poll_shutdown(cx),
        }
    }
}
<|endoftext|>


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

use target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        morestack: false,
        linker_is_gnu: true,
        has_rpath: true,
        position_independent_executables: true,
        pre_link_args: vec!(
        ),
        archive_format: "bsd".to_string(),

        .. Default::default()
    }
}
<commit_msg>Rollup merge of #27137 - dhuseby:fixing_bitrig_linking, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        morestack: false,
        linker_is_gnu: true,
        has_rpath: true,
        position_independent_executables: true,
        archive_format: "gnu".to_string(),

        .. Default::default()
    }
}
<|endoftext|>


<commit_before>mod linkedlist_test;
mod linkedlist{

    pub enum List{
        Cons(int, Box<List>),
        Nil
    }

    pub fn visual_compare(l1: &List, l2: &List) -> String{
        let equality = match equal(l1, l2){
            true  => "",
            false => "not ",
        };
        format!("{} and {} are {}equal", repr(l1), repr(l2), equality)
    }

    pub fn repr(list: &List) -> String{
        match list{
            &Nil => String::from_str("<[]>"),
            &Cons(_, _) => String::from_str("<[").append(_repr_inner(list).as_slice())
        }
    }

    fn _repr_inner(list: &List) -> String{
        match list{
            &Nil => String::from_str("]>"),
            &Cons(number, box ref tail) if match tail{
                &Nil => true,
                _ => false,
            }=> number.to_string().append("]>"),
            &Cons(number, box ref tail) => number.to_string().append(", ").append(_repr_inner(tail).as_slice())
        }
    }

    pub fn equal(l1: &List, l2: &List) -> bool{
        match (l1, l2){
            (&Nil, &Nil) => true,
            (&Cons(n1, box ref tail1), &Cons(n2, box ref tail2)) if n1 == n2 => {
                equal(tail1, tail2)
            },
            _ => false,
        }
    }
}
<commit_msg>add metadata and test cfg<commit_after>#![desc = "A linked list kata in rust"]
#![license = "public domain"]

#[cfg(test)]
mod linkedlist_test;
mod linkedlist{

    pub enum List{
        Cons(int, Box<List>),
        Nil
    }

    pub fn visual_compare(l1: &List, l2: &List) -> String{
        let equality = match equal(l1, l2){
            true  => "",
            false => "not ",
        };
        format!("{} and {} are {}equal", repr(l1), repr(l2), equality)
    }

    pub fn repr(list: &List) -> String{
        match list{
            &Nil => String::from_str("<[]>"),
            &Cons(_, _) => String::from_str("<[").append(_repr_inner(list).as_slice())
        }
    }

    fn _repr_inner(list: &List) -> String{
        match list{
            &Nil => String::from_str("]>"),
            &Cons(number, box ref tail) if match tail{
                &Nil => true,
                _ => false,
            }=> number.to_string().append("]>"),
            &Cons(number, box ref tail) => number.to_string().append(", ").append(_repr_inner(tail).as_slice())
        }
    }

    pub fn equal(l1: &List, l2: &List) -> bool{
        match (l1, l2){
            (&Nil, &Nil) => true,
            (&Cons(n1, box ref tail1), &Cons(n2, box ref tail2)) if n1 == n2 => {
                equal(tail1, tail2)
            },
            _ => false,
        }
    }
}
<|endoftext|>


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

use api::{FontInstancePlatformOptions, FontKey, FontRenderMode};
use api::{ColorU, GlyphDimensions, GlyphKey, SubpixelDirection};
use dwrote;
use gamma_lut::{ColorLut, GammaLut};
use glyph_rasterizer::{FontInstance, GlyphFormat, RasterizedGlyph};
use internal_types::FastHashMap;
use std::sync::Arc;

lazy_static! {
    static ref DEFAULT_FONT_DESCRIPTOR: dwrote::FontDescriptor = dwrote::FontDescriptor {
        family_name: "Arial".to_owned(),
        weight: dwrote::FontWeight::Regular,
        stretch: dwrote::FontStretch::Normal,
        style: dwrote::FontStyle::Normal,
    };
}

pub struct FontContext {
    fonts: FastHashMap<FontKey, dwrote::FontFace>,
    gamma_lut: GammaLut,
    gdi_gamma_lut: GammaLut,
}

// DirectWrite is safe to use on multiple threads and non-shareable resources are
// all hidden inside their font context.
unsafe impl Send for FontContext {}

fn dwrite_texture_type(render_mode: FontRenderMode) -> dwrote::DWRITE_TEXTURE_TYPE {
    match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_TEXTURE_ALIASED_1x1,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1,
    }
}

fn dwrite_measure_mode(
    render_mode: FontRenderMode,
    options: Option<FontInstancePlatformOptions>,
) -> dwrote::DWRITE_MEASURING_MODE {
    if let Some(FontInstancePlatformOptions {
        force_gdi_rendering: true,
        ..
    }) = options
    {
        return dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC;
    }

    match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_MEASURING_MODE_NATURAL,
    }
}

fn dwrite_render_mode(
    font_face: &dwrote::FontFace,
    render_mode: FontRenderMode,
    em_size: f32,
    measure_mode: dwrote::DWRITE_MEASURING_MODE,
    options: Option<FontInstancePlatformOptions>,
) -> dwrote::DWRITE_RENDERING_MODE {
    if let Some(FontInstancePlatformOptions {
        force_gdi_rendering: true,
        ..
    }) = options
    {
        return dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC;
    }

    let dwrite_render_mode = match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_RENDERING_MODE_ALIASED,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => {
            font_face.get_recommended_rendering_mode_default_params(em_size, 1.0, measure_mode)
        }
    };

    if dwrite_render_mode == dwrote::DWRITE_RENDERING_MODE_OUTLINE {
        // Outline mode is not supported
        return dwrote::DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
    }

    dwrite_render_mode
}

impl FontContext {
    pub fn new() -> FontContext {
        // These are the default values we use in Gecko.
        // We use a gamma value of 2.3 for gdi fonts
        // TODO: Fetch this data from Gecko itself.
        let contrast = 1.0;
        let gamma = 1.8;
        let gdi_gamma = 2.3;
        FontContext {
            fonts: FastHashMap::default(),
            gamma_lut: GammaLut::new(contrast, gamma, gamma),
            gdi_gamma_lut: GammaLut::new(contrast, gdi_gamma, gdi_gamma),
        }
    }

    pub fn has_font(&self, font_key: &FontKey) -> bool {
        self.fonts.contains_key(font_key)
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, data: Arc<Vec<u8>>, index: u32) {
        if self.fonts.contains_key(font_key) {
            return;
        }

        if let Some(font_file) = dwrote::FontFile::new_from_data(&**data) {
            let face = font_file.create_face(index, dwrote::DWRITE_FONT_SIMULATIONS_NONE);
            self.fonts.insert((*font_key).clone(), face);
        } else {
            // XXX add_raw_font needs to have a way to return an error
            debug!("DWrite WR failed to load font from data, using Arial instead");
            self.add_native_font(font_key, DEFAULT_FONT_DESCRIPTOR.clone());
        }
    }

    pub fn add_native_font(&mut self, font_key: &FontKey, font_handle: dwrote::FontDescriptor) {
        if self.fonts.contains_key(font_key) {
            return;
        }

        let system_fc = dwrote::FontCollection::system();
        let font = system_fc.get_font_from_descriptor(&font_handle).unwrap();
        let face = font.create_font_face();
        self.fonts.insert((*font_key).clone(), face);
    }

    pub fn delete_font(&mut self, font_key: &FontKey) {
        self.fonts.remove(font_key);
    }

    // Assumes RGB format from dwrite, which is 3 bytes per pixel as dwrite
    // doesn't output an alpha value via GlyphRunAnalysis::CreateAlphaTexture
    #[allow(dead_code)]
    fn print_glyph_data(&self, data: &[u8], width: usize, height: usize) {
        // Rust doesn't have step_by support on stable :(
        for i in 0 .. height {
            let current_height = i * width * 3;

            for pixel in data[current_height .. current_height + (width * 3)].chunks(3) {
                let r = pixel[0];
                let g = pixel[1];
                let b = pixel[2];
                print!("({}, {}, {}) ", r, g, b,);
            }
            println!("");
        }
    }

    fn create_glyph_analysis(
        &self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> dwrote::GlyphRunAnalysis {
        let face = self.fonts.get(&font.font_key).unwrap();
        let glyph = key.index as u16;
        let advance = 0.0f32;
        let offset = dwrote::GlyphOffset {
            advanceOffset: 0.0,
            ascenderOffset: 0.0,
        };

        let glyph_run = dwrote::DWRITE_GLYPH_RUN {
            fontFace: unsafe { face.as_ptr() },
            fontEmSize: font.size.to_f32_px(), // size in DIPs (1/96", same as CSS pixels)
            glyphCount: 1,
            glyphIndices: &glyph,
            glyphAdvances: &advance,
            glyphOffsets: &offset,
            isSideways: 0,
            bidiLevel: 0,
        };

        let dwrite_measure_mode = dwrite_measure_mode(font.render_mode, font.platform_options);
        let dwrite_render_mode = dwrite_render_mode(
            face,
            font.render_mode,
            font.size.to_f32_px(),
            dwrite_measure_mode,
            font.platform_options,
        );

        let (x_offset, y_offset) = font.get_subpx_offset(key);
        let transform = Some(dwrote::DWRITE_MATRIX {
            m11: 1.0,
            m12: 0.0,
            m21: 0.0,
            m22: 1.0,
            dx: x_offset as f32,
            dy: y_offset as f32,
        });

        dwrote::GlyphRunAnalysis::create(
            &glyph_run,
            1.0,
            transform,
            dwrite_render_mode,
            dwrite_measure_mode,
            0.0,
            0.0,
        )
    }

    pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
        let face = self.fonts.get(&font_key).unwrap();
        let indices = face.get_glyph_indices(&[ch as u32]);
        indices.first().map(|idx| *idx as u32)
    }

    // TODO: Pipe GlyphOptions into glyph_dimensions too
    pub fn get_glyph_dimensions(
        &self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> Option<GlyphDimensions> {
        // Probably have to default to something else here.
        let render_mode = FontRenderMode::Subpixel;
        let analysis = self.create_glyph_analysis(font, key);

        let texture_type = dwrite_texture_type(render_mode);

        let bounds = analysis.get_alpha_texture_bounds(texture_type);

        let width = (bounds.right - bounds.left) as u32;
        let height = (bounds.bottom - bounds.top) as u32;

        // Alpha texture bounds can sometimes return an empty rect
        // Such as for spaces
        if width == 0 || height == 0 {
            return None;
        }

        let face = self.fonts.get(&font.font_key).unwrap();
        face.get_design_glyph_metrics(&[key.index as u16], false)
            .first()
            .map(|metrics| {
                let em_size = font.size.to_f32_px() / 16.;
                let design_units_per_pixel = face.metrics().designUnitsPerEm as f32 / 16. as f32;
                let scaled_design_units_to_pixels = em_size / design_units_per_pixel;
                let advance = metrics.advanceWidth as f32 * scaled_design_units_to_pixels;

                GlyphDimensions {
                    left: bounds.left,
                    top: -bounds.top,
                    width,
                    height,
                    advance: advance,
                }
            })
    }

    // DWrite ClearType gives us values in RGB, but WR expects BGRA.
    fn convert_to_bgra(&self, pixels: &[u8], render_mode: FontRenderMode) -> Vec<u8> {
        match render_mode {
            FontRenderMode::Bitmap => {
                unreachable!("TODO: bitmap fonts");
            }
            FontRenderMode::Mono => {
                let mut bgra_pixels: Vec<u8> = vec![0; pixels.len() * 4];
                for i in 0 .. pixels.len() {
                    let alpha = pixels[i];
                    bgra_pixels[i * 4 + 0] = alpha;
                    bgra_pixels[i * 4 + 1] = alpha;
                    bgra_pixels[i * 4 + 2] = alpha;
                    bgra_pixels[i * 4 + 3] = alpha;
                }
                bgra_pixels
            }
            FontRenderMode::Alpha => {
                let length = pixels.len() / 3;
                let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
                for i in 0 .. length {
                    // Only take the G channel, as its closest to D2D
                    let alpha = pixels[i * 3 + 1] as u8;
                    bgra_pixels[i * 4 + 0] = alpha;
                    bgra_pixels[i * 4 + 1] = alpha;
                    bgra_pixels[i * 4 + 2] = alpha;
                    bgra_pixels[i * 4 + 3] = alpha;
                }
                bgra_pixels
            }
            FontRenderMode::Subpixel => {
                let length = pixels.len() / 3;
                let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
                for i in 0 .. length {
                    bgra_pixels[i * 4 + 0] = pixels[i * 3 + 2];
                    bgra_pixels[i * 4 + 1] = pixels[i * 3 + 1];
                    bgra_pixels[i * 4 + 2] = pixels[i * 3 + 0];
                    bgra_pixels[i * 4 + 3] = 0xff;
                }
                bgra_pixels
            }
        }
    }

    pub fn is_bitmap_font(&mut self, _font: &FontInstance) -> bool {
        // TODO(gw): Support bitmap fonts in DWrite.
        false
    }

    pub fn prepare_font(font: &mut FontInstance) {
        match font.render_mode {
            FontRenderMode::Mono | FontRenderMode::Bitmap => {
                // In mono/bitmap modes the color of the font is irrelevant.
                font.color = ColorU::new(255, 255, 255, 255);
                // Subpixel positioning is disabled in mono and bitmap modes.
                font.subpx_dir = SubpixelDirection::None;
            }
            FontRenderMode::Alpha => {
                font.color = font.color.luminance_color().quantize();
            }
            FontRenderMode::Subpixel => {
                font.color = font.color.quantize();
            }
        }
    }

    pub fn rasterize_glyph(
        &mut self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> Option<RasterizedGlyph> {
        let analysis = self.create_glyph_analysis(font, key);
        let texture_type = dwrite_texture_type(font.render_mode);

        let bounds = analysis.get_alpha_texture_bounds(texture_type);
        let width = (bounds.right - bounds.left) as u32;
        let height = (bounds.bottom - bounds.top) as u32;

        // Alpha texture bounds can sometimes return an empty rect
        // Such as for spaces
        if width == 0 || height == 0 {
            return None;
        }

        let pixels = analysis.create_alpha_texture(texture_type, bounds);
        let mut bgra_pixels = self.convert_to_bgra(&pixels, font.render_mode);

        match font.render_mode {
            FontRenderMode::Mono | FontRenderMode::Bitmap => {}
            FontRenderMode::Alpha | FontRenderMode::Subpixel => {
                let lut_correction = match font.platform_options {
                    Some(option) => if option.force_gdi_rendering {
                        &self.gdi_gamma_lut
                    } else {
                        &self.gamma_lut
                    },
                    None => &self.gamma_lut,
                };

                lut_correction.preblend(&mut bgra_pixels, font.color);
            }
        }

        Some(RasterizedGlyph {
            left: bounds.left as f32,
            top: -bounds.top as f32,
            width,
            height,
            scale: 1.0,
            format: GlyphFormat::from(font.render_mode),
            bytes: bgra_pixels,
        })
    }
}
<commit_msg>choose bitmap-compatible rendering modes with FontInstancePlatformOptions::use_embedded_bitmap<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{FontInstancePlatformOptions, FontKey, FontRenderMode};
use api::{ColorU, GlyphDimensions, GlyphKey, SubpixelDirection};
use dwrote;
use gamma_lut::{ColorLut, GammaLut};
use glyph_rasterizer::{FontInstance, GlyphFormat, RasterizedGlyph};
use internal_types::FastHashMap;
use std::sync::Arc;

lazy_static! {
    static ref DEFAULT_FONT_DESCRIPTOR: dwrote::FontDescriptor = dwrote::FontDescriptor {
        family_name: "Arial".to_owned(),
        weight: dwrote::FontWeight::Regular,
        stretch: dwrote::FontStretch::Normal,
        style: dwrote::FontStyle::Normal,
    };
}

pub struct FontContext {
    fonts: FastHashMap<FontKey, dwrote::FontFace>,
    gamma_lut: GammaLut,
    gdi_gamma_lut: GammaLut,
}

// DirectWrite is safe to use on multiple threads and non-shareable resources are
// all hidden inside their font context.
unsafe impl Send for FontContext {}

fn dwrite_texture_type(render_mode: FontRenderMode) -> dwrote::DWRITE_TEXTURE_TYPE {
    match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_TEXTURE_ALIASED_1x1,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1,
    }
}

fn dwrite_measure_mode(
    render_mode: FontRenderMode,
    options: Option<FontInstancePlatformOptions>,
) -> dwrote::DWRITE_MEASURING_MODE {
    let FontInstancePlatformOptions { force_gdi_rendering, use_embedded_bitmap, .. } =
        options.unwrap_or_default();
    if force_gdi_rendering || use_embedded_bitmap {
        return dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC;
    }

    match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_MEASURING_MODE_NATURAL,
    }
}

fn dwrite_render_mode(
    font_face: &dwrote::FontFace,
    render_mode: FontRenderMode,
    em_size: f32,
    measure_mode: dwrote::DWRITE_MEASURING_MODE,
    options: Option<FontInstancePlatformOptions>,
) -> dwrote::DWRITE_RENDERING_MODE {
    let FontInstancePlatformOptions { force_gdi_rendering, use_embedded_bitmap, .. } =
        options.unwrap_or_default();

    let dwrite_render_mode = match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_RENDERING_MODE_ALIASED,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => {
            if force_gdi_rendering || use_embedded_bitmap {
                dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC
            } else {
                font_face.get_recommended_rendering_mode_default_params(em_size, 1.0, measure_mode)
            }
        }
    };

    if dwrite_render_mode == dwrote::DWRITE_RENDERING_MODE_OUTLINE {
        // Outline mode is not supported
        return dwrote::DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
    }

    dwrite_render_mode
}

impl FontContext {
    pub fn new() -> FontContext {
        // These are the default values we use in Gecko.
        // We use a gamma value of 2.3 for gdi fonts
        // TODO: Fetch this data from Gecko itself.
        let contrast = 1.0;
        let gamma = 1.8;
        let gdi_gamma = 2.3;
        FontContext {
            fonts: FastHashMap::default(),
            gamma_lut: GammaLut::new(contrast, gamma, gamma),
            gdi_gamma_lut: GammaLut::new(contrast, gdi_gamma, gdi_gamma),
        }
    }

    pub fn has_font(&self, font_key: &FontKey) -> bool {
        self.fonts.contains_key(font_key)
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, data: Arc<Vec<u8>>, index: u32) {
        if self.fonts.contains_key(font_key) {
            return;
        }

        if let Some(font_file) = dwrote::FontFile::new_from_data(&**data) {
            let face = font_file.create_face(index, dwrote::DWRITE_FONT_SIMULATIONS_NONE);
            self.fonts.insert((*font_key).clone(), face);
        } else {
            // XXX add_raw_font needs to have a way to return an error
            debug!("DWrite WR failed to load font from data, using Arial instead");
            self.add_native_font(font_key, DEFAULT_FONT_DESCRIPTOR.clone());
        }
    }

    pub fn add_native_font(&mut self, font_key: &FontKey, font_handle: dwrote::FontDescriptor) {
        if self.fonts.contains_key(font_key) {
            return;
        }

        let system_fc = dwrote::FontCollection::system();
        let font = system_fc.get_font_from_descriptor(&font_handle).unwrap();
        let face = font.create_font_face();
        self.fonts.insert((*font_key).clone(), face);
    }

    pub fn delete_font(&mut self, font_key: &FontKey) {
        self.fonts.remove(font_key);
    }

    // Assumes RGB format from dwrite, which is 3 bytes per pixel as dwrite
    // doesn't output an alpha value via GlyphRunAnalysis::CreateAlphaTexture
    #[allow(dead_code)]
    fn print_glyph_data(&self, data: &[u8], width: usize, height: usize) {
        // Rust doesn't have step_by support on stable :(
        for i in 0 .. height {
            let current_height = i * width * 3;

            for pixel in data[current_height .. current_height + (width * 3)].chunks(3) {
                let r = pixel[0];
                let g = pixel[1];
                let b = pixel[2];
                print!("({}, {}, {}) ", r, g, b,);
            }
            println!("");
        }
    }

    fn create_glyph_analysis(
        &self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> dwrote::GlyphRunAnalysis {
        let face = self.fonts.get(&font.font_key).unwrap();
        let glyph = key.index as u16;
        let advance = 0.0f32;
        let offset = dwrote::GlyphOffset {
            advanceOffset: 0.0,
            ascenderOffset: 0.0,
        };

        let glyph_run = dwrote::DWRITE_GLYPH_RUN {
            fontFace: unsafe { face.as_ptr() },
            fontEmSize: font.size.to_f32_px(), // size in DIPs (1/96", same as CSS pixels)
            glyphCount: 1,
            glyphIndices: &glyph,
            glyphAdvances: &advance,
            glyphOffsets: &offset,
            isSideways: 0,
            bidiLevel: 0,
        };

        let dwrite_measure_mode = dwrite_measure_mode(font.render_mode, font.platform_options);
        let dwrite_render_mode = dwrite_render_mode(
            face,
            font.render_mode,
            font.size.to_f32_px(),
            dwrite_measure_mode,
            font.platform_options,
        );

        let (x_offset, y_offset) = font.get_subpx_offset(key);
        let transform = Some(dwrote::DWRITE_MATRIX {
            m11: 1.0,
            m12: 0.0,
            m21: 0.0,
            m22: 1.0,
            dx: x_offset as f32,
            dy: y_offset as f32,
        });

        dwrote::GlyphRunAnalysis::create(
            &glyph_run,
            1.0,
            transform,
            dwrite_render_mode,
            dwrite_measure_mode,
            0.0,
            0.0,
        )
    }

    pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
        let face = self.fonts.get(&font_key).unwrap();
        let indices = face.get_glyph_indices(&[ch as u32]);
        indices.first().map(|idx| *idx as u32)
    }

    // TODO: Pipe GlyphOptions into glyph_dimensions too
    pub fn get_glyph_dimensions(
        &self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> Option<GlyphDimensions> {
        // Probably have to default to something else here.
        let render_mode = FontRenderMode::Subpixel;
        let analysis = self.create_glyph_analysis(font, key);

        let texture_type = dwrite_texture_type(render_mode);

        let bounds = analysis.get_alpha_texture_bounds(texture_type);

        let width = (bounds.right - bounds.left) as u32;
        let height = (bounds.bottom - bounds.top) as u32;

        // Alpha texture bounds can sometimes return an empty rect
        // Such as for spaces
        if width == 0 || height == 0 {
            return None;
        }

        let face = self.fonts.get(&font.font_key).unwrap();
        face.get_design_glyph_metrics(&[key.index as u16], false)
            .first()
            .map(|metrics| {
                let em_size = font.size.to_f32_px() / 16.;
                let design_units_per_pixel = face.metrics().designUnitsPerEm as f32 / 16. as f32;
                let scaled_design_units_to_pixels = em_size / design_units_per_pixel;
                let advance = metrics.advanceWidth as f32 * scaled_design_units_to_pixels;

                GlyphDimensions {
                    left: bounds.left,
                    top: -bounds.top,
                    width,
                    height,
                    advance: advance,
                }
            })
    }

    // DWrite ClearType gives us values in RGB, but WR expects BGRA.
    fn convert_to_bgra(&self, pixels: &[u8], render_mode: FontRenderMode) -> Vec<u8> {
        match render_mode {
            FontRenderMode::Bitmap => {
                unreachable!("TODO: bitmap fonts");
            }
            FontRenderMode::Mono => {
                let mut bgra_pixels: Vec<u8> = vec![0; pixels.len() * 4];
                for i in 0 .. pixels.len() {
                    let alpha = pixels[i];
                    bgra_pixels[i * 4 + 0] = alpha;
                    bgra_pixels[i * 4 + 1] = alpha;
                    bgra_pixels[i * 4 + 2] = alpha;
                    bgra_pixels[i * 4 + 3] = alpha;
                }
                bgra_pixels
            }
            FontRenderMode::Alpha => {
                let length = pixels.len() / 3;
                let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
                for i in 0 .. length {
                    // Only take the G channel, as its closest to D2D
                    let alpha = pixels[i * 3 + 1] as u8;
                    bgra_pixels[i * 4 + 0] = alpha;
                    bgra_pixels[i * 4 + 1] = alpha;
                    bgra_pixels[i * 4 + 2] = alpha;
                    bgra_pixels[i * 4 + 3] = alpha;
                }
                bgra_pixels
            }
            FontRenderMode::Subpixel => {
                let length = pixels.len() / 3;
                let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
                for i in 0 .. length {
                    bgra_pixels[i * 4 + 0] = pixels[i * 3 + 2];
                    bgra_pixels[i * 4 + 1] = pixels[i * 3 + 1];
                    bgra_pixels[i * 4 + 2] = pixels[i * 3 + 0];
                    bgra_pixels[i * 4 + 3] = 0xff;
                }
                bgra_pixels
            }
        }
    }

    pub fn is_bitmap_font(&mut self, _font: &FontInstance) -> bool {
        // TODO(gw): Support bitmap fonts in DWrite.
        false
    }

    pub fn prepare_font(font: &mut FontInstance) {
        match font.render_mode {
            FontRenderMode::Mono | FontRenderMode::Bitmap => {
                // In mono/bitmap modes the color of the font is irrelevant.
                font.color = ColorU::new(255, 255, 255, 255);
                // Subpixel positioning is disabled in mono and bitmap modes.
                font.subpx_dir = SubpixelDirection::None;
            }
            FontRenderMode::Alpha => {
                font.color = font.color.luminance_color().quantize();
            }
            FontRenderMode::Subpixel => {
                font.color = font.color.quantize();
            }
        }
    }

    pub fn rasterize_glyph(
        &mut self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> Option<RasterizedGlyph> {
        let analysis = self.create_glyph_analysis(font, key);
        let texture_type = dwrite_texture_type(font.render_mode);

        let bounds = analysis.get_alpha_texture_bounds(texture_type);
        let width = (bounds.right - bounds.left) as u32;
        let height = (bounds.bottom - bounds.top) as u32;

        // Alpha texture bounds can sometimes return an empty rect
        // Such as for spaces
        if width == 0 || height == 0 {
            return None;
        }

        let pixels = analysis.create_alpha_texture(texture_type, bounds);
        let mut bgra_pixels = self.convert_to_bgra(&pixels, font.render_mode);

        match font.render_mode {
            FontRenderMode::Mono | FontRenderMode::Bitmap => {}
            FontRenderMode::Alpha | FontRenderMode::Subpixel => {
                let lut_correction = match font.platform_options {
                    Some(option) => if option.force_gdi_rendering {
                        &self.gdi_gamma_lut
                    } else {
                        &self.gamma_lut
                    },
                    None => &self.gamma_lut,
                };

                lut_correction.preblend(&mut bgra_pixels, font.color);
            }
        }

        Some(RasterizedGlyph {
            left: bounds.left as f32,
            top: -bounds.top as f32,
            width,
            height,
            scale: 1.0,
            format: GlyphFormat::from(font.render_mode),
            bytes: bgra_pixels,
        })
    }
}
<|endoftext|>


<commit_before>/**
   Translation for various task and comm-related things.

   Most of this will probably go away as we move more of this into
   libraries.

*/

import std::str;
import std::option;
import option::none;
import option::some;

import lib::llvm::llvm;
import lib::llvm::llvm::ValueRef;

import util::ppaux::ty_to_str;
import syntax::print::pprust::expr_to_str;
import syntax::ast;
import back::link::mangle_internal_name_by_path_and_seq;

import trans_common::*;
import trans::*;

export trans_port;
export trans_chan;
export trans_spawn;
export trans_send;
export trans_recv;

fn trans_port(&@block_ctxt cx, ast::node_id id) -> result {
    auto t = node_id_type(cx.fcx.lcx.ccx, id);
    auto unit_ty;
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_port(?t)) { unit_ty = t; }
        case (_) { cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port"); }
    }
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
    auto port_raw_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_port,
                       ~[bcx.fcx.lltaskptr, unit_sz.val]);
    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, t);
    auto port_val = bcx.build.PointerCast(port_raw_val, llty);
    add_clean_temp(bcx, port_val, t);
    ret rslt(bcx, port_val);
}

fn trans_chan(&@block_ctxt cx, &@ast::expr e, ast::node_id id) -> result {
    auto bcx = cx;
    auto prt = trans_expr(bcx, e);
    bcx = prt.bcx;
    auto prt_val = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
    auto chan_raw_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_chan,
                       ~[bcx.fcx.lltaskptr, prt_val]);
    auto chan_ty = node_id_type(bcx.fcx.lcx.ccx, id);
    auto chan_llty = type_of(bcx.fcx.lcx.ccx, e.span, chan_ty);
    auto chan_val = bcx.build.PointerCast(chan_raw_val, chan_llty);
    add_clean_temp(bcx, chan_val, chan_ty);
    ret rslt(bcx, chan_val);
}

fn trans_spawn(&@block_ctxt cx, &ast::spawn_dom dom, &option::t[str] name,
               &@ast::expr func, &(@ast::expr)[] args, ast::node_id id)
        -> result {
    auto bcx = cx;
    // Make the task name

    auto tname =
        alt (name) {
            case (none) {
                auto argss = std::ivec::map(expr_to_str, args);
                #fmt("%s(%s)", expr_to_str(func),
                     str::connect_ivec(argss, ", "))
            }
            case (some(?n)) { n }
        };
    // Generate code
    //
    // This is a several step process. The following things need to happen
    // (not necessarily in order):
    //
    // 1. Evaluate all the arguments to the spawnee.
    //
    // 2. Alloca a tuple that holds these arguments (they must be in reverse
    // order, so that they match the expected stack layout for the spawnee)
    //
    // 3. Fill the tuple with the arguments we evaluated.
    //
    // 3.5. Generate a wrapper function that takes the tuple and unpacks it to
    // call the real task.
    //
    // 4. Pass a pointer to the wrapper function and the argument tuple to
    // upcall_start_task. In order to do this, we need to allocate another
    // tuple that matches the arguments expected by rust_task::start.
    //
    // 5. Oh yeah, we have to create the task before we start it...

    // But first, we'll create a task.

    let ValueRef lltname = C_str(bcx.fcx.lcx.ccx, tname);
    auto new_task =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_task,
                       ~[bcx.fcx.lltaskptr, lltname]);

    // Translate the arguments, remembering their types and where the values
    // ended up.

    let ty::t[] arg_tys = ~[];
    let ValueRef[] arg_vals = ~[];
    for (@ast::expr e in args) {
        auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
        auto arg = trans_expr(bcx, e);

        arg = deep_copy(arg.bcx, arg.val, e_ty, new_task);

        bcx = arg.bcx;

        arg_vals += ~[arg.val];
        arg_tys += ~[e_ty];
    }
    // Make the tuple.

    auto args_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, arg_tys);
    // Allocate and fill the tuple.

    auto llargs = alloc_ty(bcx, args_ty);
    auto i = 0u;
    for (ValueRef v in arg_vals) {
        auto target = bcx.build.GEP(llargs.val, ~[C_int(0), C_int(i as int)]);

        bcx.build.Store(v, target);
        i += 1u;
    }

    // Generate the wrapper function
    auto wrapper = mk_spawn_wrapper(bcx, func, args_ty);
    bcx = wrapper.bcx;
    auto llfnptr_i = bcx.build.PointerCast(wrapper.val, T_int());

    // And start the task
    auto llargs_i = bcx.build.PointerCast(llargs.val, T_int());
    auto args_size = size_of(bcx, args_ty).val;
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.start_task,
                   ~[bcx.fcx.lltaskptr, new_task, llfnptr_i, llargs_i,
                     args_size]);
    auto task_ty = node_id_type(bcx.fcx.lcx.ccx, id);
    add_clean_temp(bcx, new_task, task_ty);
    ret rslt(bcx, new_task);
}

fn mk_spawn_wrapper(&@block_ctxt cx, &@ast::expr func, &ty::t args_ty) ->
   result {
    auto llmod = cx.fcx.lcx.ccx.llmod;
    auto wrapper_fn_type =
        type_of_fn(cx.fcx.lcx.ccx, cx.sp, ast::proto_fn,
                   ~[rec(mode=ty::mo_alias(false), ty=args_ty)], ty::idx_nil,
                   0u);
    // TODO: construct a name based on tname

    let str wrap_name =
        mangle_internal_name_by_path_and_seq(cx.fcx.lcx.ccx, cx.fcx.lcx.path,
                                             "spawn_wrapper");
    auto llfndecl = decl_cdecl_fn(llmod, wrap_name, wrapper_fn_type);
    auto fcx = new_fn_ctxt(cx.fcx.lcx, cx.sp, llfndecl);
    auto fbcx = new_top_block_ctxt(fcx);
    // 3u to skip the three implicit args

    let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u);
    let ValueRef[] child_args =
        ~[llvm::LLVMGetParam(fcx.llfn, 0u), llvm::LLVMGetParam(fcx.llfn, 1u),
          llvm::LLVMGetParam(fcx.llfn, 2u)];
    // unpack the arguments

    alt (ty::struct(fcx.lcx.ccx.tcx, args_ty)) {
        case (ty::ty_tup(?elements)) {
            auto i = 0;
            for (ty::mt m in elements) {
                auto src = fbcx.build.GEP(arg, ~[C_int(0), C_int(i)]);
                i += 1;
                auto child_arg = fbcx.build.Load(src);
                child_args += ~[child_arg];
            }
        }
    }
    // Find the function

    auto fnptr = trans_lval(fbcx, func).res;
    fbcx = fnptr.bcx;
    auto llfnptr = fbcx.build.GEP(fnptr.val, ~[C_int(0), C_int(0)]);
    auto llfn = fbcx.build.Load(llfnptr);
    fbcx.build.FastCall(llfn, child_args);
    fbcx.build.RetVoid();
    finish_fn(fcx, fbcx.llbb);
    // TODO: make sure we clean up everything we need to.

    ret rslt(cx, llfndecl);
}

fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
              ast::node_id id) -> result {
    auto bcx = cx;
    auto chn = trans_expr(bcx, lhs);
    bcx = chn.bcx;
    auto data = trans_lval(bcx, rhs);
    bcx = data.res.bcx;
    auto chan_ty = node_id_type(cx.fcx.lcx.ccx, id);
    auto unit_ty;
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, chan_ty)) {
        case (ty::ty_chan(?t)) { unit_ty = t; }
        case (_) { bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send"); }
    }
    auto data_alloc = alloc_ty(bcx, unit_ty);
    bcx = data_alloc.bcx;
    auto data_tmp = move_val_if_temp(bcx, INIT, data_alloc.val,
                                     data, unit_ty);
    bcx = data_tmp.bcx;
    add_clean_temp(bcx, data_alloc.val, unit_ty);
    auto llchanval = bcx.build.PointerCast(chn.val, T_opaque_chan_ptr());
    auto lldataptr = bcx.build.PointerCast(data_alloc.val, T_ptr(T_i8()));
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.send,
                   ~[bcx.fcx.lltaskptr, llchanval, lldataptr]);
    ret rslt(bcx, chn.val);
}

fn trans_recv(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
              ast::node_id id) -> result {
    auto bcx = cx;
    auto data = trans_lval(bcx, rhs);
    assert (data.is_mem);
    bcx = data.res.bcx;
    auto unit_ty = node_id_type(bcx.fcx.lcx.ccx, id);
    // FIXME: calculate copy init-ness in typestate.

    ret recv_val(bcx, data.res.val, lhs, unit_ty, DROP_EXISTING);
}

fn recv_val(&@block_ctxt cx, ValueRef to, &@ast::expr from, &ty::t unit_ty,
            copy_action action) -> result {
    auto bcx = cx;
    auto prt = trans_expr(bcx, from);
    bcx = prt.bcx;
    auto lldataptr = bcx.build.PointerCast(to, T_ptr(T_ptr(T_i8())));
    auto llportptr = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.recv,
                   ~[bcx.fcx.lltaskptr, lldataptr, llportptr]);
    auto data_load = load_if_immediate(bcx, to, unit_ty);
    //auto cp = copy_val(bcx, action, to, data_load, unit_ty);
    //bcx = cp.bcx;

    add_clean_temp(cx, data_load, unit_ty);
    ret rslt(bcx, data_load);
}

// Does a deep copy of a value. This is needed for passing arguments to child
// tasks, and for sending things through channels. There are probably some
// uniqueness optimizations and things we can do here for tasks in the same
// domain.
fn deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t, ValueRef target_task)
    -> result
{
    // TODO: make sure all paths add any reference counting that they need to.

    // TODO: Teach deep copy to understand everything else it needs to.

    auto tcx = bcx.fcx.lcx.ccx.tcx;
    if(ty::type_is_scalar(tcx, t)) {
        ret rslt(bcx, v);
    }
    else if(ty::type_is_str(tcx, t)) {
        ret rslt(bcx,
                bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.dup_str,
                               ~[bcx.fcx.lltaskptr, target_task, v]));
    }
    else if(ty::type_is_chan(tcx, t)) {
        // If this is a channel, we need to clone it.
        auto chan_ptr = bcx.build.PointerCast(v, T_opaque_chan_ptr());

        auto chan_raw_val =
            bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.clone_chan,
                           ~[bcx.fcx.lltaskptr, target_task, chan_ptr]);

        // Cast back to the type the context was expecting.
        auto chan_val = bcx.build.PointerCast(chan_raw_val,
                                              val_ty(v));

        ret rslt(bcx, chan_val);
    }
    else if(ty::type_is_structural(tcx, t)) {
        fn inner_deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t) -> result {
            log_err "Unimplemented type for deep_copy.";
            fail;
        }

        ret iter_structural_ty(bcx, v, t, inner_deep_copy);
    }
    else {
        bcx.fcx.lcx.ccx.sess.bug("unexpected type in " +
                                 "trans::deep_copy: " +
                                 ty_to_str(tcx, t));
    }
}

<commit_msg>Folding recv_val into trans_recv, since this is its only use.<commit_after>/**
   Translation for various task and comm-related things.

   Most of this will probably go away as we move more of this into
   libraries.

*/

import std::str;
import std::option;
import option::none;
import option::some;

import lib::llvm::llvm;
import lib::llvm::llvm::ValueRef;

import util::ppaux::ty_to_str;
import syntax::print::pprust::expr_to_str;
import syntax::ast;
import back::link::mangle_internal_name_by_path_and_seq;

import trans_common::*;
import trans::*;

export trans_port;
export trans_chan;
export trans_spawn;
export trans_send;
export trans_recv;

fn trans_port(&@block_ctxt cx, ast::node_id id) -> result {
    auto t = node_id_type(cx.fcx.lcx.ccx, id);
    auto unit_ty;
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_port(?t)) { unit_ty = t; }
        case (_) { cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port"); }
    }
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
    auto port_raw_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_port,
                       ~[bcx.fcx.lltaskptr, unit_sz.val]);
    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, t);
    auto port_val = bcx.build.PointerCast(port_raw_val, llty);
    add_clean_temp(bcx, port_val, t);
    ret rslt(bcx, port_val);
}

fn trans_chan(&@block_ctxt cx, &@ast::expr e, ast::node_id id) -> result {
    auto bcx = cx;
    auto prt = trans_expr(bcx, e);
    bcx = prt.bcx;
    auto prt_val = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
    auto chan_raw_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_chan,
                       ~[bcx.fcx.lltaskptr, prt_val]);
    auto chan_ty = node_id_type(bcx.fcx.lcx.ccx, id);
    auto chan_llty = type_of(bcx.fcx.lcx.ccx, e.span, chan_ty);
    auto chan_val = bcx.build.PointerCast(chan_raw_val, chan_llty);
    add_clean_temp(bcx, chan_val, chan_ty);
    ret rslt(bcx, chan_val);
}

fn trans_spawn(&@block_ctxt cx, &ast::spawn_dom dom, &option::t[str] name,
               &@ast::expr func, &(@ast::expr)[] args, ast::node_id id)
        -> result {
    auto bcx = cx;
    // Make the task name

    auto tname =
        alt (name) {
            case (none) {
                auto argss = std::ivec::map(expr_to_str, args);
                #fmt("%s(%s)", expr_to_str(func),
                     str::connect_ivec(argss, ", "))
            }
            case (some(?n)) { n }
        };
    // Generate code
    //
    // This is a several step process. The following things need to happen
    // (not necessarily in order):
    //
    // 1. Evaluate all the arguments to the spawnee.
    //
    // 2. Alloca a tuple that holds these arguments (they must be in reverse
    // order, so that they match the expected stack layout for the spawnee)
    //
    // 3. Fill the tuple with the arguments we evaluated.
    //
    // 3.5. Generate a wrapper function that takes the tuple and unpacks it to
    // call the real task.
    //
    // 4. Pass a pointer to the wrapper function and the argument tuple to
    // upcall_start_task. In order to do this, we need to allocate another
    // tuple that matches the arguments expected by rust_task::start.
    //
    // 5. Oh yeah, we have to create the task before we start it...

    // But first, we'll create a task.

    let ValueRef lltname = C_str(bcx.fcx.lcx.ccx, tname);
    auto new_task =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_task,
                       ~[bcx.fcx.lltaskptr, lltname]);

    // Translate the arguments, remembering their types and where the values
    // ended up.

    let ty::t[] arg_tys = ~[];
    let ValueRef[] arg_vals = ~[];
    for (@ast::expr e in args) {
        auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
        auto arg = trans_expr(bcx, e);

        arg = deep_copy(arg.bcx, arg.val, e_ty, new_task);

        bcx = arg.bcx;

        arg_vals += ~[arg.val];
        arg_tys += ~[e_ty];
    }
    // Make the tuple.

    auto args_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, arg_tys);
    // Allocate and fill the tuple.

    auto llargs = alloc_ty(bcx, args_ty);
    auto i = 0u;
    for (ValueRef v in arg_vals) {
        auto target = bcx.build.GEP(llargs.val, ~[C_int(0), C_int(i as int)]);

        bcx.build.Store(v, target);
        i += 1u;
    }

    // Generate the wrapper function
    auto wrapper = mk_spawn_wrapper(bcx, func, args_ty);
    bcx = wrapper.bcx;
    auto llfnptr_i = bcx.build.PointerCast(wrapper.val, T_int());

    // And start the task
    auto llargs_i = bcx.build.PointerCast(llargs.val, T_int());
    auto args_size = size_of(bcx, args_ty).val;
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.start_task,
                   ~[bcx.fcx.lltaskptr, new_task, llfnptr_i, llargs_i,
                     args_size]);
    auto task_ty = node_id_type(bcx.fcx.lcx.ccx, id);
    add_clean_temp(bcx, new_task, task_ty);
    ret rslt(bcx, new_task);
}

fn mk_spawn_wrapper(&@block_ctxt cx, &@ast::expr func, &ty::t args_ty) ->
   result {
    auto llmod = cx.fcx.lcx.ccx.llmod;
    auto wrapper_fn_type =
        type_of_fn(cx.fcx.lcx.ccx, cx.sp, ast::proto_fn,
                   ~[rec(mode=ty::mo_alias(false), ty=args_ty)], ty::idx_nil,
                   0u);
    // TODO: construct a name based on tname

    let str wrap_name =
        mangle_internal_name_by_path_and_seq(cx.fcx.lcx.ccx, cx.fcx.lcx.path,
                                             "spawn_wrapper");
    auto llfndecl = decl_cdecl_fn(llmod, wrap_name, wrapper_fn_type);
    auto fcx = new_fn_ctxt(cx.fcx.lcx, cx.sp, llfndecl);
    auto fbcx = new_top_block_ctxt(fcx);
    // 3u to skip the three implicit args

    let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u);
    let ValueRef[] child_args =
        ~[llvm::LLVMGetParam(fcx.llfn, 0u), llvm::LLVMGetParam(fcx.llfn, 1u),
          llvm::LLVMGetParam(fcx.llfn, 2u)];
    // unpack the arguments

    alt (ty::struct(fcx.lcx.ccx.tcx, args_ty)) {
        case (ty::ty_tup(?elements)) {
            auto i = 0;
            for (ty::mt m in elements) {
                auto src = fbcx.build.GEP(arg, ~[C_int(0), C_int(i)]);
                i += 1;
                auto child_arg = fbcx.build.Load(src);
                child_args += ~[child_arg];
            }
        }
    }
    // Find the function

    auto fnptr = trans_lval(fbcx, func).res;
    fbcx = fnptr.bcx;
    auto llfnptr = fbcx.build.GEP(fnptr.val, ~[C_int(0), C_int(0)]);
    auto llfn = fbcx.build.Load(llfnptr);
    fbcx.build.FastCall(llfn, child_args);
    fbcx.build.RetVoid();
    finish_fn(fcx, fbcx.llbb);
    // TODO: make sure we clean up everything we need to.

    ret rslt(cx, llfndecl);
}

fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
              ast::node_id id) -> result {
    auto bcx = cx;
    auto chn = trans_expr(bcx, lhs);
    bcx = chn.bcx;
    auto data = trans_lval(bcx, rhs);
    bcx = data.res.bcx;
    auto chan_ty = node_id_type(cx.fcx.lcx.ccx, id);
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, chan_ty)) {
        case (ty::ty_chan(?t)) { unit_ty = t; }
        case (_) { bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send"); }
    }
    auto data_alloc = alloc_ty(bcx, unit_ty);
    bcx = data_alloc.bcx;
    auto data_tmp = move_val_if_temp(bcx, INIT, data_alloc.val,
                                     data, unit_ty);
    bcx = data_tmp.bcx;
    add_clean_temp(bcx, data_alloc.val, unit_ty);
    auto llchanval = bcx.build.PointerCast(chn.val, T_opaque_chan_ptr());
    auto lldataptr = bcx.build.PointerCast(data_alloc.val, T_ptr(T_i8()));
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.send,
                   ~[bcx.fcx.lltaskptr, llchanval, lldataptr]);
    ret rslt(bcx, chn.val);
    auto unit_ty;
}

fn trans_recv(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
              ast::node_id id) -> result {
    auto bcx = cx;
    auto data = trans_lval(bcx, rhs);
    assert (data.is_mem);
    bcx = data.res.bcx;
    auto unit_ty = node_id_type(bcx.fcx.lcx.ccx, id);
    // FIXME: calculate copy init-ness in typestate.

    auto prt = trans_expr(bcx, lhs);
    bcx = prt.bcx;
    auto lldataptr = bcx.build.PointerCast(data.res.val,
                                           T_ptr(T_ptr(T_i8())));
    auto llportptr = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.recv,
                   ~[bcx.fcx.lltaskptr, lldataptr, llportptr]);
    auto data_load = load_if_immediate(bcx, data.res.val, unit_ty);
    //auto cp = copy_val(bcx, DROP_EXISTING,
    //                   data.res.val, data_load, unit_ty);
    //bcx = cp.bcx;

    add_clean_temp(cx, data_load, unit_ty);
    ret rslt(bcx, data_load);
}

// Does a deep copy of a value. This is needed for passing arguments to child
// tasks, and for sending things through channels. There are probably some
// uniqueness optimizations and things we can do here for tasks in the same
// domain.
fn deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t, ValueRef target_task)
    -> result
{
    // TODO: make sure all paths add any reference counting that they need to.

    // TODO: Teach deep copy to understand everything else it needs to.

    auto tcx = bcx.fcx.lcx.ccx.tcx;
    if(ty::type_is_scalar(tcx, t)) {
        ret rslt(bcx, v);
    }
    else if(ty::type_is_str(tcx, t)) {
        ret rslt(bcx,
                bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.dup_str,
                               ~[bcx.fcx.lltaskptr, target_task, v]));
    }
    else if(ty::type_is_chan(tcx, t)) {
        // If this is a channel, we need to clone it.
        auto chan_ptr = bcx.build.PointerCast(v, T_opaque_chan_ptr());

        auto chan_raw_val =
            bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.clone_chan,
                           ~[bcx.fcx.lltaskptr, target_task, chan_ptr]);

        // Cast back to the type the context was expecting.
        auto chan_val = bcx.build.PointerCast(chan_raw_val,
                                              val_ty(v));

        ret rslt(bcx, chan_val);
    }
    else if(ty::type_is_structural(tcx, t)) {
        fn inner_deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t) -> result {
            log_err "Unimplemented type for deep_copy.";
            fail;
        }

        ret iter_structural_ty(bcx, v, t, inner_deep_copy);
    }
    else {
        bcx.fcx.lcx.ccx.sess.bug("unexpected type in " +
                                 "trans::deep_copy: " +
                                 ty_to_str(tcx, t));
    }
}

<|endoftext|>


<commit_before>extern crate pkg_config;

use pkg_config::{Config, Error};
use std::env;
use std::io;
use std::io::prelude::*;
use std::process;

fn main() {
    if cfg!(feature = "use_glib") {
        // This include cairo linker flags
        if let Err(s) = find("cairo-gobject", &["cairo", "cairo-gobject"]) {
            let _ = writeln!(io::stderr(), "{}", s);
            process::exit(1);
        }
    } else {
        if let Err(s) = find("cairo", &["cairo"]) {
            let _ = writeln!(io::stderr(), "{}", s);
            process::exit(1);
        }
    }
}

fn find(package_name: &str, shared_libs: &[&str]) -> Result<(), Error> {
    let version = "1.12";

    if let Ok(inc_dir) = env::var("GTK_INCLUDE_DIR") {
        println!("cargo:include={}", inc_dir);
    }
    if let Ok(lib_dir) = env::var("GTK_LIB_DIR") {
        for lib_ in shared_libs.iter() {
            println!("cargo:rustc-link-lib=dylib={}", lib_);
        }
        println!("cargo:rustc-link-search=native={}", lib_dir);
        return Ok(());
    }

    let target = env::var("TARGET").unwrap();
    let hardcode_shared_libs = target.contains("windows");

    let mut config = Config::new();
    config.atleast_version(version);
    config.print_system_libs(false);

    if hardcode_shared_libs {
        config.cargo_metadata(false);
    }
    match config.probe(package_name) {
        Ok(library) => {
            if let Ok(paths) = std::env::join_paths(library.include_paths) {
                // Exposed to other build scripts as DEP_CAIRO_INCLUDE; use env::split_paths
                println!("cargo:include={}", paths.to_string_lossy());
            }
            if hardcode_shared_libs {
                for lib_ in shared_libs.iter() {
                    println!("cargo:rustc-link-lib=dylib={}", lib_);
                }
                for path in library.link_paths.iter() {
                    println!("cargo:rustc-link-search=native={}", path.to_str().unwrap());
                }
            }
            Ok(())
        }
        Err(Error::EnvNoPkgConfig(_)) | Err(Error::Command { .. }) => {
            for lib_ in shared_libs.iter() {
                println!("cargo:rustc-link-lib=dylib={}", lib_);
            }
            Ok(())
        }
        Err(err) => Err(err),
    }
}
<commit_msg>Prevent linking libraries with "dox" feature to avoid documentation failure<commit_after>#[cfg(not(feature = "dox"))]
extern crate pkg_config;

#[cfg(not(feature = "dox"))]
use pkg_config::{Config, Error};
#[cfg(not(feature = "dox"))]
use std::env;
#[cfg(not(feature = "dox"))]
use std::io;
#[cfg(not(feature = "dox"))]
use std::io::prelude::*;
#[cfg(not(feature = "dox"))]
use std::process;

#[cfg(feature = "dox")]
fn main() {} // prevent linking libraries to avoid documentation failure

#[cfg(not(feature = "dox"))]
fn main() {
    if cfg!(feature = "use_glib") {
        // This include cairo linker flags
        if let Err(s) = find("cairo-gobject", &["cairo", "cairo-gobject"]) {
            let _ = writeln!(io::stderr(), "{}", s);
            process::exit(1);
        }
    } else {
        if let Err(s) = find("cairo", &["cairo"]) {
            let _ = writeln!(io::stderr(), "{}", s);
            process::exit(1);
        }
    }
}

#[cfg(not(feature = "dox"))]
fn find(package_name: &str, shared_libs: &[&str]) -> Result<(), Error> {
    let version = "1.12";

    if let Ok(inc_dir) = env::var("GTK_INCLUDE_DIR") {
        println!("cargo:include={}", inc_dir);
    }
    if let Ok(lib_dir) = env::var("GTK_LIB_DIR") {
        for lib_ in shared_libs.iter() {
            println!("cargo:rustc-link-lib=dylib={}", lib_);
        }
        println!("cargo:rustc-link-search=native={}", lib_dir);
        return Ok(());
    }

    let target = env::var("TARGET").unwrap();
    let hardcode_shared_libs = target.contains("windows");

    let mut config = Config::new();
    config.atleast_version(version);
    config.print_system_libs(false);

    if hardcode_shared_libs {
        config.cargo_metadata(false);
    }
    match config.probe(package_name) {
        Ok(library) => {
            if let Ok(paths) = std::env::join_paths(library.include_paths) {
                // Exposed to other build scripts as DEP_CAIRO_INCLUDE; use env::split_paths
                println!("cargo:include={}", paths.to_string_lossy());
            }
            if hardcode_shared_libs {
                for lib_ in shared_libs.iter() {
                    println!("cargo:rustc-link-lib=dylib={}", lib_);
                }
                for path in library.link_paths.iter() {
                    println!("cargo:rustc-link-search=native={}", path.to_str().unwrap());
                }
            }
            Ok(())
        }
        Err(Error::EnvNoPkgConfig(_)) | Err(Error::Command { .. }) => {
            for lib_ in shared_libs.iter() {
                println!("cargo:rustc-link-lib=dylib={}", lib_);
            }
            Ok(())
        }
        Err(err) => Err(err),
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 Developers of the Rand project.

use crate::distributions::{Distribution, Uniform};

/// A distribution to sample items uniformly from a slice.
///
/// [`Slice::new`] constructs a distribution referencing a slice and uniformly
/// samples references from the items in the slice. It may do extra work up
/// front to make sampling of multiple values faster; if only one sample from
/// the slice is required, [`SliceRandom::choose`] can be more efficient.
///
/// Steps are taken to avoid bias which might be present in naive
/// implementations; for example `slice[rng.gen() % slice.len()]` samples from
/// the slice, but may be more likely to select numbers in the low range than
/// other values.
///
/// This distribution samples with replacement; each sample is independent.
/// Sampling without replacement requires state to be retained, and therefore
/// cannot be handled by a distribution; you should instead consider methods
/// on [`SliceRandom`], such as [`SliceRandom::choose_multiple`].
///
/// # Example
///
/// ```
/// use rand::Rng;
/// use rand::distributions::Slice;
///
/// let vowels = ['a', 'e', 'i', 'o', 'u'];
/// let vowels_dist = Slice::new(&vowels).unwrap();
/// let rng = rand::thread_rng();
///
/// // build a string of 10 vowels
/// let vowel_string: String = rng
///     .sample_iter(&vowels_dist)
///     .take(10)
///     .collect();
///
/// println!("{}", vowel_string);
/// assert_eq!(vowel_string.len(), 10);
/// assert!(vowel_string.chars().all(|c| vowels.contains(&c)));
/// ```
///
/// For a single sample, [`SliceRandom::choose`][crate::seq::SliceRandom::choose]
/// may be preferred:
///
/// ```
/// use rand::seq::SliceRandom;
///
/// let vowels = ['a', 'e', 'i', 'o', 'u'];
/// let mut rng = rand::thread_rng();
///
/// println!("{}", vowels.choose(&mut rng).unwrap())
/// ```
///
/// [`SliceRandom`]: crate::seq::SliceRandom
/// [`SliceRandom::choose`]: crate::seq::SliceRandom::choose
/// [`SliceRandom::choose_multiple`]: crate::seq::SliceRandom::choose_multiple
#[derive(Debug)]
pub struct Slice<'a, T> {
    slice: &'a [T],
    range: Uniform<usize>,
}

impl<'a, T> Slice<'a, T> {
    /// Create a new `Slice` instance which samples uniformly from the slice.
    /// Returns `None` if the slice is empty.
    pub fn new(slice: &'a [T]) -> Result<Self, EmptySlice> {
        match slice.len() {
            0 => Err(EmptySlice),
            len => Ok(Self {
                slice,
                range: Uniform::new(0, len),
            }),
        }
    }
}

impl<T> Clone for Slice<'_, T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T> Copy for Slice<'_, T> {}

impl<'a, T> Distribution<&'a T> for Slice<'a, T> {
    fn sample<R: crate::Rng + ?Sized>(&self, rng: &mut R) -> &'a T {
        let idx = self.range.sample(rng);

        debug_assert!(
            idx < self.slice.len(),
            "Uniform::new(0, {}) somehow returned {}",
            self.slice.len(),
            idx
        );

        // Safety: at construction time, it was ensured that the slice was
        // non-empty, and that the `Uniform` range produces values in range
        // for the slice
        unsafe { self.slice.get_unchecked(idx) }
    }
}

/// Error type indicating that a [`Slice`] distribution was improperly
/// constructed with an empty slice.
#[derive(Debug, Clone, Copy)]
pub struct EmptySlice;

impl core::fmt::Display for EmptySlice {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(
            f,
            "Tried to create a `distributions::Slice` with an empty slice"
        )
    }
}

#[cfg(feature = "std")]
impl std::error::Error for EmptySlice {}
<commit_msg>Add missing licence header<commit_after>// Copyright 2021 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::distributions::{Distribution, Uniform};

/// A distribution to sample items uniformly from a slice.
///
/// [`Slice::new`] constructs a distribution referencing a slice and uniformly
/// samples references from the items in the slice. It may do extra work up
/// front to make sampling of multiple values faster; if only one sample from
/// the slice is required, [`SliceRandom::choose`] can be more efficient.
///
/// Steps are taken to avoid bias which might be present in naive
/// implementations; for example `slice[rng.gen() % slice.len()]` samples from
/// the slice, but may be more likely to select numbers in the low range than
/// other values.
///
/// This distribution samples with replacement; each sample is independent.
/// Sampling without replacement requires state to be retained, and therefore
/// cannot be handled by a distribution; you should instead consider methods
/// on [`SliceRandom`], such as [`SliceRandom::choose_multiple`].
///
/// # Example
///
/// ```
/// use rand::Rng;
/// use rand::distributions::Slice;
///
/// let vowels = ['a', 'e', 'i', 'o', 'u'];
/// let vowels_dist = Slice::new(&vowels).unwrap();
/// let rng = rand::thread_rng();
///
/// // build a string of 10 vowels
/// let vowel_string: String = rng
///     .sample_iter(&vowels_dist)
///     .take(10)
///     .collect();
///
/// println!("{}", vowel_string);
/// assert_eq!(vowel_string.len(), 10);
/// assert!(vowel_string.chars().all(|c| vowels.contains(&c)));
/// ```
///
/// For a single sample, [`SliceRandom::choose`][crate::seq::SliceRandom::choose]
/// may be preferred:
///
/// ```
/// use rand::seq::SliceRandom;
///
/// let vowels = ['a', 'e', 'i', 'o', 'u'];
/// let mut rng = rand::thread_rng();
///
/// println!("{}", vowels.choose(&mut rng).unwrap())
/// ```
///
/// [`SliceRandom`]: crate::seq::SliceRandom
/// [`SliceRandom::choose`]: crate::seq::SliceRandom::choose
/// [`SliceRandom::choose_multiple`]: crate::seq::SliceRandom::choose_multiple
#[derive(Debug)]
pub struct Slice<'a, T> {
    slice: &'a [T],
    range: Uniform<usize>,
}

impl<'a, T> Slice<'a, T> {
    /// Create a new `Slice` instance which samples uniformly from the slice.
    /// Returns `None` if the slice is empty.
    pub fn new(slice: &'a [T]) -> Result<Self, EmptySlice> {
        match slice.len() {
            0 => Err(EmptySlice),
            len => Ok(Self {
                slice,
                range: Uniform::new(0, len),
            }),
        }
    }
}

impl<T> Clone for Slice<'_, T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T> Copy for Slice<'_, T> {}

impl<'a, T> Distribution<&'a T> for Slice<'a, T> {
    fn sample<R: crate::Rng + ?Sized>(&self, rng: &mut R) -> &'a T {
        let idx = self.range.sample(rng);

        debug_assert!(
            idx < self.slice.len(),
            "Uniform::new(0, {}) somehow returned {}",
            self.slice.len(),
            idx
        );

        // Safety: at construction time, it was ensured that the slice was
        // non-empty, and that the `Uniform` range produces values in range
        // for the slice
        unsafe { self.slice.get_unchecked(idx) }
    }
}

/// Error type indicating that a [`Slice`] distribution was improperly
/// constructed with an empty slice.
#[derive(Debug, Clone, Copy)]
pub struct EmptySlice;

impl core::fmt::Display for EmptySlice {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(
            f,
            "Tried to create a `distributions::Slice` with an empty slice"
        )
    }
}

#[cfg(feature = "std")]
impl std::error::Error for EmptySlice {}
<|endoftext|>