<commit_before>use prelude::*;
use fmt::{self, Write, FlagV1};

struct PadAdapter<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    on_newline: bool,
}

impl<'a, 'b: 'a> PadAdapter<'a, 'b> {
    fn new(fmt: &'a mut fmt::Formatter<'b>) -> PadAdapter<'a, 'b> {
        PadAdapter {
            fmt: fmt,
            on_newline: false,
        }
    }
}

impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
    fn write_str(&mut self, mut s: &str) -> fmt::Result {
        while !s.is_empty() {
            if self.on_newline {
                try!(self.fmt.write_str("    "));
            }

            let split = match s.find('\n') {
                Some(pos) => {
                    self.on_newline = true;
                    pos + 1
                }
                None => {
                    self.on_newline = false;
                    s.len()
                }
            };
            try!(self.fmt.write_str(&s[..split]));
            s = &s[split..];
        }

        Ok(())
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_struct` method.
#[must_use]
pub struct DebugStruct<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str)
                                -> DebugStruct<'a, 'b> {
    let result = fmt.write_str(name);
    DebugStruct {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
    /// Adds a new field to the generated struct output.
    #[unstable(feature = "core", reason = "method was just created")]
    pub fn field<S>(mut self, name: &str, value: &S) -> DebugStruct<'a, 'b>
            where S: fmt::Debug {
        self.result = self.result.and_then(|_| {
            let prefix = if self.has_fields {
                ","
            } else {
                " {"
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer, format_args!("{}\n{}: {:#?}", prefix, name, value))
            } else {
                write!(self.fmt, "{} {}: {:?}", prefix, name, value)
            }
        });

        self.has_fields = true;
        self
    }

    /// Consumes the `DebugStruct`, finishing output and returning any error
    /// encountered.
    #[unstable(feature = "core", reason = "method was just created")]
    pub fn finish(mut self) -> fmt::Result {
        if self.has_fields {
            self.result = self.result.and_then(|_| {
                if self.is_pretty() {
                    self.fmt.write_str("\n}")
                } else {
                    self.fmt.write_str(" }")
                }
            });
        }
        self.result
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_tuple` method.
#[must_use]
pub struct DebugTuple<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugTuple<'a, 'b> {
    let result = fmt.write_str(name);
    DebugTuple {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
    /// Adds a new field to the generated tuple struct output.
    #[unstable(feature = "core", reason = "method was just created")]
    pub fn field<S>(mut self, value: &S) -> DebugTuple<'a, 'b> where S: fmt::Debug {
        self.result = self.result.and_then(|_| {
            let (prefix, space) = if self.has_fields {
                (",", " ")
            } else {
                ("(", "")
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, value))
            } else {
                write!(self.fmt, "{}{}{:?}", prefix, space, value)
            }
        });

        self.has_fields = true;
        self
    }

    /// Consumes the `DebugTuple`, finishing output and returning any error
    /// encountered.
    #[unstable(feature = "core", reason = "method was just created")]
    pub fn finish(mut self) -> fmt::Result {
        if self.has_fields {
            self.result = self.result.and_then(|_| {
                if self.is_pretty() {
                    self.fmt.write_str("\n)")
                } else {
                    self.fmt.write_str(")")
                }
            });
        }
        self.result
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_set` method.
#[must_use]
pub struct DebugSet<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugSet<'a, 'b> {
    let result = write!(fmt, "{} {{", name);
    DebugSet {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugSet<'a, 'b> {
    /// Adds a new entry to the set output.
    #[unstable(feature = "core", reason = "method was just created")]
    pub fn entry<S>(mut self, entry: &S) -> DebugSet<'a, 'b> where S: fmt::Debug {
        self.result = self.result.and_then(|_| {
            let prefix = if self.has_fields {
                ","
            } else {
                ""
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
            } else {
                write!(self.fmt, "{} {:?}", prefix, entry)
            }
        });

        self.has_fields = true;
        self
    }

    /// Consumes the `DebugSet`, finishing output and returning any error
    /// encountered.
    #[unstable(feature = "core", reason = "method was just created")]
    pub fn finish(self) -> fmt::Result {
        self.result.and_then(|_| {
            let end = match (self.has_fields, self.is_pretty()) {
                (false, _) => "}",
                (true, false) => " }",
                (true, true) => "\n}",
            };
            self.fmt.write_str(end)
        })
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_map` method.
#[must_use]
pub struct DebugMap<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugMap<'a, 'b> {
    let result = write!(fmt, "{} {{", name);
    DebugMap {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugMap<'a, 'b> {
    /// Adds a new entry to the map output.
    #[unstable(feature = "core", reason = "method was just created")]
    pub fn entry<K, V>(mut self, key: &K, value: &V) -> DebugMap<'a, 'b>
            where K: fmt::Debug, V: fmt::Debug {
        self.result = self.result.and_then(|_| {
            let prefix = if self.has_fields {
                ","
            } else {
                ""
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer, format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
            } else {
                write!(self.fmt, "{} {:?}: {:?}", prefix, key, value)
            }
        });

        self.has_fields = true;
        self
    }

    /// Consumes the `DebugMap`, finishing output and returning any error
    /// encountered.
    #[unstable(feature = "core", reason = "method was just created")]
    pub fn finish(self) -> fmt::Result {
        self.result.and_then(|_| {
            let end = match (self.has_fields, self.is_pretty()) {
                (false, _) => "}",
                (true, false) => " }",
                (true, true) => "\n}",
            };
            self.fmt.write_str(end)
        })
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}
<commit_msg>Restructure debug builders to minimize codegen<commit_after>use prelude::*;
use fmt::{self, Write, FlagV1};

struct PadAdapter<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    on_newline: bool,
}

impl<'a, 'b: 'a> PadAdapter<'a, 'b> {
    fn new(fmt: &'a mut fmt::Formatter<'b>) -> PadAdapter<'a, 'b> {
        PadAdapter {
            fmt: fmt,
            on_newline: false,
        }
    }
}

impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
    fn write_str(&mut self, mut s: &str) -> fmt::Result {
        while !s.is_empty() {
            if self.on_newline {
                try!(self.fmt.write_str("    "));
            }

            let split = match s.find('\n') {
                Some(pos) => {
                    self.on_newline = true;
                    pos + 1
                }
                None => {
                    self.on_newline = false;
                    s.len()
                }
            };
            try!(self.fmt.write_str(&s[..split]));
            s = &s[split..];
        }

        Ok(())
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_struct` method.
#[must_use]
pub struct DebugStruct<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str)
                                -> DebugStruct<'a, 'b> {
    let result = fmt.write_str(name);
    DebugStruct {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
    /// Adds a new field to the generated struct output.
    #[unstable(feature = "core", reason = "method was just created")]
    #[inline]
    pub fn field(mut self, name: &str, value: &fmt::Debug) -> DebugStruct<'a, 'b> {
        self.field_inner(name, value);
        self
    }

    fn field_inner(&mut self, name: &str, value: &fmt::Debug) {
        self.result = self.result.and_then(|_| {
            let prefix = if self.has_fields {
                ","
            } else {
                " {"
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer, format_args!("{}\n{}: {:#?}", prefix, name, value))
            } else {
                write!(self.fmt, "{} {}: {:?}", prefix, name, value)
            }
        });

        self.has_fields = true;
    }

    /// Consumes the `DebugStruct`, finishing output and returning any error
    /// encountered.
    #[unstable(feature = "core", reason = "method was just created")]
    #[inline]
    pub fn finish(mut self) -> fmt::Result {
        self.finish_inner();
        self.result
    }

    fn finish_inner(&mut self) {
        if self.has_fields {
            self.result = self.result.and_then(|_| {
                if self.is_pretty() {
                    self.fmt.write_str("\n}")
                } else {
                    self.fmt.write_str(" }")
                }
            });
        }
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_tuple` method.
#[must_use]
pub struct DebugTuple<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugTuple<'a, 'b> {
    let result = fmt.write_str(name);
    DebugTuple {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
    /// Adds a new field to the generated tuple struct output.
    #[unstable(feature = "core", reason = "method was just created")]
    #[inline]
    pub fn field(mut self, value: &fmt::Debug) -> DebugTuple<'a, 'b> {
        self.field_inner(value);
        self
    }

    fn field_inner(&mut self, value: &fmt::Debug) {
        self.result = self.result.and_then(|_| {
            let (prefix, space) = if self.has_fields {
                (",", " ")
            } else {
                ("(", "")
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, value))
            } else {
                write!(self.fmt, "{}{}{:?}", prefix, space, value)
            }
        });

        self.has_fields = true;
    }

    /// Consumes the `DebugTuple`, finishing output and returning any error
    /// encountered.
    #[unstable(feature = "core", reason = "method was just created")]
    #[inline]
    pub fn finish(mut self) -> fmt::Result {
        self.finish_inner();
        self.result
    }

    fn finish_inner(&mut self) {
        if self.has_fields {
            self.result = self.result.and_then(|_| {
                if self.is_pretty() {
                    self.fmt.write_str("\n)")
                } else {
                    self.fmt.write_str(")")
                }
            });
        }
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_set` method.
#[must_use]
pub struct DebugSet<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugSet<'a, 'b> {
    let result = write!(fmt, "{} {{", name);
    DebugSet {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugSet<'a, 'b> {
    /// Adds a new entry to the set output.
    #[unstable(feature = "core", reason = "method was just created")]
    #[inline]
    pub fn entry(mut self, entry: &fmt::Debug) -> DebugSet<'a, 'b> {
        self.entry_inner(entry);
        self
    }

    fn entry_inner(&mut self, entry: &fmt::Debug) {
        self.result = self.result.and_then(|_| {
            let prefix = if self.has_fields {
                ","
            } else {
                ""
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
            } else {
                write!(self.fmt, "{} {:?}", prefix, entry)
            }
        });

        self.has_fields = true;
    }

    /// Consumes the `DebugSet`, finishing output and returning any error
    /// encountered.
    #[unstable(feature = "core", reason = "method was just created")]
    #[inline]
    pub fn finish(mut self) -> fmt::Result {
        self.finish_inner();
        self.result
    }

    fn finish_inner(&mut self) {
        self.result = self.result.and_then(|_| {
            let end = match (self.has_fields, self.is_pretty()) {
                (false, _) => "}",
                (true, false) => " }",
                (true, true) => "\n}",
            };
            self.fmt.write_str(end)
        });
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_map` method.
#[must_use]
pub struct DebugMap<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugMap<'a, 'b> {
    let result = write!(fmt, "{} {{", name);
    DebugMap {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugMap<'a, 'b> {
    /// Adds a new entry to the map output.
    #[unstable(feature = "core", reason = "method was just created")]
    #[inline]
    pub fn entry(mut self, key: &fmt::Debug, value: &fmt::Debug) -> DebugMap<'a, 'b> {
        self.entry_inner(key, value);
        self
    }

    fn entry_inner(&mut self, key: &fmt::Debug, value: &fmt::Debug) {
        self.result = self.result.and_then(|_| {
            let prefix = if self.has_fields {
                ","
            } else {
                ""
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer, format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
            } else {
                write!(self.fmt, "{} {:?}: {:?}", prefix, key, value)
            }
        });

        self.has_fields = true;
    }

    /// Consumes the `DebugMap`, finishing output and returning any error
    /// encountered.
    #[unstable(feature = "core", reason = "method was just created")]
    #[inline]
    pub fn finish(mut self) -> fmt::Result {
        self.finish_inner();
        self.result
    }

    fn finish_inner(&mut self) {
        self.result = self.result.and_then(|_| {
            let end = match (self.has_fields, self.is_pretty()) {
                (false, _) => "}",
                (true, false) => " }",
                (true, true) => "\n}",
            };
            self.fmt.write_str(end)
        });
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}
<|endoftext|>


<commit_before>// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

use T = inst::T;
use cmp::{Eq, Ord};
use from_str::FromStr;
use num::from_int;

pub const bits : uint = inst::bits;
pub const bytes : uint = (inst::bits / 8);

pub const min_value: T = (-1 as T) << (bits - 1);
pub const max_value: T = min_value - 1 as T;

pub pure fn min(x: T, y: T) -> T { if x < y { x } else { y } }
pub pure fn max(x: T, y: T) -> T { if x > y { x } else { y } }

pub pure fn add(x: T, y: T) -> T { x + y }
pub pure fn sub(x: T, y: T) -> T { x - y }
pub pure fn mul(x: T, y: T) -> T { x * y }
pub pure fn div(x: T, y: T) -> T { x / y }
pub pure fn rem(x: T, y: T) -> T { x % y }

pub pure fn lt(x: T, y: T) -> bool { x < y }
pub pure fn le(x: T, y: T) -> bool { x <= y }
pub pure fn eq(x: T, y: T) -> bool { x == y }
pub pure fn ne(x: T, y: T) -> bool { x != y }
pub pure fn ge(x: T, y: T) -> bool { x >= y }
pub pure fn gt(x: T, y: T) -> bool { x > y }

pub pure fn is_positive(x: T) -> bool { x > 0 as T }
pub pure fn is_negative(x: T) -> bool { x < 0 as T }
pub pure fn is_nonpositive(x: T) -> bool { x <= 0 as T }
pub pure fn is_nonnegative(x: T) -> bool { x >= 0 as T }

#[inline(always)]
/// Iterate over the range [`lo`..`hi`)
pub fn range(lo: T, hi: T, it: fn(T) -> bool) {
    let mut i = lo;
    while i < hi {
        if !it(i) { break }
        i += 1 as T;
    }
}

/// Computes the bitwise complement
pub pure fn compl(i: T) -> T {
    -1 as T ^ i
}

/// Computes the absolute value
// FIXME: abs should return an unsigned int (#2353)
pub pure fn abs(i: T) -> T {
    if is_negative(i) { -i } else { i }
}

impl T : Ord {
    pure fn lt(other: &T) -> bool { return self < (*other); }
    pure fn le(other: &T) -> bool { return self <= (*other); }
    pure fn ge(other: &T) -> bool { return self >= (*other); }
    pure fn gt(other: &T) -> bool { return self > (*other); }
}

impl T : Eq {
    pure fn eq(other: &T) -> bool { return self == (*other); }
    pure fn ne(other: &T) -> bool { return self != (*other); }
}

impl T: num::Num {
    pure fn add(other: &T)    -> T { return self + *other; }
    pure fn sub(other: &T)    -> T { return self - *other; }
    pure fn mul(other: &T)    -> T { return self * *other; }
    pure fn div(other: &T)    -> T { return self / *other; }
    pure fn modulo(other: &T) -> T { return self % *other; }
    pure fn neg()              -> T { return -self;        }

    pure fn to_int()         -> int { return self as int; }
    static pure fn from_int(n: int) -> T   { return n as T;      }
}

impl T: iter::Times {
    #[inline(always)]
    #[doc = "A convenience form for basic iteration. Given a variable `x` \
        of any numeric type, the expression `for x.times { /* anything */ }` \
        will execute the given function exactly x times. If we assume that \
        `x` is an int, this is functionally equivalent to \
        `for int::range(0, x) |_i| { /* anything */ }`."]
    pure fn times(it: fn() -> bool) {
        if self < 0 {
            fail fmt!("The .times method expects a nonnegative number, \
                       but found %?", self);
        }
        let mut i = self;
        while i > 0 {
            if !it() { break }
            i -= 1;
        }
    }
}

impl T: iter::TimesIx {
    #[inline(always)]
    /// Like `times`, but provides an index
    pure fn timesi(it: fn(uint) -> bool) {
        let slf = self as uint;
        if slf < 0u {
            fail fmt!("The .timesi method expects a nonnegative number, \
                       but found %?", self);
        }
        let mut i = 0u;
        while i < slf {
            if !it(i) { break }
            i += 1u;
        }
    }
}

/**
 * Parse a buffer of bytes
 *
 * # Arguments
 *
 * * buf - A byte buffer
 * * radix - The base of the number
 */
pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
    if vec::len(buf) == 0u { return None; }
    let mut i = vec::len(buf) - 1u;
    let mut start = 0u;
    let mut power = 1 as T;

    if buf[0] == ('-' as u8) {
        power = -1 as T;
        start = 1u;
    }
    let mut n = 0 as T;
    loop {
        match char::to_digit(buf[i] as char, radix) {
          Some(d) => n += (d as T) * power,
          None => return None
        }
        power *= radix as T;
        if i <= start { return Some(n); }
        i -= 1u;
    };
}

/// Parse a string to an int
pub fn from_str(s: &str) -> Option<T> { parse_bytes(str::to_bytes(s), 10u) }

impl T : FromStr {
    static fn from_str(s: &str) -> Option<T> { from_str(s) }
}

/// Convert to a string in a given base
pub pure fn to_str(n: T, radix: uint) -> ~str {
    do to_str_bytes(n, radix) |slice| {
        do vec::as_imm_buf(slice) |p, len| {
            unsafe { str::raw::from_buf_len(p, len) }
        }
    }
}

pub pure fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
    if n < 0 as T {
        uint::to_str_bytes(true, -n as uint, radix, f)
    } else {
        uint::to_str_bytes(false, n as uint, radix, f)
    }
}

/// Convert to a string
pub pure fn str(i: T) -> ~str { return to_str(i, 10u); }

// FIXME: Has alignment issues on windows and 32-bit linux (#2609)
#[test]
#[ignore]
fn test_from_str() {
    assert from_str(~"0") == Some(0 as T);
    assert from_str(~"3") == Some(3 as T);
    assert from_str(~"10") == Some(10 as T);
    assert from_str(~"123456789") == Some(123456789 as T);
    assert from_str(~"00100") == Some(100 as T);

    assert from_str(~"-1") == Some(-1 as T);
    assert from_str(~"-3") == Some(-3 as T);
    assert from_str(~"-10") == Some(-10 as T);
    assert from_str(~"-123456789") == Some(-123456789 as T);
    assert from_str(~"-00100") == Some(-100 as T);

    assert from_str(~" ").is_none();
    assert from_str(~"x").is_none();
}

// FIXME: Has alignment issues on windows and 32-bit linux (#2609)
#[test]
#[ignore]
fn test_parse_bytes() {
    use str::to_bytes;
    assert parse_bytes(to_bytes(~"123"), 10u) == Some(123 as T);
    assert parse_bytes(to_bytes(~"1001"), 2u) == Some(9 as T);
    assert parse_bytes(to_bytes(~"123"), 8u) == Some(83 as T);
    assert parse_bytes(to_bytes(~"123"), 16u) == Some(291 as T);
    assert parse_bytes(to_bytes(~"ffff"), 16u) == Some(65535 as T);
    assert parse_bytes(to_bytes(~"FFFF"), 16u) == Some(65535 as T);
    assert parse_bytes(to_bytes(~"z"), 36u) == Some(35 as T);
    assert parse_bytes(to_bytes(~"Z"), 36u) == Some(35 as T);

    assert parse_bytes(to_bytes(~"-123"), 10u) == Some(-123 as T);
    assert parse_bytes(to_bytes(~"-1001"), 2u) == Some(-9 as T);
    assert parse_bytes(to_bytes(~"-123"), 8u) == Some(-83 as T);
    assert parse_bytes(to_bytes(~"-123"), 16u) == Some(-291 as T);
    assert parse_bytes(to_bytes(~"-ffff"), 16u) == Some(-65535 as T);
    assert parse_bytes(to_bytes(~"-FFFF"), 16u) == Some(-65535 as T);
    assert parse_bytes(to_bytes(~"-z"), 36u) == Some(-35 as T);
    assert parse_bytes(to_bytes(~"-Z"), 36u) == Some(-35 as T);

    assert parse_bytes(to_bytes(~"Z"), 35u).is_none();
    assert parse_bytes(to_bytes(~"-9"), 2u).is_none();
}

#[test]
fn test_to_str() {
    assert (to_str(0 as T, 10u) == ~"0");
    assert (to_str(1 as T, 10u) == ~"1");
    assert (to_str(-1 as T, 10u) == ~"-1");
    assert (to_str(127 as T, 16u) == ~"7f");
    assert (to_str(100 as T, 10u) == ~"100");
}

#[test]
fn test_interfaces() {
    fn test<U:num::Num cmp::Eq>(ten: U) {
        assert (ten.to_int() == 10);

        let two: U = from_int(2);
        assert (two.to_int() == 2);

        assert (ten.add(&two) == from_int(12));
        assert (ten.sub(&two) == from_int(8));
        assert (ten.mul(&two) == from_int(20));
        assert (ten.div(&two) == from_int(5));
        assert (ten.modulo(&two) == from_int(0));
        assert (ten.neg() == from_int(-10));
    }

    test(10 as T);
}

#[test]
fn test_times() {
    use iter::Times;
    let ten = 10 as T;
    let mut accum = 0;
    for ten.times { accum += 1; }
    assert (accum == 10);
}

#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn test_times_negative() {
    use iter::Times;
    for (-10).times { log(error, ~"nope!"); }
}
<commit_msg>Remove invalid FIXME<commit_after>// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

use T = inst::T;
use cmp::{Eq, Ord};
use from_str::FromStr;
use num::from_int;

pub const bits : uint = inst::bits;
pub const bytes : uint = (inst::bits / 8);

pub const min_value: T = (-1 as T) << (bits - 1);
pub const max_value: T = min_value - 1 as T;

pub pure fn min(x: T, y: T) -> T { if x < y { x } else { y } }
pub pure fn max(x: T, y: T) -> T { if x > y { x } else { y } }

pub pure fn add(x: T, y: T) -> T { x + y }
pub pure fn sub(x: T, y: T) -> T { x - y }
pub pure fn mul(x: T, y: T) -> T { x * y }
pub pure fn div(x: T, y: T) -> T { x / y }
pub pure fn rem(x: T, y: T) -> T { x % y }

pub pure fn lt(x: T, y: T) -> bool { x < y }
pub pure fn le(x: T, y: T) -> bool { x <= y }
pub pure fn eq(x: T, y: T) -> bool { x == y }
pub pure fn ne(x: T, y: T) -> bool { x != y }
pub pure fn ge(x: T, y: T) -> bool { x >= y }
pub pure fn gt(x: T, y: T) -> bool { x > y }

pub pure fn is_positive(x: T) -> bool { x > 0 as T }
pub pure fn is_negative(x: T) -> bool { x < 0 as T }
pub pure fn is_nonpositive(x: T) -> bool { x <= 0 as T }
pub pure fn is_nonnegative(x: T) -> bool { x >= 0 as T }

#[inline(always)]
/// Iterate over the range [`lo`..`hi`)
pub fn range(lo: T, hi: T, it: fn(T) -> bool) {
    let mut i = lo;
    while i < hi {
        if !it(i) { break }
        i += 1 as T;
    }
}

/// Computes the bitwise complement
pub pure fn compl(i: T) -> T {
    -1 as T ^ i
}

/// Computes the absolute value
pub pure fn abs(i: T) -> T {
    if is_negative(i) { -i } else { i }
}

impl T : Ord {
    pure fn lt(other: &T) -> bool { return self < (*other); }
    pure fn le(other: &T) -> bool { return self <= (*other); }
    pure fn ge(other: &T) -> bool { return self >= (*other); }
    pure fn gt(other: &T) -> bool { return self > (*other); }
}

impl T : Eq {
    pure fn eq(other: &T) -> bool { return self == (*other); }
    pure fn ne(other: &T) -> bool { return self != (*other); }
}

impl T: num::Num {
    pure fn add(other: &T)    -> T { return self + *other; }
    pure fn sub(other: &T)    -> T { return self - *other; }
    pure fn mul(other: &T)    -> T { return self * *other; }
    pure fn div(other: &T)    -> T { return self / *other; }
    pure fn modulo(other: &T) -> T { return self % *other; }
    pure fn neg()              -> T { return -self;        }

    pure fn to_int()         -> int { return self as int; }
    static pure fn from_int(n: int) -> T   { return n as T;      }
}

impl T: iter::Times {
    #[inline(always)]
    #[doc = "A convenience form for basic iteration. Given a variable `x` \
        of any numeric type, the expression `for x.times { /* anything */ }` \
        will execute the given function exactly x times. If we assume that \
        `x` is an int, this is functionally equivalent to \
        `for int::range(0, x) |_i| { /* anything */ }`."]
    pure fn times(it: fn() -> bool) {
        if self < 0 {
            fail fmt!("The .times method expects a nonnegative number, \
                       but found %?", self);
        }
        let mut i = self;
        while i > 0 {
            if !it() { break }
            i -= 1;
        }
    }
}

impl T: iter::TimesIx {
    #[inline(always)]
    /// Like `times`, but provides an index
    pure fn timesi(it: fn(uint) -> bool) {
        let slf = self as uint;
        if slf < 0u {
            fail fmt!("The .timesi method expects a nonnegative number, \
                       but found %?", self);
        }
        let mut i = 0u;
        while i < slf {
            if !it(i) { break }
            i += 1u;
        }
    }
}

/**
 * Parse a buffer of bytes
 *
 * # Arguments
 *
 * * buf - A byte buffer
 * * radix - The base of the number
 */
pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
    if vec::len(buf) == 0u { return None; }
    let mut i = vec::len(buf) - 1u;
    let mut start = 0u;
    let mut power = 1 as T;

    if buf[0] == ('-' as u8) {
        power = -1 as T;
        start = 1u;
    }
    let mut n = 0 as T;
    loop {
        match char::to_digit(buf[i] as char, radix) {
          Some(d) => n += (d as T) * power,
          None => return None
        }
        power *= radix as T;
        if i <= start { return Some(n); }
        i -= 1u;
    };
}

/// Parse a string to an int
pub fn from_str(s: &str) -> Option<T> { parse_bytes(str::to_bytes(s), 10u) }

impl T : FromStr {
    static fn from_str(s: &str) -> Option<T> { from_str(s) }
}

/// Convert to a string in a given base
pub pure fn to_str(n: T, radix: uint) -> ~str {
    do to_str_bytes(n, radix) |slice| {
        do vec::as_imm_buf(slice) |p, len| {
            unsafe { str::raw::from_buf_len(p, len) }
        }
    }
}

pub pure fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
    if n < 0 as T {
        uint::to_str_bytes(true, -n as uint, radix, f)
    } else {
        uint::to_str_bytes(false, n as uint, radix, f)
    }
}

/// Convert to a string
pub pure fn str(i: T) -> ~str { return to_str(i, 10u); }

// FIXME: Has alignment issues on windows and 32-bit linux (#2609)
#[test]
#[ignore]
fn test_from_str() {
    assert from_str(~"0") == Some(0 as T);
    assert from_str(~"3") == Some(3 as T);
    assert from_str(~"10") == Some(10 as T);
    assert from_str(~"123456789") == Some(123456789 as T);
    assert from_str(~"00100") == Some(100 as T);

    assert from_str(~"-1") == Some(-1 as T);
    assert from_str(~"-3") == Some(-3 as T);
    assert from_str(~"-10") == Some(-10 as T);
    assert from_str(~"-123456789") == Some(-123456789 as T);
    assert from_str(~"-00100") == Some(-100 as T);

    assert from_str(~" ").is_none();
    assert from_str(~"x").is_none();
}

// FIXME: Has alignment issues on windows and 32-bit linux (#2609)
#[test]
#[ignore]
fn test_parse_bytes() {
    use str::to_bytes;
    assert parse_bytes(to_bytes(~"123"), 10u) == Some(123 as T);
    assert parse_bytes(to_bytes(~"1001"), 2u) == Some(9 as T);
    assert parse_bytes(to_bytes(~"123"), 8u) == Some(83 as T);
    assert parse_bytes(to_bytes(~"123"), 16u) == Some(291 as T);
    assert parse_bytes(to_bytes(~"ffff"), 16u) == Some(65535 as T);
    assert parse_bytes(to_bytes(~"FFFF"), 16u) == Some(65535 as T);
    assert parse_bytes(to_bytes(~"z"), 36u) == Some(35 as T);
    assert parse_bytes(to_bytes(~"Z"), 36u) == Some(35 as T);

    assert parse_bytes(to_bytes(~"-123"), 10u) == Some(-123 as T);
    assert parse_bytes(to_bytes(~"-1001"), 2u) == Some(-9 as T);
    assert parse_bytes(to_bytes(~"-123"), 8u) == Some(-83 as T);
    assert parse_bytes(to_bytes(~"-123"), 16u) == Some(-291 as T);
    assert parse_bytes(to_bytes(~"-ffff"), 16u) == Some(-65535 as T);
    assert parse_bytes(to_bytes(~"-FFFF"), 16u) == Some(-65535 as T);
    assert parse_bytes(to_bytes(~"-z"), 36u) == Some(-35 as T);
    assert parse_bytes(to_bytes(~"-Z"), 36u) == Some(-35 as T);

    assert parse_bytes(to_bytes(~"Z"), 35u).is_none();
    assert parse_bytes(to_bytes(~"-9"), 2u).is_none();
}

#[test]
fn test_to_str() {
    assert (to_str(0 as T, 10u) == ~"0");
    assert (to_str(1 as T, 10u) == ~"1");
    assert (to_str(-1 as T, 10u) == ~"-1");
    assert (to_str(127 as T, 16u) == ~"7f");
    assert (to_str(100 as T, 10u) == ~"100");
}

#[test]
fn test_interfaces() {
    fn test<U:num::Num cmp::Eq>(ten: U) {
        assert (ten.to_int() == 10);

        let two: U = from_int(2);
        assert (two.to_int() == 2);

        assert (ten.add(&two) == from_int(12));
        assert (ten.sub(&two) == from_int(8));
        assert (ten.mul(&two) == from_int(20));
        assert (ten.div(&two) == from_int(5));
        assert (ten.modulo(&two) == from_int(0));
        assert (ten.neg() == from_int(-10));
    }

    test(10 as T);
}

#[test]
fn test_times() {
    use iter::Times;
    let ten = 10 as T;
    let mut accum = 0;
    for ten.times { accum += 1; }
    assert (accum == 10);
}

#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn test_times_negative() {
    use iter::Times;
    for (-10).times { log(error, ~"nope!"); }
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;
use time::precise_time_ns;

use super::command::{Command, Listener};
use super::storage::Storage;

pub struct Worker {
    storage: Storage,
    receiver: Receiver<Command>,
    listener: Box<Listener>,
    last_checked: Option<u64>,
}

pub fn spawn(storage: Storage,
             receiver: Receiver<Command>,
             listener: Box<Listener>)
             -> thread::JoinHandle<()> {
    thread::spawn(move || {
        let worker = Worker::new(storage, receiver, listener);

        worker.run();
    })
}

impl Worker {
    pub fn new(storage: Storage, receiver: Receiver<Command>, listener: Box<Listener>) -> Worker {
        Worker {
            storage,
            receiver,
            listener,
            last_checked: None,
        }
    }

    pub fn run(mut self) -> thread::JoinHandle<()> {
        self.check_expired();

        loop {
            let incoming = self.receiver.recv_timeout(Duration::from_millis(500));

            self.listener.on_tick();

            if let Err(err) = incoming {
                match err {
                    RecvTimeoutError::Timeout => {}
                    RecvTimeoutError::Disconnected => panic!("channel disconnected"),
                }
            }

            if let Ok(command) = incoming {
                match command {
                    Command::AddEntry(entry) => {
                        self.storage.add_entry(entry);
                    }
                    Command::RemoveEntry(entry) => {
                        self.storage.remove_entry(&entry);
                    }
                }
            }

            if self.needs_checking() {
                self.check_expired();
            }
        }
    }

    fn check_expired(&mut self) {
        self.last_checked = Some(precise_time_ns());

        for entry in self.storage.expired_entries() {
            self.listener.on_expired(entry);
            self.storage.remove_entry(&entry);
        }
    }

    fn needs_checking(&self) -> bool {
        match self.last_checked {
            None => true,
            Some(value) => {
                // TODO: ooh no we have a magic number here
                return (precise_time_ns() - value) >= 1000000000;
            }
        }
    }
}
<commit_msg>Move parts of main worker loop to own functions<commit_after>use std::sync::mpsc::{Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;
use time::precise_time_ns;

use super::command::{Command, Listener};
use super::storage::Storage;

pub struct Worker {
    storage: Storage,
    receiver: Receiver<Command>,
    listener: Box<Listener>,
    last_checked: Option<u64>,
}

pub fn spawn(storage: Storage,
             receiver: Receiver<Command>,
             listener: Box<Listener>)
             -> thread::JoinHandle<()> {
    thread::spawn(move || {
        let worker = Worker::new(storage, receiver, listener);

        worker.run();
    })
}

impl Worker {
    pub fn new(storage: Storage, receiver: Receiver<Command>, listener: Box<Listener>) -> Worker {
        Worker {
            storage,
            receiver,
            listener,
            last_checked: None,
        }
    }

    pub fn run(mut self) -> thread::JoinHandle<()> {
        self.check_expired();

        loop {
            let incoming = self.receiver.recv_timeout(Duration::from_millis(500));

            self.listener.on_tick();

            match incoming {
                Err(err) => self.handle_error(err),
                Ok(command) => self.handle_command(command)
            }

            if self.needs_checking() {
                self.check_expired();
            }
        }
    }

    fn handle_error(&self, err: RecvTimeoutError) {
        match err {
            RecvTimeoutError::Timeout => {}
            RecvTimeoutError::Disconnected => panic!("channel disconnected"),
        }
    }

    fn handle_command(&mut self, command: Command) {
        match command {
            Command::AddEntry(entry) => {
                self.storage.add_entry(entry);
            }
            Command::RemoveEntry(entry) => {
                self.storage.remove_entry(&entry);
            }
        }
    }

    fn check_expired(&mut self) {
        self.last_checked = Some(precise_time_ns());

        for entry in self.storage.expired_entries() {
            self.listener.on_expired(entry);
            self.storage.remove_entry(&entry);
        }
    }

    fn needs_checking(&self) -> bool {
        match self.last_checked {
            None => true,
            Some(value) => {
                // TODO: ooh no we have a magic number here
                return (precise_time_ns() - value) >= 1000000000;
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::mem;
use crate::slice;

pub fn hashmap_random_keys() -> (u64, u64) {
    let mut v = (0, 0);
    unsafe {
        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
                                             mem::size_of_val(&v));
        imp::fill_bytes(view);
    }
    v
}

#[cfg(all(unix,
          not(target_os = "ios"),
          not(target_os = "openbsd"),
          not(target_os = "freebsd"),
          not(target_os = "fuchsia"),
          not(target_os = "redox")))]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        unsafe {
            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { false }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
        use crate::sync::atomic::{AtomicBool, Ordering};
        use crate::sys::os::errno;

        static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
        if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
            return false;
        }

        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::ENOSYS || err == libc::EPERM {
                    // Fall back to reading /dev/urandom if `getrandom` is not
                    // supported on the current kernel.
                    //
                    // Also fall back in case it is disabled by something like
                    // seccomp or inside of virtual machines.
                    GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
                    return false;
                } else if err == libc::EAGAIN {
                    return false;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
        true
    }

    pub fn fill_bytes(v: &mut [u8]) {
        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
        // meaning it would have blocked because the non-blocking pool (urandom)
        // has not initialized in the kernel yet due to a lack of entropy. The
        // fallback we do here is to avoid blocking applications which could
        // depend on this call without ever knowing they do and don't have a
        // work around. The PRNG of /dev/urandom will still be used but over a
        // possibly predictable entropy pool.
        if getrandom_fill_bytes(v) {
            return;
        }

        // getrandom failed because it is permanently or temporarily (because
        // of missing entropy) unavailable. Open /dev/urandom, read from it,
        // and close it again.
        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom")
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use crate::sys::os::errno;

    pub fn fill_bytes(v: &mut [u8]) {
        // getentropy(2) permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let ret = unsafe {
                libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
            };
            if ret == -1 {
                panic!("unexpected getentropy error: {}", errno());
            }
        }
    }
}

// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
// from `/dev/random` and which runs on its own thread accessed via GCD.
// This seems needlessly heavyweight for the purposes of generating two u64s
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
#[cfg(target_os = "ios")]
mod imp {
    use crate::io;
    use crate::ptr;
    use libc::{c_int, size_t};

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    extern {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t,
                              bytes: *mut u8) -> c_int;
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let ret = unsafe {
            SecRandomCopyBytes(kSecRandomDefault,
                               v.len(),
                               v.as_mut_ptr())
        };
        if ret == -1 {
            panic!("couldn't generate random bytes: {}",
                   io::Error::last_os_error());
        }
    }
}

#[cfg(target_os = "freebsd")]
mod imp {
    use crate::ptr;

    pub fn fill_bytes(v: &mut [u8]) {
        let mib = [libc::CTL_KERN, libc::KERN_ARND];
        // kern.arandom permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let mut s_len = s.len();
            let ret = unsafe {
                libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
                             s.as_mut_ptr() as *mut _, &mut s_len,
                             ptr::null(), 0)
            };
            if ret == -1 || s_len != s.len() {
                panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                       ret, s.len(), s_len);
            }
        }
    }
}

