<commit_before>use std::fmt::Default;

use super::{LogStats, StatsItem, StatsMap, ObjectStats};
use super::utils::{format_duration, format_bytes};

pub struct LogStatsPrinter<'r> {
    priv stats: &'r LogStats,
}

impl<'r> LogStatsPrinter<'r> {
    pub fn new<'r>(stats: &'r LogStats) -> LogStatsPrinter<'r> {
        LogStatsPrinter{stats: stats}
    }

    pub fn print(&self, limit: uint) {
        print_totals(&self.stats.total);
        print(&self.stats.hosts, "Requests", "Hosts", limit);
        print(&self.stats.dates, "Requests", "Dates", limit);
        print(&self.stats.clients, "Requests", "Clients", limit);
        print(&self.stats.hours, "Requests", "Hours", limit);
        print(&self.stats.paths, "Requests", "Paths", limit);
        print(&self.stats.methods, "Requests", "Methods", limit);
        print(&self.stats.statuses, "Requests", "Statuses", limit);
        print(&self.stats.referers, "Requests", "Referers", limit);
        print(&self.stats.user_agents, "Requests", "User agents", limit);
    }
}

#[inline]
fn print_totals(totals: &ObjectStats) {
    println!("Totals\n\
              =======================\n\
              Requests Duration Bytes\n\
              -----------------------");
    println!("{: >8} {: >8} {: >5}",
             totals.requests,
             format_duration(totals.request_time),
             format_bytes(totals.sent_bytes));
}

#[inline]
fn print<T: IterBytes + Eq + Default>(mapping: &StatsMap<T>, title: &str,
        key_title: &str, limit: uint) {
    let mut items: ~[StatsItem<T>] = mapping.iter().collect();
    items.sort_by(|&(_, a), &(_, b)| b.requests.cmp(&a.requests));
    print_sorted(items, title, key_title, limit);
}

#[inline]
fn print_sorted<T: IterBytes + Eq + Default>(sorted: &[StatsItem<T>],
        title: &str, key_title: &str, limit: uint) {
    println!("\n{} by {}\n\
              =====================================================\
              ============================\n\
              {: <57} Requests Duration Bytes\n\
              -----------------------------------------------------\
              ----------------------------",
              title, key_title, key_title);
    for &(client, stats) in sorted.iter().take(limit) {
        println!("{: <60.60} {: >5} {: >8} {: >5}",
                 *client,
                 stats.requests,
                 format_duration(stats.request_time),
                 format_bytes(stats.sent_bytes));
    }
}
<commit_msg>Print the current limit of records<commit_after>use std::fmt::Default;

use super::{LogStats, StatsItem, StatsMap, ObjectStats};
use super::utils::{format_duration, format_bytes};

pub struct LogStatsPrinter<'r> {
    priv stats: &'r LogStats,
}

impl<'r> LogStatsPrinter<'r> {
    pub fn new<'r>(stats: &'r LogStats) -> LogStatsPrinter<'r> {
        LogStatsPrinter{stats: stats}
    }

    pub fn print(&self, limit: uint) {
        print_totals(&self.stats.total);
        print(&self.stats.hosts, "Requests", "Hosts", limit);
        print(&self.stats.dates, "Requests", "Dates", limit);
        print(&self.stats.clients, "Requests", "Clients", limit);
        print(&self.stats.hours, "Requests", "Hours", limit);
        print(&self.stats.paths, "Requests", "Paths", limit);
        print(&self.stats.methods, "Requests", "Methods", limit);
        print(&self.stats.statuses, "Requests", "Statuses", limit);
        print(&self.stats.referers, "Requests", "Referers", limit);
        print(&self.stats.user_agents, "Requests", "User agents", limit);
    }
}

#[inline]
fn print_totals(totals: &ObjectStats) {
    println!("Totals\n\
              =======================\n\
              Requests Duration Bytes\n\
              -----------------------");
    println!("{: >8} {: >8} {: >5}",
             totals.requests,
             format_duration(totals.request_time),
             format_bytes(totals.sent_bytes));
}

#[inline]
fn print<T: IterBytes + Eq + Default>(mapping: &StatsMap<T>, title: &str,
        key_title: &str, limit: uint) {
    let mut items: ~[StatsItem<T>] = mapping.iter().collect();
    items.sort_by(|&(_, a), &(_, b)| b.requests.cmp(&a.requests));
    print_sorted(items, title, key_title, limit);
}

#[inline]
fn print_sorted<T: IterBytes + Eq + Default>(sorted: &[StatsItem<T>],
        title: &str, key_title: &str, limit: uint) {
    println!("\n{} by {} (top {})\n\
              =====================================================\
              ============================\n\
              {: <57} Requests Duration Bytes\n\
              -----------------------------------------------------\
              ----------------------------",
              title, key_title, limit, key_title);
    for &(client, stats) in sorted.iter().take(limit) {
        println!("{: <60.60} {: >5} {: >8} {: >5}",
                 *client,
                 stats.requests,
                 format_duration(stats.request_time),
                 format_bytes(stats.sent_bytes));
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 stb_image::bindgen::*;

use std::libc;
use std::libc::{c_void, c_int};
use std::ptr::{is_null, to_mut_unsafe_ptr};
use std::task;
use std::vec::raw::from_buf_raw;

pub struct Image<T> {
    width   : uint,
    height  : uint,
    depth   : uint,
    data    : ~[T],
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: ~[T]) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : data,
    }
}

enum LoadResult {
    Error,
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

pub fn load(path: ~str) -> LoadResult {
    let force_depth = 0;
    load_with_depth(path, force_depth, false)
}

priv fn load_internal<T>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = from_buf_raw(buf, (w * h * d) as uint);
        libc::free(buf as *c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: ~str, force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        do task::unkillable {
            let mut width   = 0 as c_int;
            let mut height  = 0 as c_int;
            let mut depth   = 0 as c_int;
            do path.as_c_str |bytes|
            {
                if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                    let buffer = stbi_loadf(bytes,
                                            to_mut_unsafe_ptr(&mut width),
                                            to_mut_unsafe_ptr(&mut height),
                                            to_mut_unsafe_ptr(&mut depth),
                                            force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        ImageF32( load_internal(buffer,width,height,depth) )
                    }
                } else {
                    let buffer = stbi_load(bytes,
                                           to_mut_unsafe_ptr(&mut width),
                                           to_mut_unsafe_ptr(&mut height),
                                           to_mut_unsafe_ptr(&mut depth),
                                           force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        ImageU8( load_internal(buffer,width,height,depth) )
                    }
                }
            }
        }
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        do task::unkillable {
            let mut width = 0 as c_int;
            let mut height = 0 as c_int;
            let mut depth = 0 as c_int;
            do buffer.as_imm_buf |bytes, len| {
                if !convert_hdr && stbi_is_hdr_from_memory(bytes, len as c_int) != 0 {
                    let buffer = stbi_loadf_from_memory(bytes,
                                                        len as c_int,
                                                        to_mut_unsafe_ptr(&mut width),
                                                        to_mut_unsafe_ptr(&mut height),
                                                        to_mut_unsafe_ptr(&mut depth),
                                                        force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                        ImageF32( load_internal(buffer,width,height,actual_depth) )
                    }
                } else {
                    let buffer = stbi_load_from_memory(bytes,
                                                       len as c_int,
                                                       to_mut_unsafe_ptr(&mut width),
                                                       to_mut_unsafe_ptr(&mut height),
                                                       to_mut_unsafe_ptr(&mut depth),
                                                       force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                        ImageU8( load_internal(buffer,width,height,actual_depth) )
                    }
                }
            }
        }
    }
}
<commit_msg>Style fix<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 stb_image::bindgen::*;

use std::libc;
use std::libc::{c_void, c_int};
use std::ptr::{is_null, to_mut_unsafe_ptr};
use std::task;
use std::vec::raw::from_buf_raw;

pub struct Image<T> {
    width   : uint,
    height  : uint,
    depth   : uint,
    data    : ~[T],
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: ~[T]) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : data,
    }
}

