<commit_before>use rustc::lint::*;
use syntax::ast::*;
use syntax::ext::quote::rt::Span;
use utils::span_note_and_lint;

/// **What it does:** Checks for
///  - () being assigned to a variable
///  - () being passed to a function
///
/// **Why is this bad?** It is extremely unlikely that a user intended to
/// assign '()' to valiable. Instead,
/// Unit is what a block evaluates to when it returns nothing. This is
/// typically caused by a trailing
///   unintended semicolon.
///
/// **Known problems:** None.
///
/// **Example:**
/// * `let x = {"foo" ;}` when the user almost certainly intended `let x
/// ={"foo"}`

declare_lint! {
    pub UNIT_EXPR,
    Warn,
    "unintended assignment or use of a unit typed value"
}

#[derive(Copy, Clone)]
pub struct UnitExpr;

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

impl EarlyLintPass for UnitExpr {
    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if let ExprKind::Assign(ref _left, ref right) = expr.node {
            if let Some(span) = is_unit_expr(right) {
                span_note_and_lint(
                    cx,
                    UNIT_EXPR,
                    expr.span,
                    "This expression evaluates to the Unit type ()",
                    span,
                    "Consider removing the trailing semicolon",
                );
            }
        }
        if let ExprKind::MethodCall(ref _left, ref args) = expr.node {
            for arg in args {
                if let Some(span) = is_unit_expr(arg) {
                    span_note_and_lint(
                        cx,
                        UNIT_EXPR,
                        expr.span,
                        "This expression evaluates to the Unit type ()",
                        span,
                        "Consider removing the trailing semicolon",
                    );
                }
            }
        }
        if let ExprKind::Call(_, ref args) = expr.node {
            for arg in args {
                if let Some(span) = is_unit_expr(arg) {
                    span_note_and_lint(
                        cx,
                        UNIT_EXPR,
                        expr.span,
                        "This expression evaluates to the Unit type ()",
                        span,
                        "Consider removing the trailing semicolon",
                    );
                }
            }
        }
    }

    fn check_stmt(&mut self, cx: &EarlyContext, stmt: &Stmt) {
        if let StmtKind::Local(ref local) = stmt.node {
            if local.pat.node == PatKind::Wild {
                return;
            }
            if let Some(ref expr) = local.init {
                if let Some(span) = is_unit_expr(expr) {
                    span_note_and_lint(
                        cx,
                        UNIT_EXPR,
                        expr.span,
                        "This expression evaluates to the Unit type ()",
                        span,
                        "Consider removing the trailing semicolon",
                    );
                }
            }
        }
    }
}

fn is_unit_expr(expr: &Expr) -> Option<Span> {
    match expr.node {
        ExprKind::Block(ref block) => if check_last_stmt_in_block(block) {
            Some(block.stmts[block.stmts.len() - 1].span)
        } else {
            None
        },
        ExprKind::If(_, ref then, ref else_) => {
            let check_then = check_last_stmt_in_block(then);
            if let Some(ref else_) = *else_ {
                let check_else = is_unit_expr(else_);
                if let Some(ref expr_else) = check_else {
                    return Some(*expr_else);
                }
            }
            if check_then {
                Some(expr.span)
            } else {
                None
            }
        },
        ExprKind::Match(ref _pattern, ref arms) => {
            for arm in arms {
                if let Some(expr) = is_unit_expr(&arm.body) {
                    return Some(expr);
                }
            }
            None
        },
        _ => None,
    }
}

fn check_last_stmt_in_block(block: &Block) -> bool {
    let final_stmt = &block.stmts[block.stmts.len() - 1];

    // Made a choice here to risk false positives on divergent macro invocations
    // like `panic!()`
    match final_stmt.node {
        StmtKind::Expr(_) => false,
        StmtKind::Semi(ref expr) => {
            match expr.node {
                ExprKind::Break(_, _) |
                ExprKind::Continue(_) |
                ExprKind::Ret(_) => false,
                _ => true,
            }
        },
        _ => true,
    }
}
<commit_msg>Fix empty documentation in unit_expr<commit_after>use rustc::lint::*;
use syntax::ast::*;
use syntax::ext::quote::rt::Span;
use utils::span_note_and_lint;

/// **What it does:** Checks for
///  - () being assigned to a variable
///  - () being passed to a function
///
/// **Why is this bad?** It is extremely unlikely that a user intended to
/// assign '()' to valiable. Instead,
/// Unit is what a block evaluates to when it returns nothing. This is
/// typically caused by a trailing
///   unintended semicolon.
///
/// **Known problems:** None.
///
/// **Example:**
/// * `let x = {"foo" ;}` when the user almost certainly intended `let x
/// ={"foo"}`
declare_lint! {
    pub UNIT_EXPR,
    Warn,
    "unintended assignment or use of a unit typed value"
}

#[derive(Copy, Clone)]
pub struct UnitExpr;

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

impl EarlyLintPass for UnitExpr {
    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if let ExprKind::Assign(ref _left, ref right) = expr.node {
            if let Some(span) = is_unit_expr(right) {
                span_note_and_lint(
                    cx,
                    UNIT_EXPR,
                    expr.span,
                    "This expression evaluates to the Unit type ()",
                    span,
                    "Consider removing the trailing semicolon",
                );
            }
        }
        if let ExprKind::MethodCall(ref _left, ref args) = expr.node {
            for arg in args {
                if let Some(span) = is_unit_expr(arg) {
                    span_note_and_lint(
                        cx,
                        UNIT_EXPR,
                        expr.span,
                        "This expression evaluates to the Unit type ()",
                        span,
                        "Consider removing the trailing semicolon",
                    );
                }
            }
        }
        if let ExprKind::Call(_, ref args) = expr.node {
            for arg in args {
                if let Some(span) = is_unit_expr(arg) {
                    span_note_and_lint(
                        cx,
                        UNIT_EXPR,
                        expr.span,
                        "This expression evaluates to the Unit type ()",
                        span,
                        "Consider removing the trailing semicolon",
                    );
                }
            }
        }
    }

    fn check_stmt(&mut self, cx: &EarlyContext, stmt: &Stmt) {
        if let StmtKind::Local(ref local) = stmt.node {
            if local.pat.node == PatKind::Wild {
                return;
            }
            if let Some(ref expr) = local.init {
                if let Some(span) = is_unit_expr(expr) {
                    span_note_and_lint(
                        cx,
                        UNIT_EXPR,
                        expr.span,
                        "This expression evaluates to the Unit type ()",
                        span,
                        "Consider removing the trailing semicolon",
                    );
                }
            }
        }
    }
}

fn is_unit_expr(expr: &Expr) -> Option<Span> {
    match expr.node {
        ExprKind::Block(ref block) => if check_last_stmt_in_block(block) {
            Some(block.stmts[block.stmts.len() - 1].span)
        } else {
            None
        },
        ExprKind::If(_, ref then, ref else_) => {
            let check_then = check_last_stmt_in_block(then);
            if let Some(ref else_) = *else_ {
                let check_else = is_unit_expr(else_);
                if let Some(ref expr_else) = check_else {
                    return Some(*expr_else);
                }
            }
            if check_then {
                Some(expr.span)
            } else {
                None
            }
        },
        ExprKind::Match(ref _pattern, ref arms) => {
            for arm in arms {
                if let Some(expr) = is_unit_expr(&arm.body) {
                    return Some(expr);
                }
            }
            None
        },
        _ => None,
    }
}

fn check_last_stmt_in_block(block: &Block) -> bool {
    let final_stmt = &block.stmts[block.stmts.len() - 1];

    // Made a choice here to risk false positives on divergent macro invocations
    // like `panic!()`
    match final_stmt.node {
        StmtKind::Expr(_) => false,
        StmtKind::Semi(ref expr) => {
            match expr.node {
                ExprKind::Break(_, _) |
                ExprKind::Continue(_) |
                ExprKind::Ret(_) => false,
                _ => true,
            }
        },
        _ => true,
    }
}
<|endoftext|>


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

//! A simple application to run a compute shader.

use std::time::Instant;

use wgpu::util::DeviceExt;

use bytemuck;