#[cfg(target_os = "fuchsia")]
mod imp {
    #[link(name = "zircon")]
    extern {
        fn zx_cprng_draw(buffer: *mut u8, len: usize);
    }

    pub fn fill_bytes(v: &mut [u8]) {
        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
    }
}

#[cfg(target_os = "redox")]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    pub fn fill_bytes(v: &mut [u8]) {
        // Open rand:, read from it, and close it again.
        let mut file = File::open("rand:").expect("failed to open rand:");
        file.read_exact(v).expect("failed to read rand:")
    }
}
<commit_msg>Use KERN_ARND syscall for random numbers on NetBSD, same as FreeBSD.<commit_after>use crate::mem;
use crate::slice;

pub fn hashmap_random_keys() -> (u64, u64) {
    let mut v = (0, 0);
    unsafe {
        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
                                             mem::size_of_val(&v));
        imp::fill_bytes(view);
    }
    v
}

#[cfg(all(unix,
          not(target_os = "ios"),
          not(target_os = "openbsd"),
          not(target_os = "freebsd"),
          not(target_os = "netbsd"),
          not(target_os = "fuchsia"),
          not(target_os = "redox")))]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        unsafe {
            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { false }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
        use crate::sync::atomic::{AtomicBool, Ordering};
        use crate::sys::os::errno;

        static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
        if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
            return false;
        }

        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::ENOSYS || err == libc::EPERM {
                    // Fall back to reading /dev/urandom if `getrandom` is not
                    // supported on the current kernel.
                    //
                    // Also fall back in case it is disabled by something like
                    // seccomp or inside of virtual machines.
                    GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
                    return false;
                } else if err == libc::EAGAIN {
                    return false;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
        true
    }

    pub fn fill_bytes(v: &mut [u8]) {
        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
        // meaning it would have blocked because the non-blocking pool (urandom)
        // has not initialized in the kernel yet due to a lack of entropy. The
        // fallback we do here is to avoid blocking applications which could
        // depend on this call without ever knowing they do and don't have a
        // work around. The PRNG of /dev/urandom will still be used but over a
        // possibly predictable entropy pool.
        if getrandom_fill_bytes(v) {
            return;
        }

        // getrandom failed because it is permanently or temporarily (because
        // of missing entropy) unavailable. Open /dev/urandom, read from it,
        // and close it again.
        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom")
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use crate::sys::os::errno;

    pub fn fill_bytes(v: &mut [u8]) {
        // getentropy(2) permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let ret = unsafe {
                libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
            };
            if ret == -1 {
                panic!("unexpected getentropy error: {}", errno());
            }
        }
    }
}

// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
// from `/dev/random` and which runs on its own thread accessed via GCD.
// This seems needlessly heavyweight for the purposes of generating two u64s
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
#[cfg(target_os = "ios")]
mod imp {
    use crate::io;
    use crate::ptr;
    use libc::{c_int, size_t};

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    extern {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t,
                              bytes: *mut u8) -> c_int;
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let ret = unsafe {
            SecRandomCopyBytes(kSecRandomDefault,
                               v.len(),
                               v.as_mut_ptr())
        };
        if ret == -1 {
            panic!("couldn't generate random bytes: {}",
                   io::Error::last_os_error());
        }
    }
}

#[cfg(target_os = "freebsd", target_os = "netbsd")]
mod imp {
    use crate::ptr;

    pub fn fill_bytes(v: &mut [u8]) {
        let mib = [libc::CTL_KERN, libc::KERN_ARND];
        // kern.arandom permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let mut s_len = s.len();
            let ret = unsafe {
                libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
                             s.as_mut_ptr() as *mut _, &mut s_len,
                             ptr::null(), 0)
            };
            if ret == -1 || s_len != s.len() {
                panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                       ret, s.len(), s_len);
            }
        }
    }
}

#[cfg(target_os = "fuchsia")]
mod imp {
    #[link(name = "zircon")]
    extern {
        fn zx_cprng_draw(buffer: *mut u8, len: usize);
    }