enum LoadResult {
    Error,
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

pub fn load(path: ~str) -> LoadResult {
    let force_depth = 0;
    load_with_depth(path, force_depth, false)
}

priv fn load_internal<T>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = from_buf_raw(buf, (w * h * d) as uint);
        libc::free(buf as *c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: ~str, force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        do task::unkillable {
            let mut width   = 0 as c_int;
            let mut height  = 0 as c_int;
            let mut depth   = 0 as c_int;
            do path.as_c_str |bytes| {
                if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                    let buffer = stbi_loadf(bytes,
                                            to_mut_unsafe_ptr(&mut width),
                                            to_mut_unsafe_ptr(&mut height),
                                            to_mut_unsafe_ptr(&mut depth),
                                            force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        ImageF32( load_internal(buffer,width,height,depth) )
                    }
                } else {
                    let buffer = stbi_load(bytes,
                                           to_mut_unsafe_ptr(&mut width),
                                           to_mut_unsafe_ptr(&mut height),
                                           to_mut_unsafe_ptr(&mut depth),
                                           force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        ImageU8( load_internal(buffer,width,height,depth) )
                    }
                }
            }
        }
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        do task::unkillable {
            let mut width = 0 as c_int;
            let mut height = 0 as c_int;
            let mut depth = 0 as c_int;
            do buffer.as_imm_buf |bytes, len| {
                if !convert_hdr && stbi_is_hdr_from_memory(bytes, len as c_int) != 0 {
                    let buffer = stbi_loadf_from_memory(bytes,
                                                        len as c_int,
                                                        to_mut_unsafe_ptr(&mut width),
                                                        to_mut_unsafe_ptr(&mut height),
                                                        to_mut_unsafe_ptr(&mut depth),
                                                        force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                        ImageF32( load_internal(buffer,width,height,actual_depth) )
                    }
                } else {
                    let buffer = stbi_load_from_memory(bytes,
                                                       len as c_int,
                                                       to_mut_unsafe_ptr(&mut width),
                                                       to_mut_unsafe_ptr(&mut height),
                                                       to_mut_unsafe_ptr(&mut depth),
                                                       force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                        ImageU8( load_internal(buffer,width,height,actual_depth) )
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
 *
 * 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.
 */

// there is not much to format in this file, and we don't want rusftfmt to mess up the comments
#![cfg_attr(rustfmt, rustfmt_skip)]

//! All defined response codes in DNS

use std::fmt;
use std::fmt::{Display, Formatter};

/// The status code of the response to a query.
///
/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035)
///
/// ```text
/// RCODE           Response code - this 4 bit field is set as part of
///                 responses.  The values have the following
///                 interpretation:
///
///                 0               No error condition
///
///                 1               Format error - The name server was
///                                 unable to interpret the query.
///
///                 2               Server failure - The name server was
///                                 unable to process this query due to a
///                                 problem with the name server.
///
///                 3               Name Error - Meaningful only for
///                                 responses from an authoritative name
///                                 server, this code signifies that the
///                                 domain name referenced in the query does
///                                 not exist.
///
///                 4               Not Implemented - The name server does
///                                 not support the requested kind of query.
///
///                 5               Refused - The name server refuses to
///                                 perform the specified operation for
///                                 policy reasons.  For example, a name
///                                 server may not wish to provide the
///                                 information to the particular requester,
///                                 or a name server may not wish to perform
///                                 a particular operation (e.g., zone
///
///                                 transfer) for particular data.
///
///                 6-15            Reserved for future use.
///  ```
#[derive(Debug, PartialEq, PartialOrd, Copy, Clone)]
#[allow(dead_code)]
pub enum ResponseCode {
    /// No Error [RFC 1035](https://tools.ietf.org/html/rfc1035)
    NoError,

    /// Format Error [RFC 1035](https://tools.ietf.org/html/rfc1035)
    FormErr,

    /// Server Failure [RFC 1035](https://tools.ietf.org/html/rfc1035)
    ServFail,

    /// Non-Esistent Domain [RFC 1035](https://tools.ietf.org/html/rfc1035)
    NXDomain,

    /// Not Implemented [RFC 1035](https://tools.ietf.org/html/rfc1035)
    NotImp,

    /// Query Refused [RFC 1035](https://tools.ietf.org/html/rfc1035)
    Refused,

    /// Name Exists when it should not [RFC 2136](https://tools.ietf.org/html/rfc2136)
    YXDomain,

    /// RR Set Exists when it should not [RFC 2136](https://tools.ietf.org/html/rfc2136)
    YXRRSet,

    /// RR Set that should exist does not [RFC 2136](https://tools.ietf.org/html/rfc2136)
    NXRRSet,

    /// Server Not Authoritative for zone [RFC 2136](https://tools.ietf.org/html/rfc2136)
    /// or Not Authorized [RFC 2845](https://tools.ietf.org/html/rfc2845)
    NotAuth,

    /// Name not contained in zone [RFC 2136](https://tools.ietf.org/html/rfc2136)
    NotZone,

    /// Bad OPT Version [RFC 6891](https://tools.ietf.org/html/rfc6891#section-9)
    BADVERS,

    /// TSIG Signature Failure [RFC 2845](https://tools.ietf.org/html/rfc2845)
    BADSIG,

    /// Key not recognized [RFC 2845](https://tools.ietf.org/html/rfc2845)
    BADKEY,

    /// Signature out of time window [RFC 2845](https://tools.ietf.org/html/rfc2845)
    BADTIME,

    /// Bad TKEY Mode [RFC 2930](https://tools.ietf.org/html/rfc2930#section-2.6)
    BADMODE,

    /// Duplicate key name [RFC 2930](https://tools.ietf.org/html/rfc2930#section-2.6)
    BADNAME,

    /// Algorithm not supported [RFC 2930](https://tools.ietf.org/html/rfc2930#section-2.6)
    BADALG,

    /// Bad Truncation [RFC 4635](https://tools.ietf.org/html/rfc4635#section-4)
    BADTRUNC,

    /// Bad/missing server cookie [draft-ietf-dnsop-cookies](https://tools.ietf.org/html/draft-ietf-dnsop-cookies-10)
    BADCOOKIE,
             // 24-3840      Unassigned
             // 3841-4095    Reserved for Private Use                        [RFC6895]
             // 4096-65534   Unassigned
             // 65535        Reserved, can be allocated by Standards Action  [RFC6895]
}

impl ResponseCode {
    /// returns the lower 4 bits of the response code (for the original header portion of the code)
    pub fn low(&self) -> u8 {
        (u16::from(*self) & 0x000F) as u8
    }

    /// returns the high 12 bits for the edns portion of the response code
    pub fn high(&self) -> u16 {
        (u16::from(*self) & 0x0FF0) >> 4
    }

    /// Combines the EDNS high and low from the Header to produce the Extended ResponseCode
    pub fn from(high: u8, low: u8) -> ResponseCode {
        ((u16::from(high) << 4) | ((u16::from(low)) & 0x000F)).into()
    }

    /// Transforms the response code into the human message
    pub fn to_str(&self) -> &'static str {
        match *self {
            ResponseCode::NoError => "No Error",
            ResponseCode::FormErr => "Form Error",                   // 1     FormErr       Format Error                        [RFC1035]
            ResponseCode::ServFail => "Server Failure",              // 2     ServFail      Server Failure                      [RFC1035]
            ResponseCode::NXDomain => "Non-Existent Domain",         // 3     NXDomain      Non-Existent Domain                 [RFC1035]
            ResponseCode::NotImp => "Not Implemented",               // 4     NotImp        Not Implemented                     [RFC1035]
            ResponseCode::Refused => "Query Refused",                // 5     Refused       Query Refused                       [RFC1035]
            ResponseCode::YXDomain => "Name should not exist",       // 6     YXDomain      Name Exists when it should not      [RFC2136][RFC6672]
            ResponseCode::YXRRSet => "RR Set should not exist",      // 7     YXRRSet       RR Set Exists when it should not    [RFC2136]
            ResponseCode::NXRRSet => "RR Set does not exist",        // 8     NXRRSet       RR Set that should exist does not   [RFC2136]
            ResponseCode::NotAuth => "Not authorized",               // 9     NotAuth       Server Not Authoritative for zone   [RFC2136]
            ResponseCode::NotZone => "Name not in zone",             // 10    NotZone       Name not contained in zone          [RFC2136]
            ResponseCode::BADVERS => "Bad option verions",           // 16    BADVERS       Bad OPT Version                     [RFC6891]
            ResponseCode::BADSIG => "TSIG Failure",                  // 16    BADSIG        TSIG Signature Failure              [RFC2845]
            ResponseCode::BADKEY => "Key not recognized",            // 17    BADKEY        Key not recognized                  [RFC2845]
            ResponseCode::BADTIME => "Signature out of time window", // 18    BADTIME       Signature out of time window        [RFC2845]
            ResponseCode::BADMODE => "Bad TKEY mode",                // 19    BADMODE       Bad TKEY Mode                       [RFC2930]
            ResponseCode::BADNAME => "Duplicate key name",           // 20    BADNAME       Duplicate key name                  [RFC2930]
            ResponseCode::BADALG => "Algorithm not supported",       // 21    BADALG        Algorithm not supported             [RFC2930]
            ResponseCode::BADTRUNC => "Bad truncation",              // 22    BADTRUNC      Bad Truncation                      [RFC4635]
            ResponseCode::BADCOOKIE => "Bad server cookie",          // 23    BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26)    Bad/missing server cookie    [draft-ietf-dnsop-cookies]
        }
    }
}

impl Display for ResponseCode {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        f.write_str(self.to_str())
    }
}

/// Convert from ResponseCode to u16
///
/// ```
/// use std::convert::From;
/// use trust_dns_proto::op::response_code::ResponseCode;
///
/// let var: ResponseCode = From::from(0);
/// assert_eq!(ResponseCode::NoError, var);
///
/// let var: ResponseCode = 0.into();
/// assert_eq!(ResponseCode::NoError, var);
/// ```
impl From<ResponseCode> for u16 {

    fn from(rt: ResponseCode) -> Self {
        match rt {
            ResponseCode::NoError => 0,     // 0   NoError    No Error                              [RFC1035]
            ResponseCode::FormErr => 1,     // 1   FormErr    Format Error                          [RFC1035]
            ResponseCode::ServFail => 2,    // 2   ServFail   Server Failure                        [RFC1035]
            ResponseCode::NXDomain => 3,    // 3   NXDomain   Non-Existent Domain                   [RFC1035]
            ResponseCode::NotImp => 4,      // 4   NotImp     Not Implemented                       [RFC1035]
            ResponseCode::Refused => 5,     // 5   Refused    Query Refused                         [RFC1035]
            ResponseCode::YXDomain => 6,    // 6   YXDomain   Name Exists when it should not        [RFC2136][RFC6672]
            ResponseCode::YXRRSet => 7,     // 7   YXRRSet    RR Set Exists when it should not      [RFC2136]
            ResponseCode::NXRRSet => 8,     // 8   NXRRSet    RR Set that should exist does not     [RFC2136]
            ResponseCode::NotAuth => 9,     // 9   NotAuth    Server Not Authoritative for zone     [RFC2136]
            ResponseCode::NotZone => 10,    // 10  NotZone    Name not contained in zone            [RFC2136]
            //
            // 11-15    Unassigned
            //
            // 16  BADVERS  Bad OPT Version         [RFC6891]
            // 16  BADSIG   TSIG Signature Failure  [RFC2845]
            ResponseCode::BADVERS | ResponseCode::BADSIG => 16,
            ResponseCode::BADKEY => 17,     // 17  BADKEY    Key not recognized                     [RFC2845]
            ResponseCode::BADTIME => 18,    // 18  BADTIME   Signature out of time window           [RFC2845]
            ResponseCode::BADMODE => 19,    // 19  BADMODE   Bad TKEY Mode                          [RFC2930]
            ResponseCode::BADNAME => 20,    // 20  BADNAME   Duplicate key name                     [RFC2930]
            ResponseCode::BADALG => 21,     // 21  BADALG    Algorithm not supported                [RFC2930]
            ResponseCode::BADTRUNC => 22,   // 22  BADTRUNC  Bad Truncation                         [RFC4635]
            // 23  BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26)    Bad/missing server cookie    [draft-ietf-dnsop-cookies]
            ResponseCode::BADCOOKIE => 23,
        }
    }
}

/// Convert from u16 to ResponseCode
///
/// ```
/// use std::convert::From;
/// use trust_dns_proto::op::response_code::ResponseCode;
///
/// let var: u16 = From::from(ResponseCode::NoError);
/// assert_eq!(0, var);
///
/// let var: u16 = ResponseCode::NoError.into();
/// assert_eq!(0, var);
/// ```
impl From<u16> for ResponseCode {
    fn from(value: u16) -> Self {
        match value {
            0 => ResponseCode::NoError,     // 0    NoError    No Error                             [RFC1035]
            1 => ResponseCode::FormErr,     // 1    FormErr    Format Error                         [RFC1035]
            2 => ResponseCode::ServFail,    // 2    ServFail   Server Failure                       [RFC1035]
            3 => ResponseCode::NXDomain,    // 3    NXDomain   Non-Existent Domain                  [RFC1035]
            4 => ResponseCode::NotImp,      // 4    NotImp     Not Implemented                      [RFC1035]
            5 => ResponseCode::Refused,     // 5    Refused    Query Refused                        [RFC1035]
            6 => ResponseCode::YXDomain,    // 6    YXDomain   Name Exists when it should not       [RFC2136][RFC6672]
            7 => ResponseCode::YXRRSet,     // 7    YXRRSet    RR Set Exists when it should not     [RFC2136]
            8 => ResponseCode::NXRRSet,     // 8    NXRRSet    RR Set that should exist does not    [RFC2136]
            9 => ResponseCode::NotAuth,     // 9    NotAuth    Server Not Authoritative for zone    [RFC2136]
            10 => ResponseCode::NotZone,    // 10   NotZone    Name not contained in zone           [RFC2136]
            // this looks to be backwards compat for 4 bit ResponseCodes.
            // 16    BADVERS    Bad OPT Version    [RFC6891]
            // 16 => ResponseCode::BADVERS,
            16 => ResponseCode::BADSIG,     // 16    BADSIG    TSIG Signature Failure               [RFC2845]
            17 => ResponseCode::BADKEY,     // 17    BADKEY    Key not recognized                   [RFC2845]
            18 => ResponseCode::BADTIME,    // 18    BADTIME   Signature out of time window         [RFC2845]
            19 => ResponseCode::BADMODE,    // 19    BADMODE   Bad TKEY Mode                        [RFC2930]
            20 => ResponseCode::BADNAME,    // 20    BADNAME   Duplicate key name                   [RFC2930]
            21 => ResponseCode::BADALG,     // 21    BADALG    Algorithm not supported              [RFC2930]
            22 => ResponseCode::BADTRUNC,   // 22    BADTRUNC  Bad Truncation                       [RFC4635]
            23 => ResponseCode::BADCOOKIE,  // 23    BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26)    Bad/missing server cookie    [draft-ietf-dnsop-cookies]
            _ => unimplemented!(),
        }
    }
}
<commit_msg>Removed unnecessary empty line from docs<commit_after>/*
 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
 *
 * 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.
 */

// there is not much to format in this file, and we don't want rusftfmt to mess up the comments
#![cfg_attr(rustfmt, rustfmt_skip)]

//! All defined response codes in DNS

use std::fmt;
use std::fmt::{Display, Formatter};

/// The status code of the response to a query.
///
/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035)
///
/// ```text
/// RCODE           Response code - this 4 bit field is set as part of
///                 responses.  The values have the following
///                 interpretation:
///
///                 0               No error condition
///
///                 1               Format error - The name server was
///                                 unable to interpret the query.
///
///                 2               Server failure - The name server was
///                                 unable to process this query due to a
///                                 problem with the name server.
///
///                 3               Name Error - Meaningful only for
///                                 responses from an authoritative name
///                                 server, this code signifies that the
///                                 domain name referenced in the query does
///                                 not exist.
///
///                 4               Not Implemented - The name server does
///                                 not support the requested kind of query.
///
///                 5               Refused - The name server refuses to
///                                 perform the specified operation for
///                                 policy reasons.  For example, a name
///                                 server may not wish to provide the
///                                 information to the particular requester,
///                                 or a name server may not wish to perform
///                                 a particular operation (e.g., zone
///                                 transfer) for particular data.
///
///                 6-15            Reserved for future use.
///  ```
#[derive(Debug, PartialEq, PartialOrd, Copy, Clone)]
#[allow(dead_code)]
pub enum ResponseCode {
    /// No Error [RFC 1035](https://tools.ietf.org/html/rfc1035)
    NoError,