async fn run() {
    let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY);
    let adapter = instance.request_adapter(&Default::default()).await.unwrap();
    let features = adapter.features();
    let (device, queue) = adapter
        .request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                features: features & wgpu::Features::TIMESTAMP_QUERY,
                limits: Default::default(),
            },
            None,
        )
        .await
        .unwrap();
    let query_set = if features.contains(wgpu::Features::TIMESTAMP_QUERY) {
        Some(device.create_query_set(&wgpu::QuerySetDescriptor {
            count: 2,
            ty: wgpu::QueryType::Timestamp,
            label: None,
        }))
    } else {
        None
    };

    let start_instant = Instant::now();
    let cs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
        label: None,
        //source: wgpu::ShaderSource::SpirV(bytes_to_u32(include_bytes!("alu.spv")).into()),
        source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
    });
    println!("shader compilation {:?}", start_instant.elapsed());
    let input_f = &[1.0f32, 2.0f32];
    let input : &[u8] = bytemuck::bytes_of(input_f);
    let input_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
        label: None,
        contents: input,
        usage: wgpu::BufferUsages::STORAGE
            | wgpu::BufferUsages::COPY_DST
            | wgpu::BufferUsages::COPY_SRC,
    });
    let output_buf = device.create_buffer(&wgpu::BufferDescriptor {
        label: None,
        size: input.len() as u64,
        usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
        mapped_at_creation: false,
    });
    // This works if the buffer is initialized, otherwise reads all 0, for some reason.
    let query_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
        label: None,
        contents: &[0; 16],
        usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
    });

    let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
        label: None,
        entries: &[
            wgpu::BindGroupLayoutEntry {
                binding: 0,
                visibility: wgpu::ShaderStages::COMPUTE,
                ty: wgpu::BindingType::Buffer {
                    ty: wgpu::BufferBindingType::Storage { read_only: false },
                    has_dynamic_offset: false,
                    min_binding_size: None,
                },
                count: None,
            },
        ],
    });
    let compute_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
        label: None,
        bind_group_layouts: &[&bind_group_layout],
        push_constant_ranges: &[],
    });
    let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
        label: None,
        layout: Some(&compute_pipeline_layout),
        module: &cs_module,
        entry_point: "main",
    });

    let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
        label: None,
        layout: &bind_group_layout,
        entries: &[wgpu::BindGroupEntry {
            binding: 0,
            resource: input_buf.as_entire_binding(),
        }],
    });

    let mut encoder = device.create_command_encoder(&Default::default());
    if let Some(query_set) = &query_set {
        encoder.write_timestamp(query_set, 0);
    }
    {
        let mut cpass = encoder.begin_compute_pass(&Default::default());
        cpass.set_pipeline(&pipeline);
        cpass.set_bind_group(0, &bind_group, &[]);
        cpass.dispatch_workgroups(input_f.len() as u32, 1, 1);
    }
    if let Some(query_set) = &query_set {
        encoder.write_timestamp(query_set, 1);
    }
    encoder.copy_buffer_to_buffer(&input_buf, 0, &output_buf, 0, input.len() as u64);
    if let Some(query_set) = &query_set {
        encoder.resolve_query_set(query_set, 0..2, &query_buf, 0);
    }
    queue.submit(Some(encoder.finish()));

    let buf_slice = output_buf.slice(..);
    let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel();
    buf_slice.map_async(wgpu::MapMode::Read, move |v| sender.send(v).unwrap());
    //let query_slice = query_buf.slice(..);
    //let _query_future = query_slice.map_async(wgpu::MapMode::Read);
    println!("pre-poll {:?}", std::time::Instant::now());
    device.poll(wgpu::Maintain::Wait);
    println!("post-poll {:?}", std::time::Instant::now());
    if let Some(Ok(())) = receiver.receive().await {
        let data_raw = &*buf_slice.get_mapped_range();
        let data : &[f32] = bytemuck::cast_slice(data_raw);
        println!("data: {:?}", &*data);
    }
    /*
    if features.contains(wgpu::Features::TIMESTAMP_QUERY) {
        let ts_period = queue.get_timestamp_period();
        let ts_data_raw = &*query_slice.get_mapped_range();
        let ts_data : &[u64] = bytemuck::cast_slice(ts_data_raw);
        println!("compute shader elapsed: {:?}ms", (ts_data[1] - ts_data[0]) as f64 * ts_period as f64 * 1e-6);
    }
    */
}

fn main() {
    pollster::block_on(run());
}
<commit_msg>Re-add timestamp<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Also licensed under MIT license, at your choice.

//! A simple application to run a compute shader.

use std::time::Instant;

use wgpu::util::DeviceExt;

use bytemuck;

async fn run() {
    let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY);
    let adapter = instance.request_adapter(&Default::default()).await.unwrap();
    let features = adapter.features();
    let (device, queue) = adapter
        .request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                features: features & wgpu::Features::TIMESTAMP_QUERY,
                limits: Default::default(),
            },
            None,
        )
        .await
        .unwrap();
    let query_set = if features.contains(wgpu::Features::TIMESTAMP_QUERY) {
        Some(device.create_query_set(&wgpu::QuerySetDescriptor {
            count: 2,
            ty: wgpu::QueryType::Timestamp,
            label: None,
        }))
    } else {
        None
    };

    let start_instant = Instant::now();
    let cs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
        label: None,
        //source: wgpu::ShaderSource::SpirV(bytes_to_u32(include_bytes!("alu.spv")).into()),
        source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
    });
    println!("shader compilation {:?}", start_instant.elapsed());
    let input_f = &[1.0f32, 2.0f32];
    let input: &[u8] = bytemuck::bytes_of(input_f);
    let input_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
        label: None,
        contents: input,
        usage: wgpu::BufferUsages::STORAGE
            | wgpu::BufferUsages::COPY_DST
            | wgpu::BufferUsages::COPY_SRC,
    });
    let output_buf = device.create_buffer(&wgpu::BufferDescriptor {
        label: None,
        size: input.len() as u64,
        usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
        mapped_at_creation: false,
    });
    // This works if the buffer is initialized, otherwise reads all 0, for some reason.
    let query_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
        label: None,
        contents: &[0; 16],
        usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
    });

    let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
        label: None,
        entries: &[wgpu::BindGroupLayoutEntry {
            binding: 0,
            visibility: wgpu::ShaderStages::COMPUTE,
            ty: wgpu::BindingType::Buffer {
                ty: wgpu::BufferBindingType::Storage { read_only: false },
                has_dynamic_offset: false,
                min_binding_size: None,
            },
            count: None,
        }],
    });
    let compute_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
        label: None,
        bind_group_layouts: &[&bind_group_layout],
        push_constant_ranges: &[],
    });
    let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
        label: None,
        layout: Some(&compute_pipeline_layout),
        module: &cs_module,
        entry_point: "main",
    });

    let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
        label: None,
        layout: &bind_group_layout,
        entries: &[wgpu::BindGroupEntry {
            binding: 0,
            resource: input_buf.as_entire_binding(),
        }],
    });

    let mut encoder = device.create_command_encoder(&Default::default());
    if let Some(query_set) = &query_set {
        encoder.write_timestamp(query_set, 0);
    }
    {
        let mut cpass = encoder.begin_compute_pass(&Default::default());
        cpass.set_pipeline(&pipeline);
        cpass.set_bind_group(0, &bind_group, &[]);
        cpass.dispatch_workgroups(input_f.len() as u32, 1, 1);
    }
    if let Some(query_set) = &query_set {
        encoder.write_timestamp(query_set, 1);
    }
    encoder.copy_buffer_to_buffer(&input_buf, 0, &output_buf, 0, input.len() as u64);
    if let Some(query_set) = &query_set {
        encoder.resolve_query_set(query_set, 0..2, &query_buf, 0);
    }
    queue.submit(Some(encoder.finish()));

    let buf_slice = output_buf.slice(..);
    let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel();
    buf_slice.map_async(wgpu::MapMode::Read, move |v| sender.send(v).unwrap());
    let query_slice = query_buf.slice(..);
    // Assume that both buffers become available at the same time. A more careful
    // approach would be to wait for both notifications to be sent.
    let _query_future = query_slice.map_async(wgpu::MapMode::Read, |_| ());
    println!("pre-poll {:?}", std::time::Instant::now());
    device.poll(wgpu::Maintain::Wait);
    println!("post-poll {:?}", std::time::Instant::now());
    if let Some(Ok(())) = receiver.receive().await {
        let data_raw = &*buf_slice.get_mapped_range();
        let data: &[f32] = bytemuck::cast_slice(data_raw);
        println!("data: {:?}", &*data);
    }
    if features.contains(wgpu::Features::TIMESTAMP_QUERY) {
        let ts_period = queue.get_timestamp_period();
        let ts_data_raw = &*query_slice.get_mapped_range();
        let ts_data: &[u64] = bytemuck::cast_slice(ts_data_raw);
        println!(
            "compute shader elapsed: {:?}ms",
            (ts_data[1] - ts_data[0]) as f64 * ts_period as f64 * 1e-6
        );
    }
}

fn main() {
    pollster::block_on(run());
}
<|endoftext|>


<commit_before>use inflector::Inflector;

use botocore::{Operation, Service};
use super::GenerateProtocol;

pub struct JsonGenerator;