    pub fn fill_bytes(v: &mut [u8]) {
        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
    }
}

#[cfg(target_os = "redox")]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    pub fn fill_bytes(v: &mut [u8]) {
        // Open rand:, read from it, and close it again.
        let mut file = File::open("rand:").expect("failed to open rand:");
        file.read_exact(v).expect("failed to read rand:")
    }
}
<|endoftext|>


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

//! Borders, padding, and margins.

use layout::box_::Box;

use computed = style::computed_values;
use style::computed_values::{LPA_Auto, LPA_Length, LPA_Percentage};
use servo_util::geometry::Au;
use servo_util::geometry;

/// A collapsible margin. See CSS 2.1 § 8.3.1.
pub struct AdjoiningMargins {
    /// The value of the greatest positive margin.
    most_positive: Au,

    /// The actual value (not the absolute value) of the negative margin with the largest absolute
    /// value. Since this is not the absolute value, this is always zero or negative.
    most_negative: Au,
}

impl AdjoiningMargins {
    pub fn new() -> AdjoiningMargins {
        AdjoiningMargins {
            most_positive: Au(0),
            most_negative: Au(0),
        }
    }

    pub fn from_margin(margin_value: Au) -> AdjoiningMargins {
        if margin_value >= Au(0) {
            AdjoiningMargins {
                most_positive: margin_value,
                most_negative: Au(0),
            }
        } else {
            AdjoiningMargins {
                most_positive: Au(0),
                most_negative: margin_value,
            }
        }
    }