    /// Format Error [RFC 1035](https://tools.ietf.org/html/rfc1035)
    FormErr,

    /// Server Failure [RFC 1035](https://tools.ietf.org/html/rfc1035)
    ServFail,

    /// Non-Esistent Domain [RFC 1035](https://tools.ietf.org/html/rfc1035)
    NXDomain,

    /// Not Implemented [RFC 1035](https://tools.ietf.org/html/rfc1035)
    NotImp,

    /// Query Refused [RFC 1035](https://tools.ietf.org/html/rfc1035)
    Refused,

    /// Name Exists when it should not [RFC 2136](https://tools.ietf.org/html/rfc2136)
    YXDomain,

    /// RR Set Exists when it should not [RFC 2136](https://tools.ietf.org/html/rfc2136)
    YXRRSet,

    /// RR Set that should exist does not [RFC 2136](https://tools.ietf.org/html/rfc2136)
    NXRRSet,

    /// Server Not Authoritative for zone [RFC 2136](https://tools.ietf.org/html/rfc2136)
    /// or Not Authorized [RFC 2845](https://tools.ietf.org/html/rfc2845)
    NotAuth,

    /// Name not contained in zone [RFC 2136](https://tools.ietf.org/html/rfc2136)
    NotZone,

    /// Bad OPT Version [RFC 6891](https://tools.ietf.org/html/rfc6891#section-9)
    BADVERS,

    /// TSIG Signature Failure [RFC 2845](https://tools.ietf.org/html/rfc2845)
    BADSIG,

    /// Key not recognized [RFC 2845](https://tools.ietf.org/html/rfc2845)
    BADKEY,

    /// Signature out of time window [RFC 2845](https://tools.ietf.org/html/rfc2845)
    BADTIME,

    /// Bad TKEY Mode [RFC 2930](https://tools.ietf.org/html/rfc2930#section-2.6)
    BADMODE,

    /// Duplicate key name [RFC 2930](https://tools.ietf.org/html/rfc2930#section-2.6)
    BADNAME,

    /// Algorithm not supported [RFC 2930](https://tools.ietf.org/html/rfc2930#section-2.6)
    BADALG,

    /// Bad Truncation [RFC 4635](https://tools.ietf.org/html/rfc4635#section-4)
    BADTRUNC,

    /// Bad/missing server cookie [draft-ietf-dnsop-cookies](https://tools.ietf.org/html/draft-ietf-dnsop-cookies-10)
    BADCOOKIE,
             // 24-3840      Unassigned
             // 3841-4095    Reserved for Private Use                        [RFC6895]
             // 4096-65534   Unassigned
             // 65535        Reserved, can be allocated by Standards Action  [RFC6895]
}

impl ResponseCode {
    /// returns the lower 4 bits of the response code (for the original header portion of the code)
    pub fn low(&self) -> u8 {
        (u16::from(*self) & 0x000F) as u8
    }

    /// returns the high 12 bits for the edns portion of the response code
    pub fn high(&self) -> u16 {
        (u16::from(*self) & 0x0FF0) >> 4
    }

    /// Combines the EDNS high and low from the Header to produce the Extended ResponseCode
    pub fn from(high: u8, low: u8) -> ResponseCode {
        ((u16::from(high) << 4) | ((u16::from(low)) & 0x000F)).into()
    }

    /// Transforms the response code into the human message
    pub fn to_str(&self) -> &'static str {
        match *self {
            ResponseCode::NoError => "No Error",
            ResponseCode::FormErr => "Form Error",                   // 1     FormErr       Format Error                        [RFC1035]
            ResponseCode::ServFail => "Server Failure",              // 2     ServFail      Server Failure                      [RFC1035]
            ResponseCode::NXDomain => "Non-Existent Domain",         // 3     NXDomain      Non-Existent Domain                 [RFC1035]
            ResponseCode::NotImp => "Not Implemented",               // 4     NotImp        Not Implemented                     [RFC1035]
            ResponseCode::Refused => "Query Refused",                // 5     Refused       Query Refused                       [RFC1035]
            ResponseCode::YXDomain => "Name should not exist",       // 6     YXDomain      Name Exists when it should not      [RFC2136][RFC6672]
            ResponseCode::YXRRSet => "RR Set should not exist",      // 7     YXRRSet       RR Set Exists when it should not    [RFC2136]
            ResponseCode::NXRRSet => "RR Set does not exist",        // 8     NXRRSet       RR Set that should exist does not   [RFC2136]
            ResponseCode::NotAuth => "Not authorized",               // 9     NotAuth       Server Not Authoritative for zone   [RFC2136]
            ResponseCode::NotZone => "Name not in zone",             // 10    NotZone       Name not contained in zone          [RFC2136]
            ResponseCode::BADVERS => "Bad option verions",           // 16    BADVERS       Bad OPT Version                     [RFC6891]
            ResponseCode::BADSIG => "TSIG Failure",                  // 16    BADSIG        TSIG Signature Failure              [RFC2845]
            ResponseCode::BADKEY => "Key not recognized",            // 17    BADKEY        Key not recognized                  [RFC2845]
            ResponseCode::BADTIME => "Signature out of time window", // 18    BADTIME       Signature out of time window        [RFC2845]
            ResponseCode::BADMODE => "Bad TKEY mode",                // 19    BADMODE       Bad TKEY Mode                       [RFC2930]
            ResponseCode::BADNAME => "Duplicate key name",           // 20    BADNAME       Duplicate key name                  [RFC2930]
            ResponseCode::BADALG => "Algorithm not supported",       // 21    BADALG        Algorithm not supported             [RFC2930]
            ResponseCode::BADTRUNC => "Bad truncation",              // 22    BADTRUNC      Bad Truncation                      [RFC4635]
            ResponseCode::BADCOOKIE => "Bad server cookie",          // 23    BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26)    Bad/missing server cookie    [draft-ietf-dnsop-cookies]
        }
    }
}

impl Display for ResponseCode {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        f.write_str(self.to_str())
    }
}

/// Convert from ResponseCode to u16
///
/// ```
/// use std::convert::From;
/// use trust_dns_proto::op::response_code::ResponseCode;
///
/// let var: ResponseCode = From::from(0);
/// assert_eq!(ResponseCode::NoError, var);
///
/// let var: ResponseCode = 0.into();
/// assert_eq!(ResponseCode::NoError, var);
/// ```
impl From<ResponseCode> for u16 {

    fn from(rt: ResponseCode) -> Self {
        match rt {
            ResponseCode::NoError => 0,     // 0   NoError    No Error                              [RFC1035]
            ResponseCode::FormErr => 1,     // 1   FormErr    Format Error                          [RFC1035]
            ResponseCode::ServFail => 2,    // 2   ServFail   Server Failure                        [RFC1035]
            ResponseCode::NXDomain => 3,    // 3   NXDomain   Non-Existent Domain                   [RFC1035]
            ResponseCode::NotImp => 4,      // 4   NotImp     Not Implemented                       [RFC1035]
            ResponseCode::Refused => 5,     // 5   Refused    Query Refused                         [RFC1035]
            ResponseCode::YXDomain => 6,    // 6   YXDomain   Name Exists when it should not        [RFC2136][RFC6672]
            ResponseCode::YXRRSet => 7,     // 7   YXRRSet    RR Set Exists when it should not      [RFC2136]
            ResponseCode::NXRRSet => 8,     // 8   NXRRSet    RR Set that should exist does not     [RFC2136]
            ResponseCode::NotAuth => 9,     // 9   NotAuth    Server Not Authoritative for zone     [RFC2136]
            ResponseCode::NotZone => 10,    // 10  NotZone    Name not contained in zone            [RFC2136]
            //
            // 11-15    Unassigned
            //
            // 16  BADVERS  Bad OPT Version         [RFC6891]
            // 16  BADSIG   TSIG Signature Failure  [RFC2845]
            ResponseCode::BADVERS | ResponseCode::BADSIG => 16,
            ResponseCode::BADKEY => 17,     // 17  BADKEY    Key not recognized                     [RFC2845]
            ResponseCode::BADTIME => 18,    // 18  BADTIME   Signature out of time window           [RFC2845]
            ResponseCode::BADMODE => 19,    // 19  BADMODE   Bad TKEY Mode                          [RFC2930]
            ResponseCode::BADNAME => 20,    // 20  BADNAME   Duplicate key name                     [RFC2930]
            ResponseCode::BADALG => 21,     // 21  BADALG    Algorithm not supported                [RFC2930]
            ResponseCode::BADTRUNC => 22,   // 22  BADTRUNC  Bad Truncation                         [RFC4635]
            // 23  BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26)    Bad/missing server cookie    [draft-ietf-dnsop-cookies]
            ResponseCode::BADCOOKIE => 23,
        }
    }
}