impl GenerateProtocol for JsonGenerator {
    fn generate_methods(&self, service: &Service) -> String {
        service.operations.values().map(|operation| {
            let output_type = operation.output_shape_or("()");

            format!("
                {documentation}
                pub fn {method_name}(&mut self, input: &{input_type}) -> Result<{output_type}> {{
                    let encoded = serde_json::to_string(input).unwrap();
                    let mut request = SignedRequest::new(\"{http_method}\", \"{endpoint_prefix}\", &self.region, \"{request_uri}\");
                    request.set_content_type(\"application/x-amz-json-1.0\".to_owned());
                    request.add_header(\"x-amz-target\", \"{target_prefix}.{name}\");
                    request.set_payload(Some(encoded.as_bytes()));
                    let mut result = request.sign_and_execute(try!(self.credentials_provider.credentials()));
                    let status = result.status.to_u16();
                    let mut body = String::new();
                    result.read_to_string(&mut body).unwrap();
                    match status {{
                        200 => {{
                            {ok_response}
                        }}
                        _ => Err(parse_error(&body)),
                    }}
                }}
                ",
                documentation = generate_documentation(operation).unwrap_or("".to_owned()),
                endpoint_prefix = service.metadata.endpoint_prefix,
                http_method = operation.http.method,
                input_type = operation.input_shape(),
                method_name = operation.name.to_snake_case(),
                name = operation.name,
                ok_response = generate_ok_response(operation, output_type),
                output_type = output_type,
                request_uri = operation.http.request_uri,
                target_prefix = service.metadata.target_prefix.as_ref().unwrap(),
            )
        }).collect::<Vec<String>>().join("\n")
    }

    fn generate_prelude(&self, service: &Service) -> String {
        format!(
            "use std::io::Read;
            use std::result;

            use serde_json;

            use credentials::ProvideAWSCredentials;
            use error::AWSError;
            use regions::Region;
            use signature::SignedRequest;

            /// An error produced when {service_name} API calls are unsuccessful.
            #[derive(Debug, Default, Deserialize)]
            pub struct {error_type_name} {{
                __type: String,
                message: String,
            }}

            /// The result type produced by {service_name} API calls.
            pub type Result<T> = result::Result<T, {error_type_name}>;

            impl From<AWSError> for {error_type_name} {{
                fn from(err: AWSError) -> Self {{
                    let AWSError(message) = err;

                    {error_type_name} {{
                        __type: \"Unknown\".to_string(),
                        message: message.to_string(),
                    }}
                }}
            }}

            fn parse_error(body: &str) -> {error_type_name} {{
                if let Ok(decoded) = serde_json::from_str::<{error_type_name}>(&body) {{
                    decoded
                }} else {{
                    {error_type_name} {{
                        __type: \"DecodeError\".to_string(),
                        message: body.to_string(),
                    }}
                }}
            }}
            ",
            error_type_name = service.error_type_name(),
            service_name = &service.metadata.service_abbreviation,
        )
    }

    fn generate_struct_attributes(&self) -> String {
        "#[derive(Debug, Default, Deserialize, Serialize)]".to_owned()
    }

}

fn generate_documentation(operation: &Operation) -> Option<String> {
    operation.documentation.as_ref().map(|docs| {
        format!("#[doc=\"{}\"]", docs.replace("\"", "\\\""))
    })
}

fn generate_ok_response(operation: &Operation, output_type: &str) -> String {
    if operation.output.is_some() {
        format!("Ok(serde_json::from_str::<{}>(&body).unwrap())", output_type)
    } else {
        "Ok(())".to_owned()
    }
}
<commit_msg>Derive PartialEq for JSON protocol error types.<commit_after>use inflector::Inflector;

use botocore::{Operation, Service};
use super::GenerateProtocol;

pub struct JsonGenerator;

impl GenerateProtocol for JsonGenerator {
    fn generate_methods(&self, service: &Service) -> String {
        service.operations.values().map(|operation| {
            let output_type = operation.output_shape_or("()");

            format!("
                {documentation}
                pub fn {method_name}(&mut self, input: &{input_type}) -> Result<{output_type}> {{
                    let encoded = serde_json::to_string(input).unwrap();
                    let mut request = SignedRequest::new(\"{http_method}\", \"{endpoint_prefix}\", &self.region, \"{request_uri}\");
                    request.set_content_type(\"application/x-amz-json-1.0\".to_owned());
                    request.add_header(\"x-amz-target\", \"{target_prefix}.{name}\");
                    request.set_payload(Some(encoded.as_bytes()));
                    let mut result = request.sign_and_execute(try!(self.credentials_provider.credentials()));
                    let status = result.status.to_u16();
                    let mut body = String::new();
                    result.read_to_string(&mut body).unwrap();
                    match status {{
                        200 => {{
                            {ok_response}
                        }}
                        _ => Err(parse_error(&body)),
                    }}
                }}
                ",
                documentation = generate_documentation(operation).unwrap_or("".to_owned()),
                endpoint_prefix = service.metadata.endpoint_prefix,
                http_method = operation.http.method,
                input_type = operation.input_shape(),
                method_name = operation.name.to_snake_case(),
                name = operation.name,
                ok_response = generate_ok_response(operation, output_type),
                output_type = output_type,
                request_uri = operation.http.request_uri,
                target_prefix = service.metadata.target_prefix.as_ref().unwrap(),
            )
        }).collect::<Vec<String>>().join("\n")
    }

    fn generate_prelude(&self, service: &Service) -> String {
        format!(
            "use std::io::Read;
            use std::result;

            use serde_json;

            use credentials::ProvideAWSCredentials;
            use error::AWSError;
            use regions::Region;
            use signature::SignedRequest;

            /// An error produced when {service_name} API calls are unsuccessful.
            #[derive(Debug, Default, Deserialize, PartialEq)]
            pub struct {error_type_name} {{
                __type: String,
                message: String,
            }}

            /// The result type produced by {service_name} API calls.
            pub type Result<T> = result::Result<T, {error_type_name}>;

            impl From<AWSError> for {error_type_name} {{
                fn from(err: AWSError) -> Self {{
                    let AWSError(message) = err;

                    {error_type_name} {{
                        __type: \"Unknown\".to_string(),
                        message: message.to_string(),
                    }}
                }}
            }}

            fn parse_error(body: &str) -> {error_type_name} {{
                if let Ok(decoded) = serde_json::from_str::<{error_type_name}>(&body) {{
                    decoded
                }} else {{
                    {error_type_name} {{
                        __type: \"DecodeError\".to_string(),
                        message: body.to_string(),
                    }}
                }}
            }}
            ",
            error_type_name = service.error_type_name(),
            service_name = &service.metadata.service_abbreviation,
        )
    }

    fn generate_struct_attributes(&self) -> String {
        "#[derive(Debug, Default, Deserialize, Serialize)]".to_owned()
    }

}

fn generate_documentation(operation: &Operation) -> Option<String> {
    operation.documentation.as_ref().map(|docs| {
        format!("#[doc=\"{}\"]", docs.replace("\"", "\\\""))
    })
}

fn generate_ok_response(operation: &Operation, output_type: &str) -> String {
    if operation.output.is_some() {
        format!("Ok(serde_json::from_str::<{}>(&body).unwrap())", output_type)
    } else {
        "Ok(())".to_owned()
    }
}
<|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/. */

#![macro_use]

// Provides the implementation of a CEF class. An example follows:
//
//    struct ServoCefThing {
//        ...
//    }
//
//    cef_class_impl! {
//        ServoCefThing : CefThing, cef_thing_t {
//            // Declare method implementations using the *C* API. (This may change later, once we
//            // have associated types in Rust.)
//            //
//            // Note that if the method returns unit, you must write `-> ()` explicitly. This is
//            // due to limitations of Rust's macro system.
//            fn foo(&this, a: isize, b: *mut cef_other_thing_t) -> () {
//                // Inside here, `a` will have type `isize`, and `b` will have the type
//                // `CefOtherThing` -- i.e. the Rust-wrapped version of `cef_other_thing_t`.
//                ...
//            }
//
//            fn bar(&this, a: isize) -> *mut cef_other_thing_t {
//                // Return types are automatically unwrapped from the Rust types (e.g.
//                // `CefOtherThing`) into the corresponding C types (e.g. `*mut
//                // cef_other_thing_t`).
//                let x: CefOtherThing = ...;
//                x
//            }
//        }
//    }
macro_rules! cef_class_impl(
    ($class_name:ident : $interface_name:ident, $c_interface_name:ident {
        $(
            fn $method_name:ident ( & $method_this:ident ,
                                   $( $method_arg_name:ident : $c_method_arg_type:ty ,)* )
                                   -> $method_return_type:ty {$method_body:block}
        )*
    }) => (
        full_cef_class_impl! {
            $class_name : $interface_name, $c_interface_name {
                $(fn $method_name(&$method_this,
                                  $($method_arg_name : $c_method_arg_type [$c_method_arg_type],)*)
                                  -> $method_return_type {
                    $method_body
                })*
            }
        }
    )
);

macro_rules! full_cef_class_impl(
    ($class_name:ident : $interface_name:ident, $c_interface_name:ident {
        $(
            fn $method_name:ident ( & $method_this:ident ,
                                   $( $method_arg_name:ident : $c_method_arg_type:ty [$method_arg_type:ty] ,)* )
                                   -> $method_return_type:ty {$method_body:block}
        )*
    }) => (
        impl $class_name {
            pub fn as_cef_interface(self) -> $interface_name {
                let cef_object = unsafe {
                    // Calculate the offset of the reference count. This is the size of the
                    // structure.
                    let null: *const $c_interface_name = ::std::ptr::null();
                    let offset: *const u32 = &(*null).ref_count;
                    let size = (offset as ::libc::size_t) - (null as ::libc::size_t);
                    $interface_name::from_c_object_addref(
                        ::eutil::create_cef_object::<$c_interface_name,$class_name>(size))
                };
                unsafe {
                    $((*cef_object.c_object()).$method_name = Some($method_name as extern "C" fn(*mut $c_interface_name, $($c_method_arg_type,)*) -> $method_return_type);)*
                    let extra_slot =
                        ::std::mem::transmute::<&mut u8,
                                                &mut $class_name>(&mut (*cef_object.c_object())
                                                                                .extra);
                    ::std::ptr::write(extra_slot, self);
                }
                cef_object
            }
        }

        $(
            extern "C" fn $method_name(raw_this: *mut $c_interface_name,
                                       $($method_arg_name: $c_method_arg_type),*)
                                       -> $method_return_type {
                let $method_this = unsafe {
                    $interface_name::from_c_object_addref(raw_this)
                };
                $(
                    let $method_arg_name: $method_arg_type = unsafe {
                        ::wrappers::CefWrap::to_rust($method_arg_name)
                    };
                )*
                ::wrappers::CefWrap::to_c($method_body)
            }
        )*

        impl ::eutil::Downcast<$class_name> for $interface_name {
            fn downcast(&self) -> &$class_name {
                unsafe {
                    ::std::mem::transmute::<&u8,&$class_name>(&(*self.c_object()).extra)
                }
            }
        }
    )
);

macro_rules! cef_static_method_impls(
    (
        $(
            fn $method_name:ident ( $($method_arg_name:ident : $method_arg_type:ty ),* )
                                   -> $method_return_type:ty {$method_body:block}
        )*
    ) => (
        $(
            #[no_mangle]
            pub extern "C" fn $method_name($($method_arg_name: $method_arg_type),*)
                                           -> $method_return_type {
                $(
                    let $method_arg_name = unsafe {
                        ::wrappers::CefWrap::to_rust($method_arg_name)
                    };
                )*
                ::wrappers::CefWrap::to_c($method_body)
            }
        )*
    )
);

macro_rules! cef_stub_static_method_impls(
    (
        $(
            fn $method_name:ident ( $($method_arg_name:ident : $method_arg_type:ty ),* )
                                   -> $method_return_type:ty
        )*
    ) => (
        $(
            #[no_mangle]
            pub extern "C" fn $method_name($(_: $method_arg_type),*)
                                           -> $method_return_type {
                panic!("unimplemented static method: {}", stringify!($method_name))
            }
        )*
    )
);
<commit_msg>add embedding macro for checking pointer existence<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/. */

#![macro_use]

macro_rules! check_ptr_exist {
    ($var:expr, $member:ident) => (
        unsafe { (*CefWrap::to_c($var)).$member.is_some() }
    );
}

// Provides the implementation of a CEF class. An example follows:
//
//    struct ServoCefThing {
//        ...
//    }
//
//    cef_class_impl! {
//        ServoCefThing : CefThing, cef_thing_t {
//            // Declare method implementations using the *C* API. (This may change later, once we
//            // have associated types in Rust.)
//            //
//            // Note that if the method returns unit, you must write `-> ()` explicitly. This is
//            // due to limitations of Rust's macro system.
//            fn foo(&this, a: isize, b: *mut cef_other_thing_t) -> () {
//                // Inside here, `a` will have type `isize`, and `b` will have the type
//                // `CefOtherThing` -- i.e. the Rust-wrapped version of `cef_other_thing_t`.
//                ...
//            }
//
//            fn bar(&this, a: isize) -> *mut cef_other_thing_t {
//                // Return types are automatically unwrapped from the Rust types (e.g.
//                // `CefOtherThing`) into the corresponding C types (e.g. `*mut
//                // cef_other_thing_t`).
//                let x: CefOtherThing = ...;
//                x
//            }
//        }
//    }
macro_rules! cef_class_impl(
    ($class_name:ident : $interface_name:ident, $c_interface_name:ident {
        $(
            fn $method_name:ident ( & $method_this:ident ,
                                   $( $method_arg_name:ident : $c_method_arg_type:ty ,)* )
                                   -> $method_return_type:ty {$method_body:block}
        )*
    }) => (
        full_cef_class_impl! {
            $class_name : $interface_name, $c_interface_name {
                $(fn $method_name(&$method_this,
                                  $($method_arg_name : $c_method_arg_type [$c_method_arg_type],)*)
                                  -> $method_return_type {
                    $method_body
                })*
            }
        }
    )
);

macro_rules! full_cef_class_impl(
    ($class_name:ident : $interface_name:ident, $c_interface_name:ident {
        $(
            fn $method_name:ident ( & $method_this:ident ,
                                   $( $method_arg_name:ident : $c_method_arg_type:ty [$method_arg_type:ty] ,)* )
                                   -> $method_return_type:ty {$method_body:block}
        )*
    }) => (
        impl $class_name {
            pub fn as_cef_interface(self) -> $interface_name {
                let cef_object = unsafe {
                    // Calculate the offset of the reference count. This is the size of the
                    // structure.
                    let null: *const $c_interface_name = ::std::ptr::null();
                    let offset: *const u32 = &(*null).ref_count;
                    let size = (offset as ::libc::size_t) - (null as ::libc::size_t);
                    $interface_name::from_c_object_addref(
                        ::eutil::create_cef_object::<$c_interface_name,$class_name>(size))
                };
                unsafe {
                    $((*cef_object.c_object()).$method_name = Some($method_name as extern "C" fn(*mut $c_interface_name, $($c_method_arg_type,)*) -> $method_return_type);)*
                    let extra_slot =
                        ::std::mem::transmute::<&mut u8,
                                                &mut $class_name>(&mut (*cef_object.c_object())
                                                                                .extra);
                    ::std::ptr::write(extra_slot, self);
                }
                cef_object
            }
        }

        $(
            extern "C" fn $method_name(raw_this: *mut $c_interface_name,
                                       $($method_arg_name: $c_method_arg_type),*)
                                       -> $method_return_type {
                let $method_this = unsafe {
                    $interface_name::from_c_object_addref(raw_this)
                };
                $(
                    let $method_arg_name: $method_arg_type = unsafe {
                        ::wrappers::CefWrap::to_rust($method_arg_name)
                    };
                )*
                ::wrappers::CefWrap::to_c($method_body)
            }
        )*

        impl ::eutil::Downcast<$class_name> for $interface_name {
            fn downcast(&self) -> &$class_name {
                unsafe {
                    ::std::mem::transmute::<&u8,&$class_name>(&(*self.c_object()).extra)
                }
            }
        }
    )
);

macro_rules! cef_static_method_impls(
    (
        $(
            fn $method_name:ident ( $($method_arg_name:ident : $method_arg_type:ty ),* )
                                   -> $method_return_type:ty {$method_body:block}
        )*
    ) => (
        $(
            #[no_mangle]
            pub extern "C" fn $method_name($($method_arg_name: $method_arg_type),*)
                                           -> $method_return_type {
                $(
                    let $method_arg_name = unsafe {
                        ::wrappers::CefWrap::to_rust($method_arg_name)
                    };
                )*
                ::wrappers::CefWrap::to_c($method_body)
            }
        )*
    )
);

macro_rules! cef_stub_static_method_impls(
    (
        $(
            fn $method_name:ident ( $($method_arg_name:ident : $method_arg_type:ty ),* )
                                   -> $method_return_type:ty
        )*
    ) => (
        $(
            #[no_mangle]
            pub extern "C" fn $method_name($(_: $method_arg_type),*)
                                           -> $method_return_type {
                panic!("unimplemented static method: {}", stringify!($method_name))
            }
        )*
    )
);
<|endoftext|>


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

//! Mining plugin manager, using the cuckoo-miner crate to provide
//! a mining worker implementation
//!

use chrono::prelude::Utc;
use chrono::Duration;
use std::net::{SocketAddr, ToSocketAddrs};
use std::str;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::thread;
use std::time;

use api;

use p2p;
use pool::DandelionConfig;
use util::LOGGER;

const SEEDS_URL: &'static str = "http://grin-tech.org/seeds.txt";
// DNS Seeds with contact email associated
const DNS_SEEDS: &'static [&'static str] = &[
	"t3.seed.grin-tech.org", // igno.peverell@protonmail.com
];

pub fn connect_and_monitor(
	p2p_server: Arc<p2p::Server>,
	capabilities: p2p::Capabilities,
	dandelion_config: DandelionConfig,
	seed_list: Box<Fn() -> Vec<SocketAddr> + Send>,
	preferred_peers: Option<Vec<SocketAddr>>,
	stop: Arc<AtomicBool>,
) {
	let _ = thread::Builder::new()
		.name("seed".to_string())
		.spawn(move || {
			let peers = p2p_server.peers.clone();

			// open a channel with a listener that connects every peer address sent below
			// max peer count
			let (tx, rx) = mpsc::channel();

			// check seeds first
			connect_to_seeds_and_preferred_peers(
				peers.clone(),
				tx.clone(),
				seed_list,
				preferred_peers.clone(),
			);

			let mut prev = Utc::now() - Duration::seconds(60);
			let mut start_attempt = 0;
			let start_wait_base: i64 = 2;
			loop {
				let current_time = Utc::now();

				// make several attempts to get peers as quick as possible with
				// exponential backoff
				if (peers.peer_count() < p2p_server.config.peer_min_preferred_count()
					&& current_time - prev > Duration::seconds(start_wait_base.pow(start_attempt)))
					|| current_time - prev > Duration::seconds(20)
				{
					// try to connect to any address sent to the channel
					listen_for_addrs(peers.clone(), p2p_server.clone(), capabilities, &rx);

					// monitor additional peers if we need to add more
					monitor_peers(
						peers.clone(),
						p2p_server.config.clone(),
						capabilities,
						tx.clone(),
						preferred_peers.clone(),
					);

					update_dandelion_relay(peers.clone(), dandelion_config.clone());

					prev = current_time;
					if start_attempt < 6 {
						start_attempt += 1;
					}
				}

				thread::sleep(time::Duration::from_secs(1));

				if stop.load(Ordering::Relaxed) {
					break;
				}
			}
		});
}

fn monitor_peers(
	peers: Arc<p2p::Peers>,
	config: p2p::P2PConfig,
	capabilities: p2p::Capabilities,
	tx: mpsc::Sender<SocketAddr>,
	preferred_peers_list: Option<Vec<SocketAddr>>,
) {
	// regularly check if we need to acquire more peers  and if so, gets
	// them from db
	let total_count = peers.all_peers().len();
	let mut healthy_count = 0;
	let mut banned_count = 0;
	let mut defunct_count = 0;
	for x in peers.all_peers() {
		match x.flags {
			p2p::State::Banned => {
				let interval = Utc::now().timestamp() - x.last_banned;
				// Unban peer
				if interval >= config.ban_window() {
					peers.unban_peer(&x.addr);
					debug!(
						LOGGER,
						"monitor_peers: unbanned {} after {} seconds", x.addr, interval
					);
				} else {
					banned_count += 1;
				}
			}
			p2p::State::Healthy => healthy_count += 1,
			p2p::State::Defunct => defunct_count += 1,
		}
	}

	debug!(
		LOGGER,
		"monitor_peers: {} connected ({} most_work). \
		 all {} = {} healthy + {} banned + {} defunct",
		peers.peer_count(),
		peers.most_work_peers().len(),
		total_count,
		healthy_count,
		banned_count,
		defunct_count,
	);

	// maintenance step first, clean up p2p server peers
	peers.clean_peers(config.peer_max_count() as usize);

	// not enough peers, getting more from db
	if peers.peer_count() >= config.peer_min_preferred_count() {
		return;
	}

	// loop over connected peers
	// ask them for their list of peers
	let mut connected_peers: Vec<SocketAddr> = vec![];
	for p in peers.connected_peers() {
		if let Ok(p) = p.try_read() {
			debug!(LOGGER, "monitor_peers: ask {} for more peers", p.info.addr);
			let _ = p.send_peer_request(capabilities);
			connected_peers.push(p.info.addr)
		} else {
			warn!(LOGGER, "monitor_peers: failed to get read lock on peer");
		}
	}

	// Attempt to connect to preferred peers if there is some
	match preferred_peers_list {
		Some(preferred_peers) => {
			for mut p in preferred_peers {
				if !connected_peers.is_empty() {
					if connected_peers.contains(&p) {
						tx.send(p).unwrap();
					}
				}
			}
		}
		None => debug!(LOGGER, "monitor_peers: no preferred peers"),
	}

	// find some peers from our db
	// and queue them up for a connection attempt
	let new_peers = peers.find_peers(
		p2p::State::Healthy,
		p2p::Capabilities::UNKNOWN,
		config.peer_max_count() as usize,
	);
	for p in new_peers.iter().filter(|p| !peers.is_known(&p.addr)) {
		debug!(LOGGER, "monitor_peers: queue to soon try {}", p.addr);
		tx.send(p.addr).unwrap();
	}
}

fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: DandelionConfig) {
	// Dandelion Relay Updater
	let dandelion_relay = peers.get_dandelion_relay();
	if dandelion_relay.is_empty() {
		debug!(LOGGER, "monitor_peers: no dandelion relay updating");
		peers.update_dandelion_relay();
	} else {
		for last_added in dandelion_relay.keys() {
			let dandelion_interval = Utc::now().timestamp() - last_added;
			if dandelion_interval >= dandelion_config.relay_secs.unwrap() as i64 {
				debug!(LOGGER, "monitor_peers: updating expired dandelion relay");
				peers.update_dandelion_relay();
			}
		}
	}
}

// Check if we have any pre-existing peer in db. If so, start with those,
// otherwise use the seeds provided.
fn connect_to_seeds_and_preferred_peers(
	peers: Arc<p2p::Peers>,
	tx: mpsc::Sender<SocketAddr>,
	seed_list: Box<Fn() -> Vec<SocketAddr>>,
	peers_preferred_list: Option<Vec<SocketAddr>>,
) {
	// check if we have some peers in db
	let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::FULL_HIST, 100);

	// if so, get their addresses, otherwise use our seeds
	let mut peer_addrs = if peers.len() > 3 {
		peers.iter().map(|p| p.addr).collect::<Vec<_>>()
	} else {
		seed_list()
	};

	// If we have preferred peers add them to the connection
	match peers_preferred_list {
		Some(mut peers_preferred) => peer_addrs.append(&mut peers_preferred),
		None => debug!(LOGGER, "No preferred peers"),
	};

	if peer_addrs.len() == 0 {
		warn!(LOGGER, "No seeds were retrieved.");
	}

	// connect to this first set of addresses
	for addr in peer_addrs {
		tx.send(addr).unwrap();
	}
}

/// Regularly poll a channel receiver for new addresses and initiate a
/// connection if the max peer count isn't exceeded. A request for more
/// peers is also automatically sent after connection.
fn listen_for_addrs(
	peers: Arc<p2p::Peers>,
	p2p: Arc<p2p::Server>,
	capab: p2p::Capabilities,
	rx: &mpsc::Receiver<SocketAddr>,
) {
	let pc = peers.peer_count();
	for addr in rx.try_iter() {
		if pc < p2p.config.peer_max_count() {
			let peers_c = peers.clone();
			let p2p_c = p2p.clone();
			let _ = thread::Builder::new()
				.name("peer_connect".to_string())
				.spawn(move || {
					let connect_peer = p2p_c.connect(&addr);
					match connect_peer {
						Ok(p) => {
							trace!(LOGGER, "connect_and_req: ok. attempting send_peer_request");
							if let Ok(p) = p.try_read() {
								let _ = p.send_peer_request(capab);
							}
						}
						Err(e) => {
							debug!(LOGGER, "connect_and_req: {} is Defunct; {:?}", addr, e);
							let _ = peers_c.update_state(addr, p2p::State::Defunct);
						}
					}
				});
		}
	}
}

pub fn dns_seeds() -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(|| {
		let mut addresses: Vec<SocketAddr> = vec![];
		for dns_seed in DNS_SEEDS {
			let temp_addresses = addresses.clone();
			debug!(LOGGER, "Retrieving seed nodes from dns {}", dns_seed);
			match (dns_seed.to_owned(), 0).to_socket_addrs() {
				Ok(addrs) => addresses.append(
					&mut (addrs
						.map(|mut addr| {
							addr.set_port(13414);
							addr
						})
						.filter(|addr| !temp_addresses.contains(addr))
						.collect()),
				),
				Err(e) => debug!(
					LOGGER,
					"Failed to resolve seed {:?} got error {:?}", dns_seed, e
				),
			}
		}
		addresses
	})
}

/// Extract the list of seeds from a pre-defined text file available through
/// http. Easy method until we have a set of DNS names we can rely on.
pub fn web_seeds() -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(|| {
		let text: String = api::client::get(SEEDS_URL).expect("Failed to resolve seeds");
		let addrs = text
			.split_whitespace()
			.map(|s| s.parse().unwrap())
			.collect::<Vec<_>>();
		debug!(LOGGER, "Retrieved seed addresses: {:?}", addrs);
		addrs
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn predefined_seeds(addrs_str: Vec<String>) -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(move || {
		addrs_str
			.iter()
			.map(|s| s.parse().unwrap())
			.collect::<Vec<_>>()
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn preferred_peers(addrs_str: Vec<String>) -> Option<Vec<SocketAddr>> {
	if addrs_str.is_empty() {
		None
	} else {
		Some(
			addrs_str
				.iter()
				.map(|s| s.parse().unwrap())
				.collect::<Vec<_>>(),
		)
	}
}
<commit_msg>Missing logic in preferred peers (#1471)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Mining plugin manager, using the cuckoo-miner crate to provide
//! a mining worker implementation
//!

use chrono::prelude::Utc;
use chrono::Duration;
use std::net::{SocketAddr, ToSocketAddrs};
use std::str;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::thread;
use std::time;

use api;

use p2p;
use pool::DandelionConfig;
use util::LOGGER;

const SEEDS_URL: &'static str = "http://grin-tech.org/seeds.txt";
// DNS Seeds with contact email associated
const DNS_SEEDS: &'static [&'static str] = &[
	"t3.seed.grin-tech.org", // igno.peverell@protonmail.com
];

pub fn connect_and_monitor(
	p2p_server: Arc<p2p::Server>,
	capabilities: p2p::Capabilities,
	dandelion_config: DandelionConfig,
	seed_list: Box<Fn() -> Vec<SocketAddr> + Send>,
	preferred_peers: Option<Vec<SocketAddr>>,
	stop: Arc<AtomicBool>,
) {
	let _ = thread::Builder::new()
		.name("seed".to_string())
		.spawn(move || {
			let peers = p2p_server.peers.clone();

			// open a channel with a listener that connects every peer address sent below
			// max peer count
			let (tx, rx) = mpsc::channel();

			// check seeds first
			connect_to_seeds_and_preferred_peers(
				peers.clone(),
				tx.clone(),
				seed_list,
				preferred_peers.clone(),
			);

			let mut prev = Utc::now() - Duration::seconds(60);
			let mut start_attempt = 0;
			let start_wait_base: i64 = 2;
			loop {
				let current_time = Utc::now();

				// make several attempts to get peers as quick as possible with
				// exponential backoff
				if (peers.peer_count() < p2p_server.config.peer_min_preferred_count()
					&& current_time - prev > Duration::seconds(start_wait_base.pow(start_attempt)))
					|| current_time - prev > Duration::seconds(20)
				{
					// try to connect to any address sent to the channel
					listen_for_addrs(peers.clone(), p2p_server.clone(), capabilities, &rx);

					// monitor additional peers if we need to add more
					monitor_peers(
						peers.clone(),
						p2p_server.config.clone(),
						capabilities,
						tx.clone(),
						preferred_peers.clone(),
					);

					update_dandelion_relay(peers.clone(), dandelion_config.clone());

					prev = current_time;
					if start_attempt < 6 {
						start_attempt += 1;
					}
				}

				thread::sleep(time::Duration::from_secs(1));

				if stop.load(Ordering::Relaxed) {
					break;
				}
			}
		});
}

fn monitor_peers(
	peers: Arc<p2p::Peers>,
	config: p2p::P2PConfig,
	capabilities: p2p::Capabilities,
	tx: mpsc::Sender<SocketAddr>,
	preferred_peers_list: Option<Vec<SocketAddr>>,
) {
	// regularly check if we need to acquire more peers  and if so, gets
	// them from db
	let total_count = peers.all_peers().len();
	let mut healthy_count = 0;
	let mut banned_count = 0;
	let mut defunct_count = 0;
	for x in peers.all_peers() {
		match x.flags {
			p2p::State::Banned => {
				let interval = Utc::now().timestamp() - x.last_banned;
				// Unban peer
				if interval >= config.ban_window() {
					peers.unban_peer(&x.addr);
					debug!(
						LOGGER,
						"monitor_peers: unbanned {} after {} seconds", x.addr, interval
					);
				} else {
					banned_count += 1;
				}
			}
			p2p::State::Healthy => healthy_count += 1,
			p2p::State::Defunct => defunct_count += 1,
		}
	}

	debug!(
		LOGGER,
		"monitor_peers: {} connected ({} most_work). \
		 all {} = {} healthy + {} banned + {} defunct",
		peers.peer_count(),
		peers.most_work_peers().len(),
		total_count,
		healthy_count,
		banned_count,
		defunct_count,
	);

	// maintenance step first, clean up p2p server peers
	peers.clean_peers(config.peer_max_count() as usize);

	// not enough peers, getting more from db
	if peers.peer_count() >= config.peer_min_preferred_count() {
		return;
	}

	// loop over connected peers
	// ask them for their list of peers
	let mut connected_peers: Vec<SocketAddr> = vec![];
	for p in peers.connected_peers() {
		if let Ok(p) = p.try_read() {
			debug!(LOGGER, "monitor_peers: ask {} for more peers", p.info.addr);
			let _ = p.send_peer_request(capabilities);
			connected_peers.push(p.info.addr)
		} else {
			warn!(LOGGER, "monitor_peers: failed to get read lock on peer");
		}
	}

	// Attempt to connect to preferred peers if there is some
	match preferred_peers_list {
		Some(preferred_peers) => {
			for mut p in preferred_peers {
				if !connected_peers.is_empty() {
					if !connected_peers.contains(&p) {
						tx.send(p).unwrap();
					}
				} else {
					tx.send(p).unwrap();
				}
			}
		}
		None => debug!(LOGGER, "monitor_peers: no preferred peers"),
	}

	// find some peers from our db
	// and queue them up for a connection attempt
	let new_peers = peers.find_peers(
		p2p::State::Healthy,
		p2p::Capabilities::UNKNOWN,
		config.peer_max_count() as usize,
	);
	for p in new_peers.iter().filter(|p| !peers.is_known(&p.addr)) {
		debug!(LOGGER, "monitor_peers: queue to soon try {}", p.addr);
		tx.send(p.addr).unwrap();
	}
}

fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: DandelionConfig) {
	// Dandelion Relay Updater
	let dandelion_relay = peers.get_dandelion_relay();
	if dandelion_relay.is_empty() {
		debug!(LOGGER, "monitor_peers: no dandelion relay updating");
		peers.update_dandelion_relay();
	} else {
		for last_added in dandelion_relay.keys() {
			let dandelion_interval = Utc::now().timestamp() - last_added;
			if dandelion_interval >= dandelion_config.relay_secs.unwrap() as i64 {
				debug!(LOGGER, "monitor_peers: updating expired dandelion relay");
				peers.update_dandelion_relay();
			}
		}
	}
}

// Check if we have any pre-existing peer in db. If so, start with those,
// otherwise use the seeds provided.
fn connect_to_seeds_and_preferred_peers(
	peers: Arc<p2p::Peers>,
	tx: mpsc::Sender<SocketAddr>,
	seed_list: Box<Fn() -> Vec<SocketAddr>>,
	peers_preferred_list: Option<Vec<SocketAddr>>,
) {
	// check if we have some peers in db
	let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::FULL_HIST, 100);

	// if so, get their addresses, otherwise use our seeds
	let mut peer_addrs = if peers.len() > 3 {
		peers.iter().map(|p| p.addr).collect::<Vec<_>>()
	} else {
		seed_list()
	};

	// If we have preferred peers add them to the connection
	match peers_preferred_list {
		Some(mut peers_preferred) => peer_addrs.append(&mut peers_preferred),
		None => debug!(LOGGER, "No preferred peers"),
	};

	if peer_addrs.len() == 0 {
		warn!(LOGGER, "No seeds were retrieved.");
	}

	// connect to this first set of addresses
	for addr in peer_addrs {
		tx.send(addr).unwrap();
	}
}

/// Regularly poll a channel receiver for new addresses and initiate a
/// connection if the max peer count isn't exceeded. A request for more
/// peers is also automatically sent after connection.
fn listen_for_addrs(
	peers: Arc<p2p::Peers>,
	p2p: Arc<p2p::Server>,
	capab: p2p::Capabilities,
	rx: &mpsc::Receiver<SocketAddr>,
) {
	let pc = peers.peer_count();
	for addr in rx.try_iter() {
		if pc < p2p.config.peer_max_count() {
			let peers_c = peers.clone();
			let p2p_c = p2p.clone();
			let _ = thread::Builder::new()
				.name("peer_connect".to_string())
				.spawn(move || {
					let connect_peer = p2p_c.connect(&addr);
					match connect_peer {
						Ok(p) => {
							trace!(LOGGER, "connect_and_req: ok. attempting send_peer_request");
							if let Ok(p) = p.try_read() {
								let _ = p.send_peer_request(capab);
							}
						}
						Err(e) => {
							debug!(LOGGER, "connect_and_req: {} is Defunct; {:?}", addr, e);
							let _ = peers_c.update_state(addr, p2p::State::Defunct);
						}
					}
				});
		}
	}
}

pub fn dns_seeds() -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(|| {
		let mut addresses: Vec<SocketAddr> = vec![];
		for dns_seed in DNS_SEEDS {
			let temp_addresses = addresses.clone();
			debug!(LOGGER, "Retrieving seed nodes from dns {}", dns_seed);
			match (dns_seed.to_owned(), 0).to_socket_addrs() {
				Ok(addrs) => addresses.append(
					&mut (addrs
						.map(|mut addr| {
							addr.set_port(13414);
							addr
						})
						.filter(|addr| !temp_addresses.contains(addr))
						.collect()),
				),
				Err(e) => debug!(
					LOGGER,
					"Failed to resolve seed {:?} got error {:?}", dns_seed, e
				),
			}
		}
		addresses
	})
}

/// Extract the list of seeds from a pre-defined text file available through
/// http. Easy method until we have a set of DNS names we can rely on.
pub fn web_seeds() -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(|| {
		let text: String = api::client::get(SEEDS_URL).expect("Failed to resolve seeds");
		let addrs = text
			.split_whitespace()
			.map(|s| s.parse().unwrap())
			.collect::<Vec<_>>();
		debug!(LOGGER, "Retrieved seed addresses: {:?}", addrs);
		addrs
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn predefined_seeds(addrs_str: Vec<String>) -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(move || {
		addrs_str
			.iter()
			.map(|s| s.parse().unwrap())
			.collect::<Vec<_>>()
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn preferred_peers(addrs_str: Vec<String>) -> Option<Vec<SocketAddr>> {
	if addrs_str.is_empty() {
		None
	} else {
		Some(
			addrs_str
				.iter()
				.map(|s| s.parse().unwrap())
				.collect::<Vec<_>>(),
		)
	}
}
<|endoftext|>


<commit_before>use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler};
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_parse::parse_stream_from_source_str;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{FileName, InnerSpan};

use crate::clean;
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::html::markdown::{self, RustCodeBlock};
use crate::passes::Pass;

crate const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
    name: "check-code-block-syntax",
    run: check_code_block_syntax,
    description: "validates syntax inside Rust code blocks",
};

crate fn check_code_block_syntax(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
    SyntaxChecker { cx }.fold_crate(krate)
}

struct SyntaxChecker<'a, 'tcx> {
    cx: &'a DocContext<'tcx>,
}

impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
    fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) {
        let buffer = Lrc::new(Lock::new(Buffer::default()));
        let emitter = BufferEmitter { buffer: Lrc::clone(&buffer) };

        let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
        let handler = Handler::with_emitter(false, None, Box::new(emitter));
        let source = dox[code_block.code].to_owned();
        let sess = ParseSess::with_span_handler(handler, sm);

        let is_empty = rustc_driver::catch_fatal_errors(|| {
            parse_stream_from_source_str(
                FileName::Custom(String::from("doctest")),
                source,
                &sess,
                None,
            )
            .is_empty()
        })
        .unwrap_or(false);
        let buffer = buffer.borrow();

        if !buffer.has_errors && !is_empty {
            // No errors in a non-empty program.
            return;
        }

        let local_id = match item.def_id.as_local() {
            Some(id) => id,
            // We don't need to check the syntax for other crates so returning
            // without doing anything should not be a problem.
            None => return,
        };

        let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id);
        let empty_block = code_block.syntax.is_none() && code_block.is_fenced;
        let is_ignore = code_block.is_ignore;

        // The span and whether it is precise or not.
        let (sp, precise_span) = match super::source_span_for_markdown_range(
            self.cx.tcx,
            &dox,
            &code_block.range,
            &item.attrs,
        ) {
            Some(sp) => (sp, true),
            None => (item.attr_span(self.cx.tcx), false),
        };

        // lambda that will use the lint to start a new diagnostic and add
        // a suggestion to it when needed.
        let diag_builder = |lint: LintDiagnosticBuilder<'_>| {
            let explanation = if is_ignore {
                "`ignore` code blocks require valid Rust code for syntax highlighting; \
                    mark blocks that do not contain Rust code as text"
            } else {
                "mark blocks that do not contain Rust code as text"
            };
            let msg = if buffer.has_errors {
                "could not parse code block as Rust code"
            } else {
                "Rust code block is empty"
            };
            let mut diag = lint.build(msg);

            if precise_span {
                if is_ignore {
                    // giving an accurate suggestion is hard because `ignore` might not have come first in the list.
                    // just give a `help` instead.
                    diag.span_help(
                        sp.from_inner(InnerSpan::new(0, 3)),
                        &format!("{}: ```text", explanation),
                    );
                } else if empty_block {
                    diag.span_suggestion(
                        sp.from_inner(InnerSpan::new(0, 3)),
                        explanation,
                        String::from("```text"),
                        Applicability::MachineApplicable,
                    );
                }
            } else if empty_block || is_ignore {
                diag.help(&format!("{}: ```text", explanation));
            }

            // FIXME(#67563): Provide more context for these errors by displaying the spans inline.
            for message in buffer.messages.iter() {
                diag.note(&message);
            }

            diag.emit();
        };

        // Finally build and emit the completed diagnostic.
        // All points of divergence have been handled earlier so this can be
        // done the same way whether the span is precise or not.
        self.cx.tcx.struct_span_lint_hir(
            crate::lint::INVALID_RUST_CODEBLOCKS,
            hir_id,
            sp,
            diag_builder,
        );
    }
}

impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
    fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
        if let Some(dox) = &item.attrs.collapsed_doc_value() {
            let sp = item.attr_span(self.cx.tcx);
            let extra = crate::html::markdown::ExtraInfo::new_did(
                self.cx.tcx,
                item.def_id.expect_real(),
                sp,
            );
            for code_block in markdown::rust_code_blocks(&dox, &extra) {
                self.check_rust_syntax(&item, &dox, code_block);
            }
        }