    pub fn union(&mut self, other: AdjoiningMargins) {
        self.most_positive = geometry::max(self.most_positive, other.most_positive);
        self.most_negative = geometry::min(self.most_negative, other.most_negative)
    }

    pub fn collapse(&self) -> Au {
        self.most_positive + self.most_negative
    }
}

/// Represents the top and bottom margins of a flow with collapsible margins. See CSS 2.1 § 8.3.1.
pub enum CollapsibleMargins {
    /// Margins may not collapse with this flow.
    NoCollapsibleMargins(Au, Au),

    /// Both the top and bottom margins (specified here in that order) may collapse, but the
    /// margins do not collapse through this flow.
    MarginsCollapse(AdjoiningMargins, AdjoiningMargins),

    /// Margins collapse *through* this flow. This means, essentially, that the flow doesn’t
    /// have any border, padding, or out-of-flow (floating or positioned) content
    MarginsCollapseThrough(AdjoiningMargins),
}

impl CollapsibleMargins {
    pub fn new() -> CollapsibleMargins {
        NoCollapsibleMargins(Au(0), Au(0))
    }
}

enum FinalMarginState {
    MarginsCollapseThroughFinalMarginState,
    BottomMarginCollapsesFinalMarginState,
}

pub struct MarginCollapseInfo {
    state: MarginCollapseState,
    top_margin: AdjoiningMargins,
    margin_in: AdjoiningMargins,
}