/// Convert from u16 to ResponseCode
///
/// ```
/// use std::convert::From;
/// use trust_dns_proto::op::response_code::ResponseCode;
///
/// let var: u16 = From::from(ResponseCode::NoError);
/// assert_eq!(0, var);
///
/// let var: u16 = ResponseCode::NoError.into();
/// assert_eq!(0, var);
/// ```
impl From<u16> for ResponseCode {
    fn from(value: u16) -> Self {
        match value {
            0 => ResponseCode::NoError,     // 0    NoError    No Error                             [RFC1035]
            1 => ResponseCode::FormErr,     // 1    FormErr    Format Error                         [RFC1035]
            2 => ResponseCode::ServFail,    // 2    ServFail   Server Failure                       [RFC1035]
            3 => ResponseCode::NXDomain,    // 3    NXDomain   Non-Existent Domain                  [RFC1035]
            4 => ResponseCode::NotImp,      // 4    NotImp     Not Implemented                      [RFC1035]
            5 => ResponseCode::Refused,     // 5    Refused    Query Refused                        [RFC1035]
            6 => ResponseCode::YXDomain,    // 6    YXDomain   Name Exists when it should not       [RFC2136][RFC6672]
            7 => ResponseCode::YXRRSet,     // 7    YXRRSet    RR Set Exists when it should not     [RFC2136]
            8 => ResponseCode::NXRRSet,     // 8    NXRRSet    RR Set that should exist does not    [RFC2136]
            9 => ResponseCode::NotAuth,     // 9    NotAuth    Server Not Authoritative for zone    [RFC2136]
            10 => ResponseCode::NotZone,    // 10   NotZone    Name not contained in zone           [RFC2136]
            // this looks to be backwards compat for 4 bit ResponseCodes.
            // 16    BADVERS    Bad OPT Version    [RFC6891]
            // 16 => ResponseCode::BADVERS,
            16 => ResponseCode::BADSIG,     // 16    BADSIG    TSIG Signature Failure               [RFC2845]
            17 => ResponseCode::BADKEY,     // 17    BADKEY    Key not recognized                   [RFC2845]
            18 => ResponseCode::BADTIME,    // 18    BADTIME   Signature out of time window         [RFC2845]
            19 => ResponseCode::BADMODE,    // 19    BADMODE   Bad TKEY Mode                        [RFC2930]
            20 => ResponseCode::BADNAME,    // 20    BADNAME   Duplicate key name                   [RFC2930]
            21 => ResponseCode::BADALG,     // 21    BADALG    Algorithm not supported              [RFC2930]
            22 => ResponseCode::BADTRUNC,   // 22    BADTRUNC  Bad Truncation                       [RFC4635]
            23 => ResponseCode::BADCOOKIE,  // 23    BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26)    Bad/missing server cookie    [draft-ietf-dnsop-cookies]
            _ => unimplemented!(),
        }
    }
}
<|endoftext|>


<commit_before>use std::any::TypeId;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker;

use crate::descriptor::EnumDescriptorProto;
use crate::descriptor::EnumValueDescriptorProto;
use crate::descriptor::FileDescriptorProto;
use crate::enums::ProtobufEnum;
use crate::enums::ProtobufEnumOrUnknown;
use crate::reflect::find_message_or_enum::find_message_or_enum;
use crate::reflect::find_message_or_enum::MessageOrEnum;
use crate::reflect::ProtobufValue;

/// Description for enum variant.
///
/// Used in reflection.
#[derive(Clone)]
pub struct EnumValueDescriptor {
    proto: &'static EnumValueDescriptorProto,
    protobuf_value: &'static dyn ProtobufValue,
    enum_descriptor_static: fn() -> &'static EnumDescriptor,
}

impl PartialEq for EnumValueDescriptor {
    fn eq(&self, other: &EnumValueDescriptor) -> bool {
        self.enum_descriptor() == other.enum_descriptor() && self.value() == other.value()
    }
}

impl Hash for EnumValueDescriptor {
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&self.value(), state)
    }
}

fn _assert_send_sync() {
    fn _assert_send_sync<T: Send + Sync>() {}
    _assert_send_sync::<EnumValueDescriptor>();
}

impl fmt::Debug for EnumValueDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumValueDescriptor")
            .field("proto", self.proto)
            .field("value", &"...")
            .finish()
    }
}

impl Copy for EnumValueDescriptor {}

impl EnumValueDescriptor {
    /// Name of enum variant as specified in proto file
    pub fn name(&self) -> &'static str {
        self.proto.get_name()
    }

    /// `i32` value of the enum variant
    pub fn value(&self) -> i32 {
        self.proto.get_number()
    }

    /// Convert to generic `ProtobufValue`
    pub fn protobuf_value(&self) -> &'static dyn ProtobufValue {
        self.protobuf_value
    }

    /// Get descriptor of enum holding this value.
    pub fn enum_descriptor(&self) -> &EnumDescriptor {
        (self.enum_descriptor_static)()
    }

    /// Convert this value descriptor into proper enum object.
    ///
    /// ```
    /// # use protobuf::well_known_types::NullValue;
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::reflect::EnumValueDescriptor;
    ///
    /// let value: &EnumValueDescriptor = NullValue::NULL_VALUE.descriptor();
    /// let null: Option<NullValue> = value.cast();
    /// assert_eq!(Some(NullValue::NULL_VALUE), null);
    /// ```
    pub fn cast<E: ProtobufEnum>(&self) -> Option<E> {
        self.enum_descriptor()
            .cast_to_protobuf_enum::<E>(self.value())
    }
}

trait GetEnumDescriptor: Send + Sync + 'static {
    unsafe fn copy_to(&self, value: i32, dest: *mut ());
}

struct GetDescriptorImpl<E: ProtobufEnum>(marker::PhantomData<E>);

impl<E: ProtobufEnum> GetEnumDescriptor for GetDescriptorImpl<E> {
    unsafe fn copy_to(&self, value: i32, dest: *mut ()) {
        let e = E::from_i32(value).expect("unknown value");
        (&e as *const E).copy_to(dest as *mut E, 1);
    }
}

/// Dynamic representation of enum type.
///
/// Can be used in reflective operations.
pub struct EnumDescriptor {
    full_name: String,
    proto: &'static EnumDescriptorProto,
    values: Vec<EnumValueDescriptor>,
    /// Type id of `<E>`
    type_id: TypeId,
    /// Type id of `<ProtobufEnumOrUnknown<E>>`
    enum_or_unknown_type_id: TypeId,

    #[cfg(not(rustc_nightly))]
    get_descriptor: &'static dyn GetEnumDescriptor,

    index_by_name: HashMap<String, usize>,
    index_by_number: HashMap<i32, usize>,
}

impl fmt::Debug for EnumDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumDescriptor")
            .field("full_name", &self.full_name)
            .field("..", &"..")
            .finish()
    }
}

/// Identity comparison: message descriptor are equal if their addresses are equal
impl PartialEq for EnumDescriptor {
    fn eq(&self, other: &EnumDescriptor) -> bool {
        self as *const EnumDescriptor == other as *const EnumDescriptor
    }
}