        Some(self.fold_item_recur(item))
    }
}

#[derive(Default)]
struct Buffer {
    messages: Vec<String>,
    has_errors: bool,
}

struct BufferEmitter {
    buffer: Lrc<Lock<Buffer>>,
}

impl Emitter for BufferEmitter {
    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
        let mut buffer = self.buffer.borrow_mut();
        buffer.messages.push(format!("error from rustc: {}", diag.message[0].0));
        if diag.is_error() {
            buffer.has_errors = true;
        }
    }

    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
        None
    }
}
<commit_msg>Fix rebase conflicts<commit_after>use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler};
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_parse::parse_stream_from_source_str;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{FileName, InnerSpan};

use crate::clean;
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::html::markdown::{self, RustCodeBlock};
use crate::passes::Pass;

crate const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
    name: "check-code-block-syntax",
    run: check_code_block_syntax,
    description: "validates syntax inside Rust code blocks",
};

crate fn check_code_block_syntax(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
    SyntaxChecker { cx }.fold_crate(krate)
}

struct SyntaxChecker<'a, 'tcx> {
    cx: &'a DocContext<'tcx>,
}

impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
    fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) {
        let buffer = Lrc::new(Lock::new(Buffer::default()));
        let emitter = BufferEmitter { buffer: Lrc::clone(&buffer) };

        let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
        let handler = Handler::with_emitter(false, None, Box::new(emitter));
        let source = dox[code_block.code].to_owned();
        let sess = ParseSess::with_span_handler(handler, sm);

        let is_empty = rustc_driver::catch_fatal_errors(|| {
            parse_stream_from_source_str(
                FileName::Custom(String::from("doctest")),
                source,
                &sess,
                None,
            )
            .is_empty()
        })
        .unwrap_or(false);
        let buffer = buffer.borrow();

        if !buffer.has_errors && !is_empty {
            // No errors in a non-empty program.
            return;
        }

        let local_id = match item.def_id.as_real().and_then(|x| x.as_local()) {
            Some(id) => id,
            // We don't need to check the syntax for other crates so returning
            // without doing anything should not be a problem.
            None => return,
        };

        let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id);
        let empty_block = code_block.syntax.is_none() && code_block.is_fenced;
        let is_ignore = code_block.is_ignore;

        // The span and whether it is precise or not.
        let (sp, precise_span) = match super::source_span_for_markdown_range(
            self.cx.tcx,
            &dox,
            &code_block.range,
            &item.attrs,
        ) {
            Some(sp) => (sp, true),
            None => (item.attr_span(self.cx.tcx), false),
        };

        // lambda that will use the lint to start a new diagnostic and add
        // a suggestion to it when needed.
        let diag_builder = |lint: LintDiagnosticBuilder<'_>| {
            let explanation = if is_ignore {
                "`ignore` code blocks require valid Rust code for syntax highlighting; \
                    mark blocks that do not contain Rust code as text"
            } else {
                "mark blocks that do not contain Rust code as text"
            };
            let msg = if buffer.has_errors {
                "could not parse code block as Rust code"
            } else {
                "Rust code block is empty"
            };
            let mut diag = lint.build(msg);

            if precise_span {
                if is_ignore {
                    // giving an accurate suggestion is hard because `ignore` might not have come first in the list.
                    // just give a `help` instead.
                    diag.span_help(
                        sp.from_inner(InnerSpan::new(0, 3)),
                        &format!("{}: ```text", explanation),
                    );
                } else if empty_block {
                    diag.span_suggestion(
                        sp.from_inner(InnerSpan::new(0, 3)),
                        explanation,
                        String::from("```text"),
                        Applicability::MachineApplicable,
                    );
                }
            } else if empty_block || is_ignore {
                diag.help(&format!("{}: ```text", explanation));
            }

            // FIXME(#67563): Provide more context for these errors by displaying the spans inline.
            for message in buffer.messages.iter() {
                diag.note(&message);
            }

            diag.emit();
        };

        // Finally build and emit the completed diagnostic.
        // All points of divergence have been handled earlier so this can be
        // done the same way whether the span is precise or not.
        self.cx.tcx.struct_span_lint_hir(
            crate::lint::INVALID_RUST_CODEBLOCKS,
            hir_id,
            sp,
            diag_builder,
        );
    }
}

impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
    fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
        if let Some(dox) = &item.attrs.collapsed_doc_value() {
            let sp = item.attr_span(self.cx.tcx);
            let extra = crate::html::markdown::ExtraInfo::new_did(
                self.cx.tcx,
                item.def_id.expect_real(),
                sp,
            );
            for code_block in markdown::rust_code_blocks(&dox, &extra) {
                self.check_rust_syntax(&item, &dox, code_block);
            }
        }

        Some(self.fold_item_recur(item))
    }
}

#[derive(Default)]
struct Buffer {
    messages: Vec<String>,
    has_errors: bool,
}

struct BufferEmitter {
    buffer: Lrc<Lock<Buffer>>,
}

impl Emitter for BufferEmitter {
    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
        let mut buffer = self.buffer.borrow_mut();
        buffer.messages.push(format!("error from rustc: {}", diag.message[0].0));
        if diag.is_error() {
            buffer.has_errors = true;
        }
    }

    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
        None
    }
}
<|endoftext|>


<commit_before>// run-pass

#![allow(incomplete_features)]
#![feature(unsized_locals, unsized_fn_params)]

pub fn f0(_f: dyn FnOnce()) {}
pub fn f1(_s: str) {}
pub fn f2((_x, _y): (i32, [i32])) {}