impl MarginCollapseInfo {
    /// TODO(#2012, pcwalton): Remove this method once `box_` is not an `Option`.
    pub fn new() -> MarginCollapseInfo {
        MarginCollapseInfo {
            state: AccumulatingCollapsibleTopMargin,
            top_margin: AdjoiningMargins::new(),
            margin_in: AdjoiningMargins::new(),
        }
    }

    pub fn initialize_top_margin(&mut self,
                                 fragment: &Box,
                                 can_collapse_top_margin_with_kids: bool) {
        if !can_collapse_top_margin_with_kids {
            self.state = AccumulatingMarginIn
        }

        self.top_margin = AdjoiningMargins::from_margin(fragment.margin.get().top)
    }

    pub fn finish_and_compute_collapsible_margins(mut self,
                                                  fragment: &Box,
                                                  can_collapse_bottom_margin_with_kids: bool)
                                                  -> (CollapsibleMargins, Au) {
        let state = match self.state {
            AccumulatingCollapsibleTopMargin => {
                match fragment.style().Box.get().height {
                    LPA_Auto | LPA_Length(Au(0)) | LPA_Percentage(0.) => {
                        MarginsCollapseThroughFinalMarginState
                    },
                    _ => {
                        // If the box has an explicitly specified height, margins may not collapse
                        // through it.
                        BottomMarginCollapsesFinalMarginState
                    }
                }
            }
            AccumulatingMarginIn => BottomMarginCollapsesFinalMarginState,
        };

        // Different logic is needed here depending on whether this flow can collapse its bottom
        // margin with its children.
        let bottom_margin = fragment.margin.get().bottom;
        if !can_collapse_bottom_margin_with_kids {
            match state {
                MarginsCollapseThroughFinalMarginState => {
                    let advance = self.top_margin.collapse();
                    self.margin_in.union(AdjoiningMargins::from_margin(bottom_margin));
                    (MarginsCollapse(self.top_margin, self.margin_in), advance)
                }
                BottomMarginCollapsesFinalMarginState => {
                    let advance = self.margin_in.collapse();
                    self.margin_in.union(AdjoiningMargins::from_margin(bottom_margin));
                    (MarginsCollapse(self.top_margin, self.margin_in), advance)
                }
            }
        } else {
            match state {
                MarginsCollapseThroughFinalMarginState => {
                    self.top_margin.union(AdjoiningMargins::from_margin(bottom_margin));
                    (MarginsCollapseThrough(self.top_margin), Au(0))
                }
                BottomMarginCollapsesFinalMarginState => {
                    self.margin_in.union(AdjoiningMargins::from_margin(bottom_margin));
                    (MarginsCollapse(self.top_margin, self.margin_in), Au(0))
                }
            }
        }
    }