impl EnumDescriptor {
    /// Enum name as given in `.proto` file
    pub fn name(&self) -> &'static str {
        self.proto.get_name()
    }

    /// Fully qualified protobuf name of enum
    pub fn full_name(&self) -> &str {
        &self.full_name[..]
    }

    /// Get `EnumDescriptor` object for given enum type
    pub fn for_type<E: ProtobufEnum>() -> &'static EnumDescriptor {
        E::enum_descriptor_static()
    }

    fn compute_full_name(
        package: &str,
        path_to_package: &str,
        proto: &EnumDescriptorProto,
    ) -> String {
        let mut full_name = package.to_owned();
        if path_to_package.len() != 0 {
            if full_name.len() != 0 {
                full_name.push('.');
            }
            full_name.push_str(path_to_package);
        }
        if full_name.len() != 0 {
            full_name.push('.');
        }
        full_name.push_str(proto.get_name());
        full_name
    }

    /// Separate function to reduce generated code size bloat.
    fn make_indices(proto: &EnumDescriptorProto) -> (HashMap<String, usize>, HashMap<i32, usize>) {
        let mut index_by_name = HashMap::new();
        let mut index_by_number = HashMap::new();
        for (i, v) in proto.value.iter().enumerate() {
            index_by_number.insert(v.get_number(), i);
            index_by_name.insert(v.get_name().to_string(), i);
        }

        (index_by_name, index_by_number)
    }

    /// Construct `EnumDescriptor` given enum name and `FileDescriptorProto`.
    ///
    /// This function is called from generated code, and should rarely be called directly.
    ///
    /// This function is not a part of public API.
    #[doc(hidden)]
    pub fn new<E>(name_in_file: &'static str, file: &'static FileDescriptorProto) -> EnumDescriptor
    where
        E: ProtobufEnum,
    {
        let (path_to_package, proto) = match find_message_or_enum(file, name_in_file) {
            (path_to_package, MessageOrEnum::Enum(e)) => (path_to_package, e),
            (_, MessageOrEnum::Message(_)) => panic!("not an enum"),
        };

        let (index_by_name, index_by_number) = EnumDescriptor::make_indices(proto);

        let proto_values = &proto.value;
        let code_values = E::values();
        assert_eq!(proto_values.len(), code_values.len());

        let values = proto_values
            .iter()
            .zip(code_values)
            .map(|(p, c)| EnumValueDescriptor {
                proto: p,
                protobuf_value: c,
                enum_descriptor_static: E::enum_descriptor_static,
            })
            .collect();

        EnumDescriptor {
            full_name: EnumDescriptor::compute_full_name(
                file.get_package(),
                &path_to_package,
                &proto,
            ),
            proto,
            values,
            type_id: TypeId::of::<E>(),
            enum_or_unknown_type_id: TypeId::of::<ProtobufEnumOrUnknown<E>>(),
            #[cfg(not(rustc_nightly))]
            get_descriptor: &GetDescriptorImpl(marker::PhantomData::<E>),
            index_by_name,
            index_by_number,
        }
    }

    /// This enum values
    pub fn values(&self) -> &[EnumValueDescriptor] {
        &self.values
    }

    /// Find enum variant by name
    pub fn get_value_by_name<'a>(&'a self, name: &str) -> Option<&'a EnumValueDescriptor> {
        let &index = self.index_by_name.get(name)?;
        Some(&self.values[index])
    }

    /// Find enum variant by number
    pub fn get_value_by_number(&self, number: i32) -> Option<&EnumValueDescriptor> {
        let &index = self.index_by_number.get(&number)?;
        Some(&self.values[index])
    }

    /// Find enum variant by number or return default (first) enum value
    pub fn get_value_by_number_or_default(&self, number: i32) -> &EnumValueDescriptor {
        match self.get_value_by_number(number) {
            Some(v) => v,
            None => &self.values()[0],
        }
    }

    /// Check if this enum descriptor corresponds given enum type
    ///
    /// ```
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::descriptor::field_descriptor_proto::Label;
    /// # use protobuf::reflect::EnumDescriptor;
    ///
    /// let descriptor: &EnumDescriptor = Label::enum_descriptor_static();
    ///
    /// assert!(descriptor.is::<Label>())
    /// ```
    pub fn is<E: ProtobufEnum>(&self) -> bool {
        TypeId::of::<E>() == self.type_id
    }

    /// Create enum object from given value.
    ///
    /// Type parameter `E` can be either [`ProtobufEnum`](crate::ProtobufEnum)
    /// or [`ProtobufEnumOrUnknown`](crate::ProtobufEnumOrUnknown).
    ///
    /// # Panics
    ///
    /// This operation panics of `E` is `ProtobufEnum` and `value` is unknown.
    pub(crate) fn cast<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if let Some(e) = self.cast_to_protobuf_enum(value) {
            return Some(e);
        }
        if let Some(e) = self.cast_to_protobuf_enum_or_unknown(value) {
            return Some(e);
        }
        None
    }

    #[cfg(rustc_nightly)]
    fn cast_to_protobuf_enum<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.type_id {
            return None;
        }

        Some(<E as cast_impl::CastValueToProtobufEnum>::cast(value))
    }

    #[cfg(not(rustc_nightly))]
    fn cast_to_protobuf_enum<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.type_id {
            return None;
        }

        use std::mem;
        unsafe {
            let mut r = mem::uninitialized();
            self.get_descriptor
                .copy_to(value, &mut r as *mut E as *mut ());
            Some(r)
        }
    }

    #[cfg(rustc_nightly)]
    fn cast_to_protobuf_enum_or_unknown<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.enum_or_unknown_type_id {
            return None;
        }

        Some(<E as cast_impl::CastValueToProtobufEnumOrUnknown>::cast(
            value,
        ))
    }

    #[cfg(not(rustc_nightly))]
    fn cast_to_protobuf_enum_or_unknown<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.enum_or_unknown_type_id {
            return None;
        }

        use std::mem;
        use std::ptr;
        debug_assert_eq!(mem::size_of::<E>(), mem::size_of::<i32>());
        unsafe {
            // This works because `ProtobufEnumOrUnknown<E>` is `#[repr(transparent)]`
            let mut r = mem::uninitialized();
            ptr::copy(&value, &mut r as *mut E as *mut i32, 1);
            Some(r)
        }
    }
}

#[cfg(rustc_nightly)]
mod cast_impl {
    use super::*;

    pub(crate) trait CastValueToProtobufEnumOrUnknown: Sized {
        fn cast(value: i32) -> Self;
    }

    impl<T> CastValueToProtobufEnumOrUnknown for T {
        default fn cast(_value: i32) -> T {
            unreachable!();
        }
    }

    impl<E: ProtobufEnum> CastValueToProtobufEnumOrUnknown for ProtobufEnumOrUnknown<E> {
        fn cast(value: i32) -> ProtobufEnumOrUnknown<E> {
            ProtobufEnumOrUnknown::from_i32(value)
        }
    }

    pub(crate) trait CastValueToProtobufEnum: Sized {
        fn cast(value: i32) -> Self;
    }

    impl<T> CastValueToProtobufEnum for T {
        default fn cast(_value: i32) -> T {
            unreachable!();
        }
    }

    impl<E: ProtobufEnum> CastValueToProtobufEnum for E {
        fn cast(value: i32) -> E {
            E::from_i32(value).expect(&format!("unknown enum value: {}", value))
        }
    }
}
<commit_msg>Replace mem::uninitialized with MaybeUninit<commit_after>use std::any::TypeId;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker;

use crate::descriptor::EnumDescriptorProto;
use crate::descriptor::EnumValueDescriptorProto;
use crate::descriptor::FileDescriptorProto;
use crate::enums::ProtobufEnum;
use crate::enums::ProtobufEnumOrUnknown;
use crate::reflect::find_message_or_enum::find_message_or_enum;
use crate::reflect::find_message_or_enum::MessageOrEnum;
use crate::reflect::ProtobufValue;

/// Description for enum variant.
///
/// Used in reflection.
#[derive(Clone)]
pub struct EnumValueDescriptor {
    proto: &'static EnumValueDescriptorProto,
    protobuf_value: &'static dyn ProtobufValue,
    enum_descriptor_static: fn() -> &'static EnumDescriptor,
}

impl PartialEq for EnumValueDescriptor {
    fn eq(&self, other: &EnumValueDescriptor) -> bool {
        self.enum_descriptor() == other.enum_descriptor() && self.value() == other.value()
    }
}

impl Hash for EnumValueDescriptor {
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&self.value(), state)
    }
}

fn _assert_send_sync() {
    fn _assert_send_sync<T: Send + Sync>() {}
    _assert_send_sync::<EnumValueDescriptor>();
}

impl fmt::Debug for EnumValueDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumValueDescriptor")
            .field("proto", self.proto)
            .field("value", &"...")
            .finish()
    }
}

impl Copy for EnumValueDescriptor {}

impl EnumValueDescriptor {
    /// Name of enum variant as specified in proto file
    pub fn name(&self) -> &'static str {
        self.proto.get_name()
    }

    /// `i32` value of the enum variant
    pub fn value(&self) -> i32 {
        self.proto.get_number()
    }

    /// Convert to generic `ProtobufValue`
    pub fn protobuf_value(&self) -> &'static dyn ProtobufValue {
        self.protobuf_value
    }

    /// Get descriptor of enum holding this value.
    pub fn enum_descriptor(&self) -> &EnumDescriptor {
        (self.enum_descriptor_static)()
    }

    /// Convert this value descriptor into proper enum object.
    ///
    /// ```
    /// # use protobuf::well_known_types::NullValue;
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::reflect::EnumValueDescriptor;
    ///
    /// let value: &EnumValueDescriptor = NullValue::NULL_VALUE.descriptor();
    /// let null: Option<NullValue> = value.cast();
    /// assert_eq!(Some(NullValue::NULL_VALUE), null);
    /// ```
    pub fn cast<E: ProtobufEnum>(&self) -> Option<E> {
        self.enum_descriptor()
            .cast_to_protobuf_enum::<E>(self.value())
    }
}

trait GetEnumDescriptor: Send + Sync + 'static {
    unsafe fn copy_to(&self, value: i32, dest: *mut ());
}

struct GetDescriptorImpl<E: ProtobufEnum>(marker::PhantomData<E>);

impl<E: ProtobufEnum> GetEnumDescriptor for GetDescriptorImpl<E> {
    unsafe fn copy_to(&self, value: i32, dest: *mut ()) {
        let e = E::from_i32(value).expect("unknown value");
        (&e as *const E).copy_to(dest as *mut E, 1);
    }
}

/// Dynamic representation of enum type.
///
/// Can be used in reflective operations.
pub struct EnumDescriptor {
    full_name: String,
    proto: &'static EnumDescriptorProto,
    values: Vec<EnumValueDescriptor>,
    /// Type id of `<E>`
    type_id: TypeId,
    /// Type id of `<ProtobufEnumOrUnknown<E>>`
    enum_or_unknown_type_id: TypeId,

    #[cfg(not(rustc_nightly))]
    get_descriptor: &'static dyn GetEnumDescriptor,

    index_by_name: HashMap<String, usize>,
    index_by_number: HashMap<i32, usize>,
}

impl fmt::Debug for EnumDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumDescriptor")
            .field("full_name", &self.full_name)
            .field("..", &"..")
            .finish()
    }
}

/// Identity comparison: message descriptor are equal if their addresses are equal
impl PartialEq for EnumDescriptor {
    fn eq(&self, other: &EnumDescriptor) -> bool {
        self as *const EnumDescriptor == other as *const EnumDescriptor
    }
}