fn main() {
    let foo = "foo".to_string().into_boxed_str();
    f1(*foo);
}
<commit_msg>unsized_locals feature is not needed in this test<commit_after>// run-pass

#![allow(incomplete_features)]
#![feature(unsized_fn_params)]

pub fn f0(_f: dyn FnOnce()) {}
pub fn f1(_s: str) {}
pub fn f2((_x, _y): (i32, [i32])) {}

fn main() {
    let foo = "foo".to_string().into_boxed_str();
    f1(*foo);
}
<|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/. */

#[allow(uppercase_variables)];

extern crate freetype;
extern crate fontconfig;

use fontconfig::fontconfig::{
    FcChar8, FcResultMatch, FcSetSystem, FcPattern,
    FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD, FC_SLANT_OBLIQUE
};
use fontconfig::fontconfig::{
    FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
    FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute,
    FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger,
    FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
    FcObjectSetAdd, FcPatternGetInteger
};

use style::computed_values::font_style;

use font::{FontHandleMethods, UsedFontStyle};
use font_list::{FontEntry, FontFamily, FontFamilyMap};
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;

use collections::HashMap;
use libc;
use libc::{c_int, c_char};
use std::ptr;
use std::str;

pub struct FontListHandle {
    pub fctx: FontContextHandle,
}