    pub fn current_float_ceiling(&mut self) -> Au {
        match self.state {
            AccumulatingCollapsibleTopMargin => self.top_margin.collapse(),
            AccumulatingMarginIn => self.margin_in.collapse(),
        }
    }

    /// Adds the child's potentially collapsible top margin to the current margin state and
    /// advances the Y offset by the appropriate amount to handle that margin. Returns the amount
    /// that should be added to the Y offset during block layout.
    pub fn advance_top_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) -> Au {
        match (self.state, *child_collapsible_margins) {
            (AccumulatingCollapsibleTopMargin, NoCollapsibleMargins(top, _)) => {
                self.state = AccumulatingMarginIn;
                top
            }
            (AccumulatingCollapsibleTopMargin, MarginsCollapse(top, _)) => {
                self.top_margin.union(top);
                self.state = AccumulatingMarginIn;
                Au(0)
            }
            (AccumulatingMarginIn, NoCollapsibleMargins(top, _)) => {
                let previous_margin_value = self.margin_in.collapse();
                self.margin_in = AdjoiningMargins::new();
                previous_margin_value + top
            }
            (AccumulatingMarginIn, MarginsCollapse(top, _)) => {
                self.margin_in.union(top);
                let margin_value = self.margin_in.collapse();
                self.margin_in = AdjoiningMargins::new();
                margin_value
            }
            (_, MarginsCollapseThrough(_)) => {
                // For now, we ignore this; this will be handled by `advance_bottom_margin` below.
                Au(0)
            }
        }
    }

    /// Adds the child's potentially collapsible bottom margin to the current margin state and
    /// advances the Y offset by the appropriate amount to handle that margin. Returns the amount
    /// that should be added to the Y offset during block layout.
    pub fn advance_bottom_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) -> Au {
        match (self.state, *child_collapsible_margins) {
            (AccumulatingCollapsibleTopMargin, NoCollapsibleMargins(..)) |
            (AccumulatingCollapsibleTopMargin, MarginsCollapse(..)) => {
                // Can't happen because the state will have been replaced with
                // `AccumulatingMarginIn` above.
                fail!("should not be accumulating collapsible top margins anymore!")
            }
            (AccumulatingCollapsibleTopMargin, MarginsCollapseThrough(margin)) => {
                self.top_margin.union(margin);
                Au(0)
            }
            (AccumulatingMarginIn, NoCollapsibleMargins(_, bottom)) => {
                assert_eq!(self.margin_in.most_positive, Au(0));
                assert_eq!(self.margin_in.most_negative, Au(0));
                bottom
            }
            (AccumulatingMarginIn, MarginsCollapse(_, bottom)) |
            (AccumulatingMarginIn, MarginsCollapseThrough(bottom)) => {
                self.margin_in.union(bottom);
                Au(0)
            }
        }
    }
}

enum MarginCollapseState {
    AccumulatingCollapsibleTopMargin,
    AccumulatingMarginIn,
}

/// Intrinsic widths, which consist of minimum and preferred.
pub struct IntrinsicWidths {
    /// The *minimum width* of the content.
    minimum_width: Au,
    /// The *preferred width* of the content.
    preferred_width: Au,
    /// The estimated sum of borders, padding, and margins. Some calculations use this information
    /// when computing intrinsic widths.
    surround_width: Au,
}

impl IntrinsicWidths {
    pub fn new() -> IntrinsicWidths {
        IntrinsicWidths {
            minimum_width: Au(0),
            preferred_width: Au(0),
            surround_width: Au(0),
        }
    }

    pub fn total_minimum_width(&self) -> Au {
        self.minimum_width + self.surround_width
    }

    pub fn total_preferred_width(&self) -> Au {
        self.preferred_width + self.surround_width
    }
}

/// Useful helper data type when computing values for blocks and positioned elements.
pub enum MaybeAuto {
    Auto,
    Specified(Au),
}

impl MaybeAuto {
    #[inline]
    pub fn from_style(length: computed::LengthOrPercentageOrAuto, containing_length: Au)
                      -> MaybeAuto {
        match length {
            computed::LPA_Auto => Auto,
            computed::LPA_Percentage(percent) => Specified(containing_length.scale_by(percent)),
            computed::LPA_Length(length) => Specified(length)
        }
    }

    #[inline]
    pub fn specified_or_default(&self, default: Au) -> Au {
        match *self {
            Auto => default,
            Specified(value) => value,
        }
    }

    #[inline]
    pub fn specified_or_zero(&self) -> Au {
        self.specified_or_default(Au::new(0))
    }
}

pub fn specified_or_none(length: computed::LengthOrPercentageOrNone, containing_length: Au) -> Option<Au> {
    match length {
        computed::LPN_None => None,
        computed::LPN_Percentage(percent) => Some(containing_length.scale_by(percent)),
        computed::LPN_Length(length) => Some(length),
    }
}

pub fn specified(length: computed::LengthOrPercentage, containing_length: Au) -> Au {
    match length {
        computed::LP_Length(length) => length,
        computed::LP_Percentage(p) => containing_length.scale_by(p)
    }
}
<commit_msg>auto merge of #2038 : SimonSapin/servo/min-height-collapse, r=pcwalton<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Borders, padding, and margins.

use layout::box_::Box;

use computed = style::computed_values;
use style::computed_values::{LPA_Auto, LPA_Length, LPA_Percentage, LP_Length, LP_Percentage};
use servo_util::geometry::Au;
use servo_util::geometry;

/// A collapsible margin. See CSS 2.1 § 8.3.1.
pub struct AdjoiningMargins {
    /// The value of the greatest positive margin.
    most_positive: Au,

    /// The actual value (not the absolute value) of the negative margin with the largest absolute
    /// value. Since this is not the absolute value, this is always zero or negative.
    most_negative: Au,
}

impl AdjoiningMargins {
    pub fn new() -> AdjoiningMargins {
        AdjoiningMargins {
            most_positive: Au(0),
            most_negative: Au(0),
        }
    }

    pub fn from_margin(margin_value: Au) -> AdjoiningMargins {
        if margin_value >= Au(0) {
            AdjoiningMargins {
                most_positive: margin_value,
                most_negative: Au(0),
            }
        } else {
            AdjoiningMargins {
                most_positive: Au(0),
                most_negative: margin_value,
            }
        }
    }

    pub fn union(&mut self, other: AdjoiningMargins) {
        self.most_positive = geometry::max(self.most_positive, other.most_positive);
        self.most_negative = geometry::min(self.most_negative, other.most_negative)
    }

    pub fn collapse(&self) -> Au {
        self.most_positive + self.most_negative
    }
}

/// Represents the top and bottom margins of a flow with collapsible margins. See CSS 2.1 § 8.3.1.
pub enum CollapsibleMargins {
    /// Margins may not collapse with this flow.
    NoCollapsibleMargins(Au, Au),

    /// Both the top and bottom margins (specified here in that order) may collapse, but the
    /// margins do not collapse through this flow.
    MarginsCollapse(AdjoiningMargins, AdjoiningMargins),

    /// Margins collapse *through* this flow. This means, essentially, that the flow doesn’t
    /// have any border, padding, or out-of-flow (floating or positioned) content
    MarginsCollapseThrough(AdjoiningMargins),
}

impl CollapsibleMargins {
    pub fn new() -> CollapsibleMargins {
        NoCollapsibleMargins(Au(0), Au(0))
    }
}

enum FinalMarginState {
    MarginsCollapseThroughFinalMarginState,
    BottomMarginCollapsesFinalMarginState,
}

pub struct MarginCollapseInfo {
    state: MarginCollapseState,
    top_margin: AdjoiningMargins,
    margin_in: AdjoiningMargins,
}