impl EnumDescriptor {
    /// Enum name as given in `.proto` file
    pub fn name(&self) -> &'static str {
        self.proto.get_name()
    }

    /// Fully qualified protobuf name of enum
    pub fn full_name(&self) -> &str {
        &self.full_name[..]
    }

    /// Get `EnumDescriptor` object for given enum type
    pub fn for_type<E: ProtobufEnum>() -> &'static EnumDescriptor {
        E::enum_descriptor_static()
    }

    fn compute_full_name(
        package: &str,
        path_to_package: &str,
        proto: &EnumDescriptorProto,
    ) -> String {
        let mut full_name = package.to_owned();
        if path_to_package.len() != 0 {
            if full_name.len() != 0 {
                full_name.push('.');
            }
            full_name.push_str(path_to_package);
        }
        if full_name.len() != 0 {
            full_name.push('.');
        }
        full_name.push_str(proto.get_name());
        full_name
    }

    /// Separate function to reduce generated code size bloat.
    fn make_indices(proto: &EnumDescriptorProto) -> (HashMap<String, usize>, HashMap<i32, usize>) {
        let mut index_by_name = HashMap::new();
        let mut index_by_number = HashMap::new();
        for (i, v) in proto.value.iter().enumerate() {
            index_by_number.insert(v.get_number(), i);
            index_by_name.insert(v.get_name().to_string(), i);
        }

        (index_by_name, index_by_number)
    }

    /// Construct `EnumDescriptor` given enum name and `FileDescriptorProto`.
    ///
    /// This function is called from generated code, and should rarely be called directly.
    ///
    /// This function is not a part of public API.
    #[doc(hidden)]
    pub fn new<E>(name_in_file: &'static str, file: &'static FileDescriptorProto) -> EnumDescriptor
    where
        E: ProtobufEnum,
    {
        let (path_to_package, proto) = match find_message_or_enum(file, name_in_file) {
            (path_to_package, MessageOrEnum::Enum(e)) => (path_to_package, e),
            (_, MessageOrEnum::Message(_)) => panic!("not an enum"),
        };

        let (index_by_name, index_by_number) = EnumDescriptor::make_indices(proto);

        let proto_values = &proto.value;
        let code_values = E::values();
        assert_eq!(proto_values.len(), code_values.len());

        let values = proto_values
            .iter()
            .zip(code_values)
            .map(|(p, c)| EnumValueDescriptor {
                proto: p,
                protobuf_value: c,
                enum_descriptor_static: E::enum_descriptor_static,
            })
            .collect();

        EnumDescriptor {
            full_name: EnumDescriptor::compute_full_name(
                file.get_package(),
                &path_to_package,
                &proto,
            ),
            proto,
            values,
            type_id: TypeId::of::<E>(),
            enum_or_unknown_type_id: TypeId::of::<ProtobufEnumOrUnknown<E>>(),
            #[cfg(not(rustc_nightly))]
            get_descriptor: &GetDescriptorImpl(marker::PhantomData::<E>),
            index_by_name,
            index_by_number,
        }
    }

    /// This enum values
    pub fn values(&self) -> &[EnumValueDescriptor] {
        &self.values
    }

    /// Find enum variant by name
    pub fn get_value_by_name<'a>(&'a self, name: &str) -> Option<&'a EnumValueDescriptor> {
        let &index = self.index_by_name.get(name)?;
        Some(&self.values[index])
    }

    /// Find enum variant by number
    pub fn get_value_by_number(&self, number: i32) -> Option<&EnumValueDescriptor> {
        let &index = self.index_by_number.get(&number)?;
        Some(&self.values[index])
    }

    /// Find enum variant by number or return default (first) enum value
    pub fn get_value_by_number_or_default(&self, number: i32) -> &EnumValueDescriptor {
        match self.get_value_by_number(number) {
            Some(v) => v,
            None => &self.values()[0],
        }
    }

    /// Check if this enum descriptor corresponds given enum type
    ///
    /// ```
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::descriptor::field_descriptor_proto::Label;
    /// # use protobuf::reflect::EnumDescriptor;
    ///
    /// let descriptor: &EnumDescriptor = Label::enum_descriptor_static();
    ///
    /// assert!(descriptor.is::<Label>())
    /// ```
    pub fn is<E: ProtobufEnum>(&self) -> bool {
        TypeId::of::<E>() == self.type_id
    }

    /// Create enum object from given value.
    ///
    /// Type parameter `E` can be either [`ProtobufEnum`](crate::ProtobufEnum)
    /// or [`ProtobufEnumOrUnknown`](crate::ProtobufEnumOrUnknown).
    ///
    /// # Panics
    ///
    /// This operation panics of `E` is `ProtobufEnum` and `value` is unknown.
    pub(crate) fn cast<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if let Some(e) = self.cast_to_protobuf_enum(value) {
            return Some(e);
        }
        if let Some(e) = self.cast_to_protobuf_enum_or_unknown(value) {
            return Some(e);
        }
        None
    }

    #[cfg(rustc_nightly)]
    fn cast_to_protobuf_enum<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.type_id {
            return None;
        }

        Some(<E as cast_impl::CastValueToProtobufEnum>::cast(value))
    }

    #[cfg(not(rustc_nightly))]
    fn cast_to_protobuf_enum<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.type_id {
            return None;
        }

        use std::mem;
        unsafe {
            let mut r = mem::MaybeUninit::<E>::uninit();
            self.get_descriptor
                .copy_to(value, r.as_mut_ptr() as *mut ());
            Some(r.assume_init())
        }
    }

    #[cfg(rustc_nightly)]
    fn cast_to_protobuf_enum_or_unknown<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.enum_or_unknown_type_id {
            return None;
        }

        Some(<E as cast_impl::CastValueToProtobufEnumOrUnknown>::cast(
            value,
        ))
    }

    #[cfg(not(rustc_nightly))]
    fn cast_to_protobuf_enum_or_unknown<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.enum_or_unknown_type_id {
            return None;
        }

        use std::mem;
        use std::ptr;
        debug_assert_eq!(mem::size_of::<E>(), mem::size_of::<i32>());
        unsafe {
            // This works because `ProtobufEnumOrUnknown<E>` is `#[repr(transparent)]`
            let mut r = mem::MaybeUninit::<E>::uninit();
            ptr::copy(&value, r.as_mut_ptr() as *mut i32, 1);
            Some(r.assume_init())
        }
    }
}

#[cfg(rustc_nightly)]
mod cast_impl {
    use super::*;

    pub(crate) trait CastValueToProtobufEnumOrUnknown: Sized {
        fn cast(value: i32) -> Self;
    }

    impl<T> CastValueToProtobufEnumOrUnknown for T {
        default fn cast(_value: i32) -> T {
            unreachable!();
        }
    }

    impl<E: ProtobufEnum> CastValueToProtobufEnumOrUnknown for ProtobufEnumOrUnknown<E> {
        fn cast(value: i32) -> ProtobufEnumOrUnknown<E> {
            ProtobufEnumOrUnknown::from_i32(value)
        }
    }

    pub(crate) trait CastValueToProtobufEnum: Sized {
        fn cast(value: i32) -> Self;
    }

    impl<T> CastValueToProtobufEnum for T {
        default fn cast(_value: i32) -> T {
            unreachable!();
        }
    }

    impl<E: ProtobufEnum> CastValueToProtobufEnum for E {
        fn cast(value: i32) -> E {
            E::from_i32(value).expect(&format!("unknown enum value: {}", value))
        }
    }
}
<|endoftext|>


<commit_before>//! Shared access to Cairo image surfaces.
use std::ptr::NonNull;

use cairo::prelude::SurfaceExt;
use cairo::{self, ImageSurface};
use cairo_sys;
use glib::translate::{Stash, ToGlibPtr};

use filters::context::IRect;

use super::{iterators::Pixels, ImageSurfaceDataExt, Pixel};

/// Wrapper for a Cairo image surface that allows shared access.
///
/// There doesn't seem to be any good way of making safe shared access to `ImageSurface` pixel
/// data, since a read-only borrowed reference can still be cloned and then modified (for example,
/// via a `Context`). We can't simply use `ImageSurface::get_data()` because in the filter code we
/// have surfaces referenced from multiple places and it would probably add more complexity to
/// remove that and start passing around references.
///
/// This wrapper asserts the uniqueness of its image surface and doesn't permit modifying it.
///
/// Note: originally I had an idea of using `Rc<RefCell<ImageSurface>>` here which allows to create
/// both read-only and unique read-write accessors safely, however then I realized a read-write
/// accessor isn't of much use if it can't expose a Cairo context interface. Cairo contexts have
/// the very same issue that they can be cloned from a read-only reference and break all safety
/// constraints in this way. Thus the only safe way of exposing a Cairo context seemed to be to
/// manually add all Cairo context methods on the accessor forwarding to the underlying Cairo
/// context (without exposing the context itself to prevent cloning), which would result in too
/// much code. Unless it's absolutely required, I'd like to avoid that.
///
/// Having just read-only access simplifies things further dropping the need for `Rc<RefCell<>>`
/// altogether.
#[derive(Debug, Clone)]
pub struct SharedImageSurface {
    surface: ImageSurface,

    data_ptr: NonNull<u8>, // *const.
    width: i32,
    height: i32,
    stride: isize,
}

impl SharedImageSurface {
    /// Creates a `SharedImageSurface` from a unique `ImageSurface`.
    ///
    /// # Panics
    /// Panics if the `ImageSurface` is not unique, that is, its reference count isn't 1.
    #[inline]
    pub fn new(surface: ImageSurface) -> Result<Self, cairo::Status> {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        surface.flush();
        if surface.status() != cairo::Status::Success {
            return Err(surface.status());
        }

        let data_ptr = NonNull::new(unsafe {
            cairo_sys::cairo_image_surface_get_data(surface.to_raw_none())
        }).unwrap();

        let width = surface.get_width();
        let height = surface.get_height();
        let stride = surface.get_stride() as isize;

        Ok(Self {
            surface,
            data_ptr,
            width,
            height,
            stride,
        })
    }