impl FontListHandle {
    pub fn new(fctx: &FontContextHandle) -> FontListHandle {
        FontListHandle { fctx: fctx.clone() }
    }

    pub fn get_available_families(&self) -> FontFamilyMap {
        let mut family_map : FontFamilyMap = HashMap::new();
        unsafe {
            let config = FcConfigGetCurrent();
            let fontSet = FcConfigGetFonts(config, FcSetSystem);
            for i in range(0, (*fontSet).nfont as int) {
                let font = (*fontSet).fonts.offset(i);
                let family: *FcChar8 = ptr::null();
                let mut v: c_int = 0;
                "family".to_c_str().with_ref(|FC_FAMILY| {
                    while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
                        let family_name = str::raw::from_c_str(family as *c_char);
                        debug!("Creating new FontFamily for family: {:s}", family_name);
                        let new_family = FontFamily::new(family_name);
                        family_map.insert(family_name, new_family);
                        v += 1;
                    }
                });
            }
        }
        return family_map;
    }

    pub fn load_variations_for_family(&self, family: &mut FontFamily) {
        debug!("getting variations for {:?}", family);
        unsafe {
            let config = FcConfigGetCurrent();
            let font_set = FcConfigGetFonts(config, FcSetSystem);
            let font_set_array_ptr = &font_set;
            let pattern = FcPatternCreate();
            assert!(pattern.is_not_null());
            "family".to_c_str().with_ref(|FC_FAMILY| {
                family.family_name.to_c_str().with_ref(|family_name| {
                    let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
                    assert!(ok != 0);
                });
            });

            let object_set = FcObjectSetCreate();
            assert!(object_set.is_not_null());

            "file".to_c_str().with_ref(|FC_FILE| {
                FcObjectSetAdd(object_set, FC_FILE);
            });
            "index".to_c_str().with_ref(|FC_INDEX| {
                FcObjectSetAdd(object_set, FC_INDEX);
            });

            let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);

            debug!("found {} variations", (*matches).nfont);

            for i in range(0, (*matches).nfont as int) {
                let font = (*matches).fonts.offset(i);
                let file = "file".to_c_str().with_ref(|FC_FILE| {
                    let file: *FcChar8 = ptr::null();
                    if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
                        str::raw::from_c_str(file as *libc::c_char)
                    } else {
                        fail!();
                    }
                });
                let index = "index".to_c_str().with_ref(|FC_INDEX| {
                    let index: libc::c_int = 0;
                    if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
                        index
                    } else {
                        fail!();
                    }
                });

                debug!("variation file: {}", file);
                debug!("variation index: {}", index);

                let font_handle = FontHandle::new_from_file_unstyled(&self.fctx,
                                                                     file);
                let font_handle = font_handle.unwrap();

                debug!("Creating new FontEntry for face: {:s}", font_handle.face_name());
                let entry = FontEntry::new(font_handle);
                family.entries.push(entry);
            }

            FcFontSetDestroy(matches);
            FcPatternDestroy(pattern);
            FcObjectSetDestroy(object_set);
        }
    }

    pub fn get_last_resort_font_families() -> ~[~str] {
        ~[~"Arial"]
    }
}