impl MarginCollapseInfo {
    /// TODO(#2012, pcwalton): Remove this method once `box_` is not an `Option`.
    pub fn new() -> MarginCollapseInfo {
        MarginCollapseInfo {
            state: AccumulatingCollapsibleTopMargin,
            top_margin: AdjoiningMargins::new(),
            margin_in: AdjoiningMargins::new(),
        }
    }

    pub fn initialize_top_margin(&mut self,
                                 fragment: &Box,
                                 can_collapse_top_margin_with_kids: bool) {
        if !can_collapse_top_margin_with_kids {
            self.state = AccumulatingMarginIn
        }

        self.top_margin = AdjoiningMargins::from_margin(fragment.margin.get().top)
    }

    pub fn finish_and_compute_collapsible_margins(mut self,
                                                  fragment: &Box,
                                                  can_collapse_bottom_margin_with_kids: bool)
                                                  -> (CollapsibleMargins, Au) {
        let state = match self.state {
            AccumulatingCollapsibleTopMargin => {
                match fragment.style().Box.get().height {
                    LPA_Auto | LPA_Length(Au(0)) | LPA_Percentage(0.) => {
                        match fragment.style().Box.get().min_height {
                            LP_Length(Au(0)) | LP_Percentage(0.) => {
                                MarginsCollapseThroughFinalMarginState
                            },
                            _ => {
                                // If the box has non-zero min-height, margins may not collapse
                                // through it.
                                BottomMarginCollapsesFinalMarginState
                            }
                        }
                    },
                    _ => {
                        // If the box has an explicitly specified height, margins may not collapse
                        // through it.
                        BottomMarginCollapsesFinalMarginState
                    }
                }
            }
            AccumulatingMarginIn => BottomMarginCollapsesFinalMarginState,
        };

        // Different logic is needed here depending on whether this flow can collapse its bottom
        // margin with its children.
        let bottom_margin = fragment.margin.get().bottom;
        if !can_collapse_bottom_margin_with_kids {
            match state {
                MarginsCollapseThroughFinalMarginState => {
                    let advance = self.top_margin.collapse();
                    self.margin_in.union(AdjoiningMargins::from_margin(bottom_margin));
                    (MarginsCollapse(self.top_margin, self.margin_in), advance)
                }
                BottomMarginCollapsesFinalMarginState => {
                    let advance = self.margin_in.collapse();
                    self.margin_in.union(AdjoiningMargins::from_margin(bottom_margin));
                    (MarginsCollapse(self.top_margin, self.margin_in), advance)
                }
            }
        } else {
            match state {
                MarginsCollapseThroughFinalMarginState => {
                    self.top_margin.union(AdjoiningMargins::from_margin(bottom_margin));
                    (MarginsCollapseThrough(self.top_margin), Au(0))
                }
                BottomMarginCollapsesFinalMarginState => {
                    self.margin_in.union(AdjoiningMargins::from_margin(bottom_margin));
                    (MarginsCollapse(self.top_margin, self.margin_in), Au(0))
                }
            }
        }
    }

    pub fn current_float_ceiling(&mut self) -> Au {
        match self.state {
            AccumulatingCollapsibleTopMargin => self.top_margin.collapse(),
            AccumulatingMarginIn => self.margin_in.collapse(),
        }
    }

    /// Adds the child's potentially collapsible top margin to the current margin state and
    /// advances the Y offset by the appropriate amount to handle that margin. Returns the amount
    /// that should be added to the Y offset during block layout.
    pub fn advance_top_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) -> Au {
        match (self.state, *child_collapsible_margins) {
            (AccumulatingCollapsibleTopMargin, NoCollapsibleMargins(top, _)) => {
                self.state = AccumulatingMarginIn;
                top
            }
            (AccumulatingCollapsibleTopMargin, MarginsCollapse(top, _)) => {
                self.top_margin.union(top);
                self.state = AccumulatingMarginIn;
                Au(0)
            }
            (AccumulatingMarginIn, NoCollapsibleMargins(top, _)) => {
                let previous_margin_value = self.margin_in.collapse();
                self.margin_in = AdjoiningMargins::new();
                previous_margin_value + top
            }
            (AccumulatingMarginIn, MarginsCollapse(top, _)) => {
                self.margin_in.union(top);
                let margin_value = self.margin_in.collapse();
                self.margin_in = AdjoiningMargins::new();
                margin_value
            }
            (_, MarginsCollapseThrough(_)) => {
                // For now, we ignore this; this will be handled by `advance_bottom_margin` below.
                Au(0)
            }
        }
    }

    /// Adds the child's potentially collapsible bottom margin to the current margin state and
    /// advances the Y offset by the appropriate amount to handle that margin. Returns the amount
    /// that should be added to the Y offset during block layout.
    pub fn advance_bottom_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) -> Au {
        match (self.state, *child_collapsible_margins) {
            (AccumulatingCollapsibleTopMargin, NoCollapsibleMargins(..)) |
            (AccumulatingCollapsibleTopMargin, MarginsCollapse(..)) => {
                // Can't happen because the state will have been replaced with
                // `AccumulatingMarginIn` above.
                fail!("should not be accumulating collapsible top margins anymore!")
            }
            (AccumulatingCollapsibleTopMargin, MarginsCollapseThrough(margin)) => {
                self.top_margin.union(margin);
                Au(0)
            }
            (AccumulatingMarginIn, NoCollapsibleMargins(_, bottom)) => {
                assert_eq!(self.margin_in.most_positive, Au(0));
                assert_eq!(self.margin_in.most_negative, Au(0));
                bottom
            }
            (AccumulatingMarginIn, MarginsCollapse(_, bottom)) |
            (AccumulatingMarginIn, MarginsCollapseThrough(bottom)) => {
                self.margin_in.union(bottom);
                Au(0)
            }
        }
    }
}

enum MarginCollapseState {
    AccumulatingCollapsibleTopMargin,
    AccumulatingMarginIn,
}

/// Intrinsic widths, which consist of minimum and preferred.
pub struct IntrinsicWidths {
    /// The *minimum width* of the content.
    minimum_width: Au,
    /// The *preferred width* of the content.
    preferred_width: Au,
    /// The estimated sum of borders, padding, and margins. Some calculations use this information
    /// when computing intrinsic widths.
    surround_width: Au,
}

impl IntrinsicWidths {
    pub fn new() -> IntrinsicWidths {
        IntrinsicWidths {
            minimum_width: Au(0),
            preferred_width: Au(0),
            surround_width: Au(0),
        }
    }

    pub fn total_minimum_width(&self) -> Au {
        self.minimum_width + self.surround_width
    }

    pub fn total_preferred_width(&self) -> Au {
        self.preferred_width + self.surround_width
    }
}

/// Useful helper data type when computing values for blocks and positioned elements.
pub enum MaybeAuto {
    Auto,
    Specified(Au),
}

impl MaybeAuto {
    #[inline]
    pub fn from_style(length: computed::LengthOrPercentageOrAuto, containing_length: Au)
                      -> MaybeAuto {
        match length {
            computed::LPA_Auto => Auto,
            computed::LPA_Percentage(percent) => Specified(containing_length.scale_by(percent)),
            computed::LPA_Length(length) => Specified(length)
        }
    }

    #[inline]
    pub fn specified_or_default(&self, default: Au) -> Au {
        match *self {
            Auto => default,
            Specified(value) => value,
        }
    }

    #[inline]
    pub fn specified_or_zero(&self) -> Au {
        self.specified_or_default(Au::new(0))
    }
}

pub fn specified_or_none(length: computed::LengthOrPercentageOrNone, containing_length: Au) -> Option<Au> {
    match length {
        computed::LPN_None => None,
        computed::LPN_Percentage(percent) => Some(containing_length.scale_by(percent)),
        computed::LPN_Length(length) => Some(length),
    }
}

pub fn specified(length: computed::LengthOrPercentage, containing_length: Au) -> Au {
    match length {
        computed::LP_Length(length) => length,
        computed::LP_Percentage(p) => containing_length.scale_by(p)
    }
}
<|endoftext|>