    /// Converts this `SharedImageSurface` back into a Cairo image surface.
    ///
    /// # Panics
    /// Panics if the underlying Cairo image surface is not unique, that is, there are other
    /// instances of `SharedImageSurface` pointing at the same Cairo image surface.
    #[inline]
    pub fn into_image_surface(self) -> ImageSurface {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(self.surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        self.surface
    }

    /// Returns the surface width.
    #[inline]
    pub fn width(&self) -> i32 {
        self.width
    }

    /// Returns the surface height.
    #[inline]
    pub fn height(&self) -> i32 {
        self.height
    }

    /// Retrieves the pixel value at the given coordinates.
    #[inline]
    pub fn get_pixel(&self, x: u32, y: u32) -> Pixel {
        assert!(x < self.width as u32);
        assert!(y < self.height as u32);

        let value = unsafe {
            *(self
                .data_ptr
                .as_ptr()
                .offset(y as isize * self.stride + x as isize * 4) as *const u32)
        };

        Pixel {
            r: ((value >> 16) & 0xFF) as u8,
            g: ((value >> 8) & 0xFF) as u8,
            b: (value & 0xFF) as u8,
            a: ((value >> 24) & 0xFF) as u8,
        }
    }

    /// Calls `set_source_surface()` on the given Cairo context.
    #[inline]
    pub fn set_as_source_surface(&self, cr: &cairo::Context, x: f64, y: f64) {
        cr.set_source_surface(&self.surface, x, y);
    }

    /// Returns a new `ImageSurface` with the same contents as the one stored in this
    /// `SharedImageSurface` within the given bounds.
    pub fn copy_surface(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            bounds.x0 as f64,
            bounds.y0 as f64,
            (bounds.x1 - bounds.x0) as f64,
            (bounds.y1 - bounds.y0) as f64,
        );
        cr.clip();

        cr.set_source_surface(&self.surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Scales the given surface by `x` and `y` into a surface `width`×`height` in size, clipped by
    /// `bounds`.
    pub fn scale_to(
        &self,
        width: i32,
        height: i32,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<SharedImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?;

        {
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            cr.scale(x, y);
            self.set_as_source_surface(&cr, 0.0, 0.0);
            cr.paint();
        }

        Ok(SharedImageSurface::new(output_surface)?)
    }

    /// Returns a scaled version of a surface and bounds.
    #[inline]
    pub fn scale(
        &self,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<(SharedImageSurface, IRect), cairo::Status> {
        let new_width = (f64::from(self.width) * x).ceil() as i32;
        let new_height = (f64::from(self.height) * x).ceil() as i32;
        let new_bounds = bounds.scale(x, y);

        Ok((
            self.scale_to(new_width, new_height, new_bounds, x, y)?,
            new_bounds,
        ))
    }

    /// Returns a surface with black background and alpha channel matching this surface.
    pub fn extract_alpha(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let output_stride = output_surface.get_stride() as usize;
        {
            let mut output_data = output_surface.get_data().unwrap();

            for (x, y, Pixel { a, .. }) in Pixels::new(self, bounds) {
                let output_pixel = Pixel {
                    r: 0,
                    g: 0,
                    b: 0,
                    a,
                };
                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        Ok(output_surface)
    }

    /// Returns a raw pointer to the underlying surface.
    ///
    /// # Safety
    /// The returned pointer must not be used to modify the surface.
    #[inline]
    pub unsafe fn to_glib_none(&self) -> Stash<*mut cairo_sys::cairo_surface_t, ImageSurface> {
        self.surface.to_glib_none()
    }
}
<commit_msg>Add SharedImageSurface::unpremultiply()<commit_after>//! Shared access to Cairo image surfaces.
use std::ptr::NonNull;

use cairo::prelude::SurfaceExt;
use cairo::{self, ImageSurface};
use cairo_sys;
use glib::translate::{Stash, ToGlibPtr};

use filters::context::IRect;

use super::{iterators::Pixels, ImageSurfaceDataExt, Pixel};

/// Wrapper for a Cairo image surface that allows shared access.
///
/// There doesn't seem to be any good way of making safe shared access to `ImageSurface` pixel
/// data, since a read-only borrowed reference can still be cloned and then modified (for example,
/// via a `Context`). We can't simply use `ImageSurface::get_data()` because in the filter code we
/// have surfaces referenced from multiple places and it would probably add more complexity to
/// remove that and start passing around references.
///
/// This wrapper asserts the uniqueness of its image surface and doesn't permit modifying it.
///
/// Note: originally I had an idea of using `Rc<RefCell<ImageSurface>>` here which allows to create
/// both read-only and unique read-write accessors safely, however then I realized a read-write
/// accessor isn't of much use if it can't expose a Cairo context interface. Cairo contexts have
/// the very same issue that they can be cloned from a read-only reference and break all safety
/// constraints in this way. Thus the only safe way of exposing a Cairo context seemed to be to
/// manually add all Cairo context methods on the accessor forwarding to the underlying Cairo
/// context (without exposing the context itself to prevent cloning), which would result in too
/// much code. Unless it's absolutely required, I'd like to avoid that.
///
/// Having just read-only access simplifies things further dropping the need for `Rc<RefCell<>>`
/// altogether.
#[derive(Debug, Clone)]
pub struct SharedImageSurface {
    surface: ImageSurface,

    data_ptr: NonNull<u8>, // *const.
    width: i32,
    height: i32,
    stride: isize,
}

impl SharedImageSurface {
    /// Creates a `SharedImageSurface` from a unique `ImageSurface`.
    ///
    /// # Panics
    /// Panics if the `ImageSurface` is not unique, that is, its reference count isn't 1.
    #[inline]
    pub fn new(surface: ImageSurface) -> Result<Self, cairo::Status> {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        surface.flush();
        if surface.status() != cairo::Status::Success {
            return Err(surface.status());
        }

        let data_ptr = NonNull::new(unsafe {
            cairo_sys::cairo_image_surface_get_data(surface.to_raw_none())
        }).unwrap();

        let width = surface.get_width();
        let height = surface.get_height();
        let stride = surface.get_stride() as isize;

        Ok(Self {
            surface,
            data_ptr,
            width,
            height,
            stride,
        })
    }

    /// Converts this `SharedImageSurface` back into a Cairo image surface.
    ///
    /// # Panics
    /// Panics if the underlying Cairo image surface is not unique, that is, there are other
    /// instances of `SharedImageSurface` pointing at the same Cairo image surface.
    #[inline]
    pub fn into_image_surface(self) -> ImageSurface {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(self.surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        self.surface
    }

    /// Returns the surface width.
    #[inline]
    pub fn width(&self) -> i32 {
        self.width
    }

    /// Returns the surface height.
    #[inline]
    pub fn height(&self) -> i32 {
        self.height
    }

    /// Retrieves the pixel value at the given coordinates.
    #[inline]
    pub fn get_pixel(&self, x: u32, y: u32) -> Pixel {
        assert!(x < self.width as u32);
        assert!(y < self.height as u32);

        let value = unsafe {
            *(self
                .data_ptr
                .as_ptr()
                .offset(y as isize * self.stride + x as isize * 4) as *const u32)
        };

        Pixel {
            r: ((value >> 16) & 0xFF) as u8,
            g: ((value >> 8) & 0xFF) as u8,
            b: (value & 0xFF) as u8,
            a: ((value >> 24) & 0xFF) as u8,
        }
    }

    /// Calls `set_source_surface()` on the given Cairo context.
    #[inline]
    pub fn set_as_source_surface(&self, cr: &cairo::Context, x: f64, y: f64) {
        cr.set_source_surface(&self.surface, x, y);
    }

    /// Returns a new `ImageSurface` with the same contents as the one stored in this
    /// `SharedImageSurface` within the given bounds.
    pub fn copy_surface(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            bounds.x0 as f64,
            bounds.y0 as f64,
            (bounds.x1 - bounds.x0) as f64,
            (bounds.y1 - bounds.y0) as f64,
        );
        cr.clip();

        cr.set_source_surface(&self.surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Scales the given surface by `x` and `y` into a surface `width`×`height` in size, clipped by
    /// `bounds`.
    pub fn scale_to(
        &self,
        width: i32,
        height: i32,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<SharedImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?;

        {
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            cr.scale(x, y);
            self.set_as_source_surface(&cr, 0.0, 0.0);
            cr.paint();
        }

        Ok(SharedImageSurface::new(output_surface)?)
    }

    /// Returns a scaled version of a surface and bounds.
    #[inline]
    pub fn scale(
        &self,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<(SharedImageSurface, IRect), cairo::Status> {
        let new_width = (f64::from(self.width) * x).ceil() as i32;
        let new_height = (f64::from(self.height) * x).ceil() as i32;
        let new_bounds = bounds.scale(x, y);

        Ok((
            self.scale_to(new_width, new_height, new_bounds, x, y)?,
            new_bounds,
        ))
    }

    /// Returns a surface with black background and alpha channel matching this surface.
    pub fn extract_alpha(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let output_stride = output_surface.get_stride() as usize;
        {
            let mut output_data = output_surface.get_data().unwrap();

            for (x, y, Pixel { a, .. }) in Pixels::new(self, bounds) {
                let output_pixel = Pixel {
                    r: 0,
                    g: 0,
                    b: 0,
                    a,
                };
                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        Ok(output_surface)
    }

    /// Returns a surface with pre-multiplication of color values undone.
    ///
    /// HACK: this is storing unpremultiplied pixels in an ARGB32 image surface (which is supposed
    /// to be premultiplied pixels).
    pub fn unpremultiply(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let stride = output_surface.get_stride() as usize;
        {
            let mut data = output_surface.get_data().unwrap();

            for (x, y, pixel) in Pixels::new(self, bounds) {
                data.set_pixel(stride, pixel.unpremultiply(), x, y);
            }
        }

        Ok(output_surface)
    }

    /// Returns a raw pointer to the underlying surface.
    ///
    /// # Safety
    /// The returned pointer must not be used to modify the surface.
    #[inline]
    pub unsafe fn to_glib_none(&self) -> Stash<*mut cairo_sys::cairo_surface_t, ImageSurface> {
        self.surface.to_glib_none()
    }
}
<|endoftext|>


<commit_before>use std::option::Option;
use std::ops::Deref;

use rocksdb::{DB, Writable, DBIterator, Direction, IteratorMode, DBVector, WriteBatch};
use rocksdb::rocksdb::Snapshot;
use protobuf;
use byteorder::{ByteOrder, BigEndian};

use raftserver::{Result, other};

pub fn new_engine(path: &str) -> Result<DB> {
    // TODO: set proper options here,
    let db = try!(DB::open_default(path));
    Ok(db)
}

pub enum DBValue {
    DBVector(DBVector),
    Box(Box<[u8]>),
}

impl Deref for DBValue {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        match *self {
            DBValue::DBVector(ref v) => v,
            DBValue::Box(ref v) => v,
        }
    }
}

pub trait Retriever {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>>;
    fn new_iterator(&self, start_key: &[u8]) -> DBIterator;

    fn get_msg<M>(&self, key: &[u8]) -> Result<Option<M>>
        where M: protobuf::Message + protobuf::MessageStatic
    {
        let value = try!(self.get_value(key));

        if value.is_none() {
            return Ok(None);
        }

        let mut m = M::new();
        try!(m.merge_from_bytes(&value.unwrap()));
        Ok(Some(m))
    }

    fn get_u64(&self, key: &[u8]) -> Result<Option<u64>> {
        let value = try!(self.get_value(key));

        if value.is_none() {
            return Ok(None);
        }

        let value = value.unwrap();
        if value.len() != 8 {
            return Err(other(format!("need 8 bytes, but only got {}", value.len())));
        }

        let n = BigEndian::read_u64(&value);
        Ok(Some(n))
    }

    fn get_i64(&self, key: &[u8]) -> Result<Option<i64>> {
        let r = try!(self.get_u64(key));
        match r {
            None => Ok(None),
            Some(n) => Ok(Some(n as i64)),
        }
    }

    // scan scans database using an iterator in range [start_key, end_key), calls function f for
    // each iteration, if f returns false, terminates this scan.
    fn scan<F>(&self, start_key: &[u8], end_key: &[u8], f: &mut F) -> Result<()>
        where F: FnMut(&[u8], &[u8]) -> Result<bool>
    {
        let it = self.new_iterator(start_key);

        for (key, value) in it {
            if key.as_ref() >= end_key {
                break;
            }

            let r = try!(f(key.as_ref(), value.as_ref()));
            if !r {
                break;
            }
        }

        Ok(())
    }
}

impl Retriever for DB {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>> {
        let v = try!(self.get(key));
        Ok(v.map(DBValue::DBVector))
    }

    fn new_iterator(&self, start_key: &[u8]) -> DBIterator {
        self.iterator(IteratorMode::From(start_key, Direction::forward))
    }
}

impl<'a> Retriever for Snapshot<'a> {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>> {
        let mut it = self.iterator(IteratorMode::From(key, Direction::forward));
        if let Some((seek_key, value)) = it.next() {
            if seek_key.as_ref() == key {
                return Ok(Some(DBValue::Box(value)));
            }
        }
        Ok(None)
    }

    fn new_iterator(&self, start_key: &[u8]) -> DBIterator {
        self.iterator(IteratorMode::From(start_key, Direction::forward))
    }
}

pub trait Mutator : Writable{
    fn put_msg<M: protobuf::Message>(&self, key: &[u8], m: &M) -> Result<()> {
        let value = try!(m.write_to_bytes());
        try!(self.put(key, &value));
        Ok(())
    }

    fn put_u64(&self, key: &[u8], n: u64) -> Result<()> {
        let mut value = vec![0;8];
        BigEndian::write_u64(&mut value, n);
        try!(self.put(key, &value));
        Ok(())
    }

    fn put_i64(&self, key: &[u8], n: i64) -> Result<()> {
        self.put_u64(key, n as u64)
    }
}

impl Mutator for DB {}
impl Mutator for WriteBatch {}

#[cfg(test)]
mod tests {
    use tempdir::TempDir;
    use rocksdb::Writable;

    use super::*;
    use raftserver::Result;
    use proto::metapb::Region;

    #[test]
    fn test_base() {
        let path = TempDir::new("var").unwrap();
        let engine = new_engine(path.path().to_str().unwrap()).unwrap();

        let mut r = Region::new();
        r.set_region_id(10);

        let key = b"key";
        engine.put_msg(key, &r).unwrap();

        let snap = engine.snapshot();

        let mut r1: Region = engine.get_msg(key).unwrap().unwrap();
        assert_eq!(r, r1);

        let mut r2: Region = snap.get_msg(key).unwrap().unwrap();
        assert_eq!(r, r2);

        r.set_region_id(11);
        engine.put_msg(key, &r).unwrap();
        r1 = engine.get_msg(key).unwrap().unwrap();
        r2 = snap.get_msg(key).unwrap().unwrap();
        assert!(r1 != r2);

        let b: Option<Region> = engine.get_msg(b"missing_key").unwrap();
        assert!(b.is_none());

        engine.put_i64(key, -1).unwrap();
        assert_eq!(engine.get_i64(key).unwrap(), Some(-1));
        assert!(engine.get_i64(b"missing_key").unwrap().is_none());

        let snap = engine.snapshot();
        assert_eq!(snap.get_i64(key).unwrap(), Some(-1));
        assert!(snap.get_i64(b"missing_key").unwrap().is_none());

        engine.put_u64(key, 1).unwrap();
        assert_eq!(engine.get_u64(key).unwrap(), Some(1));
        assert_eq!(snap.get_i64(key).unwrap(), Some(-1));
    }

    #[test]
    fn test_scan() {
        let path = TempDir::new("var").unwrap();
        let engine = new_engine(path.path().to_str().unwrap()).unwrap();

        engine.put(b"a1", b"v1").unwrap();
        engine.put(b"a2", b"v2").unwrap();

        let mut data = vec![];
        engine.scan(b"",
                    &[0xFF, 0xFF],
                    &mut |key, value| -> Result<bool> {
                        data.push((key.to_vec(), value.to_vec()));
                        Ok(true)
                    })
              .unwrap();

        assert_eq!(data.len(), 2);

        data.clear();
        let mut index = 0;
        engine.scan(b"",
                    &[0xFF, 0xFF],
                    &mut |key, value| -> Result<bool> {
                        data.push((key.to_vec(), value.to_vec()));
                        index += 1;
                        Ok(index != 1)
                    })
              .unwrap();

        assert_eq!(data.len(), 1);

        let snap = engine.snapshot();

        engine.put(b"a3", b"v3").unwrap();

        data.clear();

        snap.scan(b"",
                  &[0xFF, 0xFF],
                  &mut |key, value| -> Result<bool> {
                      data.push((key.to_vec(), value.to_vec()));
                      Ok(true)
                  })
            .unwrap();

        assert_eq!(data.len(), 2);
    }
}
<commit_msg>raftserver: support seek in Retriever.<commit_after>use std::option::Option;
use std::ops::Deref;

use rocksdb::{DB, Writable, DBIterator, Direction, IteratorMode, DBVector, WriteBatch};
use rocksdb::rocksdb::Snapshot;
use protobuf;
use byteorder::{ByteOrder, BigEndian};

use raftserver::{Result, other};

pub fn new_engine(path: &str) -> Result<DB> {
    // TODO: set proper options here,
    let db = try!(DB::open_default(path));
    Ok(db)
}

pub enum DBValue {
    DBVector(DBVector),
    Box(Box<[u8]>),
}

impl Deref for DBValue {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        match *self {
            DBValue::DBVector(ref v) => v,
            DBValue::Box(ref v) => v,
        }
    }
}

pub trait Retriever {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>>;
    fn new_iterator(&self, start_key: &[u8]) -> DBIterator;

    fn get_msg<M>(&self, key: &[u8]) -> Result<Option<M>>
        where M: protobuf::Message + protobuf::MessageStatic
    {
        let value = try!(self.get_value(key));

        if value.is_none() {
            return Ok(None);
        }

        let mut m = M::new();
        try!(m.merge_from_bytes(&value.unwrap()));
        Ok(Some(m))
    }

    fn get_u64(&self, key: &[u8]) -> Result<Option<u64>> {
        let value = try!(self.get_value(key));

        if value.is_none() {
            return Ok(None);
        }

        let value = value.unwrap();
        if value.len() != 8 {
            return Err(other(format!("need 8 bytes, but only got {}", value.len())));
        }

        let n = BigEndian::read_u64(&value);
        Ok(Some(n))
    }

    fn get_i64(&self, key: &[u8]) -> Result<Option<i64>> {
        let r = try!(self.get_u64(key));
        match r {
            None => Ok(None),
            Some(n) => Ok(Some(n as i64)),
        }
    }

    // scan scans database using an iterator in range [start_key, end_key), calls function f for
    // each iteration, if f returns false, terminates this scan.
    fn scan<F>(&self, start_key: &[u8], end_key: &[u8], f: &mut F) -> Result<()>
        where F: FnMut(&[u8], &[u8]) -> Result<bool>
    {
        let it = self.new_iterator(start_key);

        for (key, value) in it {
            if key.as_ref() >= end_key {
                break;
            }

            let r = try!(f(key.as_ref(), value.as_ref()));
            if !r {
                break;
            }
        }

        Ok(())
    }

    // Seek the first key >= given key, if no found, return None.
    fn seek(&self, key: &[u8]) -> Result<Option<(Vec<u8>, Vec<u8>)>> {
        let pair = self.new_iterator(key).next().map(|(k, v)| (k.into_vec(), v.into_vec()));
        Ok(pair)
    }
}

impl Retriever for DB {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>> {
        let v = try!(self.get(key));
        Ok(v.map(DBValue::DBVector))
    }

    fn new_iterator(&self, start_key: &[u8]) -> DBIterator {
        self.iterator(IteratorMode::From(start_key, Direction::forward))
    }
}

impl<'a> Retriever for Snapshot<'a> {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>> {
        let mut it = self.iterator(IteratorMode::From(key, Direction::forward));
        if let Some((seek_key, value)) = it.next() {
            if seek_key.as_ref() == key {
                return Ok(Some(DBValue::Box(value)));
            }
        }
        Ok(None)
    }

    fn new_iterator(&self, start_key: &[u8]) -> DBIterator {
        self.iterator(IteratorMode::From(start_key, Direction::forward))
    }
}

pub trait Mutator : Writable{
    fn put_msg<M: protobuf::Message>(&self, key: &[u8], m: &M) -> Result<()> {
        let value = try!(m.write_to_bytes());
        try!(self.put(key, &value));
        Ok(())
    }

    fn put_u64(&self, key: &[u8], n: u64) -> Result<()> {
        let mut value = vec![0;8];
        BigEndian::write_u64(&mut value, n);
        try!(self.put(key, &value));
        Ok(())
    }

    fn put_i64(&self, key: &[u8], n: i64) -> Result<()> {
        self.put_u64(key, n as u64)
    }
}

impl Mutator for DB {}
impl Mutator for WriteBatch {}

#[cfg(test)]
mod tests {
    use tempdir::TempDir;
    use rocksdb::Writable;

    use super::*;
    use raftserver::Result;
    use proto::metapb::Region;

    #[test]
    fn test_base() {
        let path = TempDir::new("var").unwrap();
        let engine = new_engine(path.path().to_str().unwrap()).unwrap();

        let mut r = Region::new();
        r.set_region_id(10);

        let key = b"key";
        engine.put_msg(key, &r).unwrap();

        let snap = engine.snapshot();

        let mut r1: Region = engine.get_msg(key).unwrap().unwrap();
        assert_eq!(r, r1);

        let mut r2: Region = snap.get_msg(key).unwrap().unwrap();
        assert_eq!(r, r2);

        r.set_region_id(11);
        engine.put_msg(key, &r).unwrap();
        r1 = engine.get_msg(key).unwrap().unwrap();
        r2 = snap.get_msg(key).unwrap().unwrap();
        assert!(r1 != r2);

        let b: Option<Region> = engine.get_msg(b"missing_key").unwrap();
        assert!(b.is_none());

        engine.put_i64(key, -1).unwrap();
        assert_eq!(engine.get_i64(key).unwrap(), Some(-1));
        assert!(engine.get_i64(b"missing_key").unwrap().is_none());

        let snap = engine.snapshot();
        assert_eq!(snap.get_i64(key).unwrap(), Some(-1));
        assert!(snap.get_i64(b"missing_key").unwrap().is_none());

        engine.put_u64(key, 1).unwrap();
        assert_eq!(engine.get_u64(key).unwrap(), Some(1));
        assert_eq!(snap.get_i64(key).unwrap(), Some(-1));
    }

    #[test]
    fn test_scan() {
        let path = TempDir::new("var").unwrap();
        let engine = new_engine(path.path().to_str().unwrap()).unwrap();

        engine.put(b"a1", b"v1").unwrap();
        engine.put(b"a2", b"v2").unwrap();

        let mut data = vec![];
        engine.scan(b"",
                    &[0xFF, 0xFF],
                    &mut |key, value| -> Result<bool> {
                        data.push((key.to_vec(), value.to_vec()));
                        Ok(true)
                    })
              .unwrap();

        assert_eq!(data.len(), 2);
        let pair = engine.seek(b"a1").unwrap().unwrap();
        assert_eq!(pair, (b"a1".to_vec(), b"v1".to_vec()));
        assert!(engine.seek(b"a3").unwrap().is_none());

        data.clear();
        let mut index = 0;
        engine.scan(b"",
                    &[0xFF, 0xFF],
                    &mut |key, value| -> Result<bool> {
                        data.push((key.to_vec(), value.to_vec()));
                        index += 1;
                        Ok(index != 1)
                    })
              .unwrap();

        assert_eq!(data.len(), 1);

        let snap = engine.snapshot();

        engine.put(b"a3", b"v3").unwrap();
        assert!(engine.seek(b"a3").unwrap().is_some());

        let pair = snap.seek(b"a1").unwrap().unwrap();
        assert_eq!(pair, (b"a1".to_vec(), b"v1".to_vec()));
        assert!(snap.seek(b"a3").unwrap().is_none());

        data.clear();

        snap.scan(b"",
                  &[0xFF, 0xFF],
                  &mut |key, value| -> Result<bool> {
                      data.push((key.to_vec(), value.to_vec()));
                      Ok(true)
                  })
            .unwrap();

        assert_eq!(data.len(), 2);
    }
}
<|endoftext|>