struct AutoPattern {
    pattern: *FcPattern
}

impl Drop for AutoPattern {
    fn drop(&mut self) {
        unsafe {
            FcPatternDestroy(self.pattern);
        }
    }
}

pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
    unsafe {
        let config = FcConfigGetCurrent();
        let wrapper = AutoPattern { pattern: FcPatternCreate() };
        let pattern = wrapper.pattern;
        let res = "family".to_c_str().with_ref(|FC_FAMILY| {
            name.to_c_str().with_ref(|family| {
                FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
            })
        });
        if res != 1 {
            debug!("adding family to pattern failed");
            return Err(());
        }

        match style.style {
            font_style::normal => (),
            font_style::italic => {
                let res = "slant".to_c_str().with_ref(|FC_SLANT| {
                    FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
                });
                if res != 1 {
                    debug!("adding slant to pattern failed");
                    return Err(());
                }
            },
            font_style::oblique => {
                let res = "slant".to_c_str().with_ref(|FC_SLANT| {
                    FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
                });
                if res != 1 {
                    debug!("adding slant(oblique) to pattern failed");
                    return Err(());
                }
            }
        }

        if style.weight.is_bold() {
            let res = "weight".to_c_str().with_ref(|FC_WEIGHT| {
                FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
            });
            if res != 1 {
                debug!("adding weight to pattern failed");
                return Err(());
            }
        }

        if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
            debug!("substitution failed");
            return Err(());
        }
        FcDefaultSubstitute(pattern);
        let result = FcResultNoMatch;
        let result_wrapper = AutoPattern { pattern: FcFontMatch(config, pattern, &result) };
        let result_pattern = result_wrapper.pattern;
        if result != FcResultMatch && result_pattern.is_null() {
            debug!("obtaining match to pattern failed");
            return Err(());
        }

        let file: *FcChar8 = ptr::null();
        let res = "file".to_c_str().with_ref(|FC_FILE| {
            FcPatternGetString(result_pattern, FC_FILE, 0, &file)
        });
        if res != FcResultMatch {
            debug!("getting filename for font failed");
            return Err(());
        }
        Ok(str::raw::from_c_str(file as *c_char))
    }
}
<commit_msg>Use new attribute syntax<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/. */

#![allow(uppercase_variables)]

extern crate freetype;
extern crate fontconfig;

use fontconfig::fontconfig::{
    FcChar8, FcResultMatch, FcSetSystem, FcPattern,
    FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD, FC_SLANT_OBLIQUE
};
use fontconfig::fontconfig::{
    FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
    FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute,
    FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger,
    FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
    FcObjectSetAdd, FcPatternGetInteger
};

use style::computed_values::font_style;

use font::{FontHandleMethods, UsedFontStyle};
use font_list::{FontEntry, FontFamily, FontFamilyMap};
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;

use collections::HashMap;
use libc;
use libc::{c_int, c_char};
use std::ptr;
use std::str;

pub struct FontListHandle {
    pub fctx: FontContextHandle,
}

impl FontListHandle {
    pub fn new(fctx: &FontContextHandle) -> FontListHandle {
        FontListHandle { fctx: fctx.clone() }
    }

    pub fn get_available_families(&self) -> FontFamilyMap {
        let mut family_map : FontFamilyMap = HashMap::new();
        unsafe {
            let config = FcConfigGetCurrent();
            let fontSet = FcConfigGetFonts(config, FcSetSystem);
            for i in range(0, (*fontSet).nfont as int) {
                let font = (*fontSet).fonts.offset(i);
                let family: *FcChar8 = ptr::null();
                let mut v: c_int = 0;
                "family".to_c_str().with_ref(|FC_FAMILY| {
                    while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
                        let family_name = str::raw::from_c_str(family as *c_char);
                        debug!("Creating new FontFamily for family: {:s}", family_name);
                        let new_family = FontFamily::new(family_name);
                        family_map.insert(family_name, new_family);
                        v += 1;
                    }
                });
            }
        }
        return family_map;
    }

    pub fn load_variations_for_family(&self, family: &mut FontFamily) {
        debug!("getting variations for {:?}", family);
        unsafe {
            let config = FcConfigGetCurrent();
            let font_set = FcConfigGetFonts(config, FcSetSystem);
            let font_set_array_ptr = &font_set;
            let pattern = FcPatternCreate();
            assert!(pattern.is_not_null());
            "family".to_c_str().with_ref(|FC_FAMILY| {
                family.family_name.to_c_str().with_ref(|family_name| {
                    let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
                    assert!(ok != 0);
                });
            });

            let object_set = FcObjectSetCreate();
            assert!(object_set.is_not_null());

            "file".to_c_str().with_ref(|FC_FILE| {
                FcObjectSetAdd(object_set, FC_FILE);
            });
            "index".to_c_str().with_ref(|FC_INDEX| {
                FcObjectSetAdd(object_set, FC_INDEX);
            });

            let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);

            debug!("found {} variations", (*matches).nfont);

            for i in range(0, (*matches).nfont as int) {
                let font = (*matches).fonts.offset(i);
                let file = "file".to_c_str().with_ref(|FC_FILE| {
                    let file: *FcChar8 = ptr::null();
                    if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
                        str::raw::from_c_str(file as *libc::c_char)
                    } else {
                        fail!();
                    }
                });
                let index = "index".to_c_str().with_ref(|FC_INDEX| {
                    let index: libc::c_int = 0;
                    if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
                        index
                    } else {
                        fail!();
                    }
                });

                debug!("variation file: {}", file);
                debug!("variation index: {}", index);

                let font_handle = FontHandle::new_from_file_unstyled(&self.fctx,
                                                                     file);
                let font_handle = font_handle.unwrap();

                debug!("Creating new FontEntry for face: {:s}", font_handle.face_name());
                let entry = FontEntry::new(font_handle);
                family.entries.push(entry);
            }

            FcFontSetDestroy(matches);
            FcPatternDestroy(pattern);
            FcObjectSetDestroy(object_set);
        }
    }

    pub fn get_last_resort_font_families() -> ~[~str] {
        ~[~"Arial"]
    }
}

struct AutoPattern {
    pattern: *FcPattern
}

impl Drop for AutoPattern {
    fn drop(&mut self) {
        unsafe {
            FcPatternDestroy(self.pattern);
        }
    }
}

pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
    unsafe {
        let config = FcConfigGetCurrent();
        let wrapper = AutoPattern { pattern: FcPatternCreate() };
        let pattern = wrapper.pattern;
        let res = "family".to_c_str().with_ref(|FC_FAMILY| {
            name.to_c_str().with_ref(|family| {
                FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
            })
        });
        if res != 1 {
            debug!("adding family to pattern failed");
            return Err(());
        }

        match style.style {
            font_style::normal => (),
            font_style::italic => {
                let res = "slant".to_c_str().with_ref(|FC_SLANT| {
                    FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
                });
                if res != 1 {
                    debug!("adding slant to pattern failed");
                    return Err(());
                }
            },
            font_style::oblique => {
                let res = "slant".to_c_str().with_ref(|FC_SLANT| {
                    FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
                });
                if res != 1 {
                    debug!("adding slant(oblique) to pattern failed");
                    return Err(());
                }
            }
        }

        if style.weight.is_bold() {
            let res = "weight".to_c_str().with_ref(|FC_WEIGHT| {
                FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
            });
            if res != 1 {
                debug!("adding weight to pattern failed");
                return Err(());
            }
        }

        if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
            debug!("substitution failed");
            return Err(());
        }
        FcDefaultSubstitute(pattern);
        let result = FcResultNoMatch;
        let result_wrapper = AutoPattern { pattern: FcFontMatch(config, pattern, &result) };
        let result_pattern = result_wrapper.pattern;
        if result != FcResultMatch && result_pattern.is_null() {
            debug!("obtaining match to pattern failed");
            return Err(());
        }

        let file: *FcChar8 = ptr::null();
        let res = "file".to_c_str().with_ref(|FC_FILE| {
            FcPatternGetString(result_pattern, FC_FILE, 0, &file)
        });
        if res != FcResultMatch {
            debug!("getting filename for font failed");
            return Err(());
        }
        Ok(str::raw::from_c_str(file as *c_char))
    }
}
<|endoftext|>