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

#![sanitizer_runtime]
#![feature(alloc_system)]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
#![no_std]
#![unstable(feature = "sanitizer_runtime_lib",
            reason = "internal implementation detail of sanitizers",
            issue = "0")]

extern crate alloc_system;

use alloc_system::System;

#[global_allocator]
static ALLOC: System = System;
<commit_msg>[nll] librustc_lsan: enable feature(nll) for bootstrap<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![sanitizer_runtime]
#![feature(alloc_system)]
#![cfg_attr(not(stage0), feature(nll))]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
#![no_std]
#![unstable(feature = "sanitizer_runtime_lib",
            reason = "internal implementation detail of sanitizers",
            issue = "0")]

extern crate alloc_system;

use alloc_system::System;

#[global_allocator]
static ALLOC: System = System;
<|endoftext|>


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

//! A private parser implementation of IPv4, IPv6, and socket addresses.
//!
//! This module is "publicly exported" through the `FromStr` implementations
//! below.

use prelude::v1::*;

use error::Error;
use fmt;
use net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use str::FromStr;

struct Parser<'a> {
    // parsing as ASCII, so can use byte array
    s: &'a [u8],
    pos: usize,
}

impl<'a> Parser<'a> {
    fn new(s: &'a str) -> Parser<'a> {
        Parser {
            s: s.as_bytes(),
            pos: 0,
        }
    }

    fn is_eof(&self) -> bool {
        self.pos == self.s.len()
    }

    // Commit only if parser returns Some
    fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where
        F: FnOnce(&mut Parser) -> Option<T>,
    {
        let pos = self.pos;
        let r = cb(self);
        if r.is_none() {
            self.pos = pos;
        }
        r
    }

    // Commit only if parser read till EOF
    fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where
        F: FnOnce(&mut Parser) -> Option<T>,
    {
        self.read_atomically(move |p| {
            match cb(p) {
                Some(x) => if p.is_eof() {Some(x)} else {None},
                None => None,
            }
        })
    }

    // Return result of first successful parser
    fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T> + 'static>])
               -> Option<T> {
        for pf in parsers {
            match self.read_atomically(|p: &mut Parser| pf(p)) {
                Some(r) => return Some(r),
                None => {}
            }
        }
        None
    }

    // Apply 3 parsers sequentially
    fn read_seq_3<A, B, C, PA, PB, PC>(&mut self,
                                       pa: PA,
                                       pb: PB,
                                       pc: PC)
                                       -> Option<(A, B, C)> where
        PA: FnOnce(&mut Parser) -> Option<A>,
        PB: FnOnce(&mut Parser) -> Option<B>,
        PC: FnOnce(&mut Parser) -> Option<C>,
    {
        self.read_atomically(move |p| {
            let a = pa(p);
            let b = if a.is_some() { pb(p) } else { None };
            let c = if b.is_some() { pc(p) } else { None };
            match (a, b, c) {
                (Some(a), Some(b), Some(c)) => Some((a, b, c)),
                _ => None
            }
        })
    }

    // Read next char
    fn read_char(&mut self) -> Option<char> {
        if self.is_eof() {
            None
        } else {
            let r = self.s[self.pos] as char;
            self.pos += 1;
            Some(r)
        }
    }

    // Return char and advance iff next char is equal to requested
    fn read_given_char(&mut self, c: char) -> Option<char> {
        self.read_atomically(|p| {
            match p.read_char() {
                Some(next) if next == c => Some(next),
                _ => None,
            }
        })
    }

    // Read digit
    fn read_digit(&mut self, radix: u8) -> Option<u8> {
        fn parse_digit(c: char, radix: u8) -> Option<u8> {
            let c = c as u8;
            // assuming radix is either 10 or 16
            if c >= b'0' && c <= b'9' {
                Some(c - b'0')
            } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) {
                Some(c - b'a' + 10)
            } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) {
                Some(c - b'A' + 10)
            } else {
                None
            }
        }

        self.read_atomically(|p| {
            p.read_char().and_then(|c| parse_digit(c, radix))
        })
    }

    fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
        let mut r = 0;
        let mut digit_count = 0;
        loop {
            match self.read_digit(radix) {
                Some(d) => {
                    r = r * (radix as u32) + (d as u32);
                    digit_count += 1;
                    if digit_count > max_digits || r >= upto {
                        return None
                    }
                }
                None => {
                    if digit_count == 0 {
                        return None
                    } else {
                        return Some(r)
                    }
                }
            };
        }
    }

    // Read number, failing if max_digits of number value exceeded
    fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
        self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto))
    }

    fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> {
        let mut bs = [0; 4];
        let mut i = 0;
        while i < 4 {
            if i != 0 && self.read_given_char('.').is_none() {
                return None;
            }

            let octet = self.read_number(10, 3, 0x100).map(|n| n as u8);
            match octet {
                Some(d) => bs[i] = d,
                None => return None,
            };
            i += 1;
        }
        Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3]))
    }

    // Read IPv4 address
    fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
        self.read_atomically(|p| p.read_ipv4_addr_impl())
    }

    fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> {
        fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr {
            assert!(head.len() + tail.len() <= 8);
            let mut gs = [0; 8];
            gs.clone_from_slice(head);
            gs[(8 - tail.len()) .. 8].clone_from_slice(tail);
            Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
        }

        fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize)
                       -> (usize, bool) {
            let mut i = 0;
            while i < limit {
                if i < limit - 1 {
                    let ipv4 = p.read_atomically(|p| {
                        if i == 0 || p.read_given_char(':').is_some() {
                            p.read_ipv4_addr()
                        } else {
                            None
                        }
                    });
                    if let Some(v4_addr) = ipv4 {
                        let octets = v4_addr.octets();
                        groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
                        groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
                        return (i + 2, true);
                    }
                }

                let group = p.read_atomically(|p| {
                    if i == 0 || p.read_given_char(':').is_some() {
                        p.read_number(16, 4, 0x10000).map(|n| n as u16)
                    } else {
                        None
                    }
                });
                match group {
                    Some(g) => groups[i] = g,
                    None => return (i, false)
                }
                i += 1;
            }
            (i, false)
        }

        let mut head = [0; 8];
        let (head_size, head_ipv4) = read_groups(self, &mut head, 8);

        if head_size == 8 {
            return Some(Ipv6Addr::new(
                head[0], head[1], head[2], head[3],
                head[4], head[5], head[6], head[7]))
        }

        // IPv4 part is not allowed before `::`
        if head_ipv4 {
            return None
        }

        // read `::` if previous code parsed less than 8 groups
        if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
            return None;
        }

        let mut tail = [0; 8];
        let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size);
        Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
    }

    fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
        self.read_atomically(|p| p.read_ipv6_addr_impl())
    }

    fn read_ip_addr(&mut self) -> Option<IpAddr> {
        let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr().map(|v4| IpAddr::V4(v4));
        let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(|v6| IpAddr::V6(v6));
        self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
    }

    fn read_socket_addr(&mut self) -> Option<SocketAddr> {
        let ip_addr = |p: &mut Parser| {
            let ipv4_p = |p: &mut Parser| p.read_ip_addr();
            let ipv6_p = |p: &mut Parser| {
                let open_br = |p: &mut Parser| p.read_given_char('[');
                let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
                let clos_br = |p: &mut Parser| p.read_given_char(']');
                p.read_seq_3::<char, Ipv6Addr, char, _, _, _>(open_br, ip_addr, clos_br)
                        .map(|t| match t { (_, ip, _) => IpAddr::V6(ip) })
            };
            p.read_or(&mut [Box::new(ipv4_p), Box::new(ipv6_p)])
        };
        let colon = |p: &mut Parser| p.read_given_char(':');
        let port  = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);

        // host, colon, port
        self.read_seq_3(ip_addr, colon, port).map(|t| {
            let (ip, _, port): (IpAddr, char, u16) = t;
            match ip {
                IpAddr::V4(ip) => SocketAddr::V4(SocketAddrV4::new(ip, port)),
                IpAddr::V6(ip) => SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)),
            }
        })
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for IpAddr {
    type Err = AddrParseError;
    fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
        match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
            Some(s) => Ok(s),
            None => Err(AddrParseError(()))
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for Ipv4Addr {
    type Err = AddrParseError;
    fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
        match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) {
            Some(s) => Ok(s),
            None => Err(AddrParseError(()))
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for Ipv6Addr {
    type Err = AddrParseError;
    fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
        match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) {
            Some(s) => Ok(s),
            None => Err(AddrParseError(()))
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for SocketAddr {
    type Err = AddrParseError;
    fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
        match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) {
            Some(s) => Ok(s),
            None => Err(AddrParseError(())),
        }
    }
}

/// An error returned when parsing an IP address or a socket address.
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug, Clone, PartialEq)]
pub struct AddrParseError(());

impl fmt::Display for AddrParseError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for AddrParseError {
    fn description(&self) -> &str {
        "invalid IP address syntax"
    }
}
<commit_msg>Add stability markers for new impls<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A private parser implementation of IPv4, IPv6, and socket addresses.
//!
//! This module is "publicly exported" through the `FromStr` implementations
//! below.

use prelude::v1::*;

use error::Error;
use fmt;
use net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use str::FromStr;

struct Parser<'a> {
    // parsing as ASCII, so can use byte array
    s: &'a [u8],
    pos: usize,
}

impl<'a> Parser<'a> {
    fn new(s: &'a str) -> Parser<'a> {
        Parser {
            s: s.as_bytes(),
            pos: 0,
        }
    }

    fn is_eof(&self) -> bool {
        self.pos == self.s.len()
    }

    // Commit only if parser returns Some
    fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where
        F: FnOnce(&mut Parser) -> Option<T>,
    {
        let pos = self.pos;
        let r = cb(self);
        if r.is_none() {
            self.pos = pos;
        }
        r
    }

    // Commit only if parser read till EOF
    fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where
        F: FnOnce(&mut Parser) -> Option<T>,
    {
        self.read_atomically(move |p| {
            match cb(p) {
                Some(x) => if p.is_eof() {Some(x)} else {None},
                None => None,
            }
        })
    }

    // Return result of first successful parser
    fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T> + 'static>])
               -> Option<T> {
        for pf in parsers {
            match self.read_atomically(|p: &mut Parser| pf(p)) {
                Some(r) => return Some(r),
                None => {}
            }
        }
        None
    }

    // Apply 3 parsers sequentially
    fn read_seq_3<A, B, C, PA, PB, PC>(&mut self,
                                       pa: PA,
                                       pb: PB,
                                       pc: PC)
                                       -> Option<(A, B, C)> where
        PA: FnOnce(&mut Parser) -> Option<A>,
        PB: FnOnce(&mut Parser) -> Option<B>,
        PC: FnOnce(&mut Parser) -> Option<C>,
    {
        self.read_atomically(move |p| {
            let a = pa(p);
            let b = if a.is_some() { pb(p) } else { None };
            let c = if b.is_some() { pc(p) } else { None };
            match (a, b, c) {
                (Some(a), Some(b), Some(c)) => Some((a, b, c)),
                _ => None
            }
        })
    }

    // Read next char
    fn read_char(&mut self) -> Option<char> {
        if self.is_eof() {
            None
        } else {
            let r = self.s[self.pos] as char;
            self.pos += 1;
            Some(r)
        }
    }

    // Return char and advance iff next char is equal to requested
    fn read_given_char(&mut self, c: char) -> Option<char> {
        self.read_atomically(|p| {
            match p.read_char() {
                Some(next) if next == c => Some(next),
                _ => None,
            }
        })
    }

    // Read digit
    fn read_digit(&mut self, radix: u8) -> Option<u8> {
        fn parse_digit(c: char, radix: u8) -> Option<u8> {
            let c = c as u8;
            // assuming radix is either 10 or 16
            if c >= b'0' && c <= b'9' {
                Some(c - b'0')
            } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) {
                Some(c - b'a' + 10)
            } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) {
                Some(c - b'A' + 10)
            } else {
                None
            }
        }

        self.read_atomically(|p| {
            p.read_char().and_then(|c| parse_digit(c, radix))
        })
    }

    fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
        let mut r = 0;
        let mut digit_count = 0;
        loop {
            match self.read_digit(radix) {
                Some(d) => {
                    r = r * (radix as u32) + (d as u32);
                    digit_count += 1;
                    if digit_count > max_digits || r >= upto {
                        return None
                    }
                }
                None => {
                    if digit_count == 0 {
                        return None
                    } else {
                        return Some(r)
                    }
                }
            };
        }
    }

    // Read number, failing if max_digits of number value exceeded
    fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
        self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto))
    }

    fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> {
        let mut bs = [0; 4];
        let mut i = 0;
        while i < 4 {
            if i != 0 && self.read_given_char('.').is_none() {
                return None;
            }

            let octet = self.read_number(10, 3, 0x100).map(|n| n as u8);
            match octet {
                Some(d) => bs[i] = d,
                None => return None,
            };
            i += 1;
        }
        Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3]))
    }

    // Read IPv4 address
    fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
        self.read_atomically(|p| p.read_ipv4_addr_impl())
    }

    fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> {
        fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr {
            assert!(head.len() + tail.len() <= 8);
            let mut gs = [0; 8];
            gs.clone_from_slice(head);
            gs[(8 - tail.len()) .. 8].clone_from_slice(tail);
            Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
        }

        fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize)
                       -> (usize, bool) {
            let mut i = 0;
            while i < limit {
                if i < limit - 1 {
                    let ipv4 = p.read_atomically(|p| {
                        if i == 0 || p.read_given_char(':').is_some() {
                            p.read_ipv4_addr()
                        } else {
                            None
                        }
                    });
                    if let Some(v4_addr) = ipv4 {
                        let octets = v4_addr.octets();
                        groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
                        groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
                        return (i + 2, true);
                    }
                }

                let group = p.read_atomically(|p| {
                    if i == 0 || p.read_given_char(':').is_some() {
                        p.read_number(16, 4, 0x10000).map(|n| n as u16)
                    } else {
                        None
                    }
                });
                match group {
                    Some(g) => groups[i] = g,
                    None => return (i, false)
                }
                i += 1;
            }
            (i, false)
        }

        let mut head = [0; 8];
        let (head_size, head_ipv4) = read_groups(self, &mut head, 8);

        if head_size == 8 {
            return Some(Ipv6Addr::new(
                head[0], head[1], head[2], head[3],
                head[4], head[5], head[6], head[7]))
        }

        // IPv4 part is not allowed before `::`
        if head_ipv4 {
            return None
        }

        // read `::` if previous code parsed less than 8 groups
        if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
            return None;
        }

        let mut tail = [0; 8];
        let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size);
        Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
    }

    fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
        self.read_atomically(|p| p.read_ipv6_addr_impl())
    }

    fn read_ip_addr(&mut self) -> Option<IpAddr> {
        let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr().map(|v4| IpAddr::V4(v4));
        let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(|v6| IpAddr::V6(v6));
        self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
    }

    fn read_socket_addr(&mut self) -> Option<SocketAddr> {
        let ip_addr = |p: &mut Parser| {
            let ipv4_p = |p: &mut Parser| p.read_ip_addr();
            let ipv6_p = |p: &mut Parser| {
                let open_br = |p: &mut Parser| p.read_given_char('[');
                let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
                let clos_br = |p: &mut Parser| p.read_given_char(']');
                p.read_seq_3::<char, Ipv6Addr, char, _, _, _>(open_br, ip_addr, clos_br)
                        .map(|t| match t { (_, ip, _) => IpAddr::V6(ip) })
            };
            p.read_or(&mut [Box::new(ipv4_p), Box::new(ipv6_p)])
        };
        let colon = |p: &mut Parser| p.read_given_char(':');
        let port  = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);

        // host, colon, port
        self.read_seq_3(ip_addr, colon, port).map(|t| {
            let (ip, _, port): (IpAddr, char, u16) = t;
            match ip {
                IpAddr::V4(ip) => SocketAddr::V4(SocketAddrV4::new(ip, port)),
                IpAddr::V6(ip) => SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)),
            }
        })
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for IpAddr {
    type Err = AddrParseError;
    fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
        match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
            Some(s) => Ok(s),
            None => Err(AddrParseError(()))
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for Ipv4Addr {
    type Err = AddrParseError;
    fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
        match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) {
            Some(s) => Ok(s),
            None => Err(AddrParseError(()))
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for Ipv6Addr {
    type Err = AddrParseError;
    fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
        match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) {
            Some(s) => Ok(s),
            None => Err(AddrParseError(()))
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for SocketAddr {
    type Err = AddrParseError;
    fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
        match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) {
            Some(s) => Ok(s),
            None => Err(AddrParseError(())),
        }
    }
}

/// An error returned when parsing an IP address or a socket address.
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug, Clone, PartialEq)]
pub struct AddrParseError(());

#[stable(feature = "addr_parse_error_error", since = "1.4.0")]
impl fmt::Display for AddrParseError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

#[stable(feature = "addr_parse_error_error", since = "1.4.0")]
impl Error for AddrParseError {
    fn description(&self) -> &str {
        "invalid IP address syntax"
    }
}
<|endoftext|>


<commit_before>//! Parser for an Accept-Language HTTP header.

use language_tags::{LanguageTag, ParseError};

use std::str::FromStr;

#[derive(Debug, PartialEq)]
struct Weight(Option<f32>);

impl Weight {
    fn numeric(&self) -> f32 {
        self.0.unwrap_or(1.0)
    }
}

#[derive(Debug, PartialEq)]
struct Item {
    tag: LanguageTag,
    weight: Weight,
}

/// Stores a parsed version of an HTTP Accept-Language header.
///
/// https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.5
#[derive(Debug, PartialEq)]
pub struct AcceptLanguage(Box<[Item]>);

/// Errors when parsing an `AcceptLanguage`.
#[derive(Debug, PartialEq)]
pub enum Error {
    NoElements,
    InvalidCharacters,
    InvalidLanguageTag(ParseError),
    InvalidWeight,
}

/// Optional whitespace, Space or Tab, per https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.3
const OWS: [char; 2] = ['\x20', '\x09'];

impl AcceptLanguage {
    pub fn parse(s: &str) -> Result<AcceptLanguage, Error> {
        if !s.is_ascii() {
            return Err(Error::InvalidCharacters);
        }

        let mut items = Vec::new();

        for val in s.split(',') {
            let trimmed = val.trim_matches(&OWS[..]);
            if trimmed.len() == 0 {
                continue;
            }

            items.push(Item::parse(trimmed)?);
        }

        if items.len() == 0 {
            Err(Error::NoElements)
        } else {
            Ok(AcceptLanguage(items.into_boxed_slice()))
        }
    }

    pub fn iter(&self) -> impl Iterator<Item = (&LanguageTag, f32)> {
        self.0.iter().map(|item| (&item.tag, item.weight.numeric()))
    }
}

impl Item {
    fn parse(s: &str) -> Result<Item, Error> {
        let semicolon_pos = s.find(';');

        let (before_semicolon, after_semicolon) = if let Some(semi) = semicolon_pos {
            (&s[..semi], Some(&s[semi + 1..]))
        } else {
            (s, None)
        };

        let tag = LanguageTag::parse(before_semicolon).map_err(Error::InvalidLanguageTag)?;

        let weight;

        if let Some(quality) = after_semicolon {
            let quality = quality.trim_start_matches(&OWS[..]);

            let number = if let Some(qvalue) = quality.strip_prefix("q=") {
                if qvalue.starts_with(&['0', '1'][..]) {
                    let first_digit = qvalue.chars().next().unwrap();

                    if let Some(decimals) = qvalue[1..].strip_prefix(".") {
                        if first_digit == '0'
                            && decimals.len() <= 3
                            && decimals.chars().all(|c| c.is_digit(10))
                        {
                            qvalue
                        } else if first_digit == '1'
                            && decimals.len() <= 3
                            && decimals.chars().all(|c| c == '0')
                        {
                            qvalue
                        } else {
                            return Err(Error::InvalidWeight);
                        }
                    } else {
                        qvalue
                    }
                } else {
                    return Err(Error::InvalidWeight);
                }
            } else {
                return Err(Error::InvalidWeight);
            };

            weight = Weight(Some(
                f32::from_str(number).map_err(|_| Error::InvalidWeight)?,
            ));
        } else {
            weight = Weight(None);
        }

        Ok(Item { tag, weight })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_accept_language() {
        // plain tag
        assert_eq!(
            AcceptLanguage::parse("es-MX").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(None)
                }]
                .into_boxed_slice()
            )
        );

        // with quality
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // with quality
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=0").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(0.0))
                }]
                .into_boxed_slice()
            )
        );

        // zero decimals are allowed
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=0.").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(0.0))
                }]
                .into_boxed_slice()
            )
        );

        // zero decimals are allowed
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // one decimal
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.0").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // two decimals
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.00").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // three decimals
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.000").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // multiple elements
        assert_eq!(
            AcceptLanguage::parse("es-MX, en; q=0.5").unwrap(),
            AcceptLanguage(
                vec![
                    Item {
                        tag: LanguageTag::parse("es-MX").unwrap(),
                        weight: Weight(None)
                    },
                    Item {
                        tag: LanguageTag::parse("en").unwrap(),
                        weight: Weight(Some(0.5))
                    },
                ]
                .into_boxed_slice()
            )
        );

        // superfluous whitespace
        assert_eq!(
            AcceptLanguage::parse(",es-MX;q=1.000  , en; q=0.125  ,  ,").unwrap(),
            AcceptLanguage(
                vec![
                    Item {
                        tag: LanguageTag::parse("es-MX").unwrap(),
                        weight: Weight(Some(1.0))
                    },
                    Item {
                        tag: LanguageTag::parse("en").unwrap(),
                        weight: Weight(Some(0.125))
                    },
                ]
                .into_boxed_slice()
            )
        );
    }

    #[test]
    fn empty_lists() {
        assert!(matches!(AcceptLanguage::parse(""), Err(Error::NoElements)));

        assert!(matches!(AcceptLanguage::parse(","), Err(Error::NoElements)));

        assert!(matches!(
            AcceptLanguage::parse(", , ,,,"),
            Err(Error::NoElements)
        ));
    }

    #[test]
    fn ascii_only() {
        assert!(matches!(
            AcceptLanguage::parse("ës"),
            Err(Error::InvalidCharacters)
        ));
    }

    #[test]
    fn invalid_tag() {
        assert!(matches!(
            AcceptLanguage::parse("no_underscores"),
            Err(Error::InvalidLanguageTag(_))
        ));
    }

    #[test]
    fn invalid_weight() {
        assert!(matches!(
            AcceptLanguage::parse("es;"),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q"),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q="),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=2"),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.1"),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.12"),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.123"),
            Err(Error::InvalidWeight)
        ));

        // Up to three decimals allowed per RFC 7231
        assert!(matches!(
            AcceptLanguage::parse("es;q=0.1234"),
            Err(Error::InvalidWeight)
        ));
    }

    #[test]
    fn iter() {
        let accept_language = AcceptLanguage::parse("es-MX, en; q=0.5").unwrap();
        let mut iter = accept_language.iter();

        let (tag, weight) = iter.next().unwrap();
        assert_eq!(*tag, LanguageTag::parse("es-MX").unwrap());
        assert_eq!(weight, 1.0);

        let (tag, weight) = iter.next().unwrap();
        assert_eq!(*tag, LanguageTag::parse("en").unwrap());
        assert_eq!(weight, 0.5);

        assert!(iter.next().is_none());
    }
}
<commit_msg>Rename AcceptLanguageError<commit_after>//! Parser for an Accept-Language HTTP header.

use language_tags::{LanguageTag, ParseError};

use std::str::FromStr;

#[derive(Debug, PartialEq)]
struct Weight(Option<f32>);

impl Weight {
    fn numeric(&self) -> f32 {
        self.0.unwrap_or(1.0)
    }
}

#[derive(Debug, PartialEq)]
struct Item {
    tag: LanguageTag,
    weight: Weight,
}

/// Stores a parsed version of an HTTP Accept-Language header.
///
/// https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.5
#[derive(Debug, PartialEq)]
pub struct AcceptLanguage(Box<[Item]>);

/// Errors when parsing an `AcceptLanguage`.
#[derive(Debug, PartialEq)]
pub enum AcceptLanguageError {
    NoElements,
    InvalidCharacters,
    InvalidLanguageTag(ParseError),
    InvalidWeight,
}

/// Optional whitespace, Space or Tab, per https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.3
const OWS: [char; 2] = ['\x20', '\x09'];

impl AcceptLanguage {
    pub fn parse(s: &str) -> Result<AcceptLanguage, AcceptLanguageError> {
        if !s.is_ascii() {
            return Err(AcceptLanguageError::InvalidCharacters);
        }

        let mut items = Vec::new();

        for val in s.split(',') {
            let trimmed = val.trim_matches(&OWS[..]);
            if trimmed.len() == 0 {
                continue;
            }

            items.push(Item::parse(trimmed)?);
        }

        if items.len() == 0 {
            Err(AcceptLanguageError::NoElements)
        } else {
            Ok(AcceptLanguage(items.into_boxed_slice()))
        }
    }

    pub fn iter(&self) -> impl Iterator<Item = (&LanguageTag, f32)> {
        self.0.iter().map(|item| (&item.tag, item.weight.numeric()))
    }
}

impl Item {
    fn parse(s: &str) -> Result<Item, AcceptLanguageError> {
        let semicolon_pos = s.find(';');

        let (before_semicolon, after_semicolon) = if let Some(semi) = semicolon_pos {
            (&s[..semi], Some(&s[semi + 1..]))
        } else {
            (s, None)
        };

        let tag = LanguageTag::parse(before_semicolon).map_err(AcceptLanguageError::InvalidLanguageTag)?;

        let weight;

        if let Some(quality) = after_semicolon {
            let quality = quality.trim_start_matches(&OWS[..]);

            let number = if let Some(qvalue) = quality.strip_prefix("q=") {
                if qvalue.starts_with(&['0', '1'][..]) {
                    let first_digit = qvalue.chars().next().unwrap();

                    if let Some(decimals) = qvalue[1..].strip_prefix(".") {
                        if first_digit == '0'
                            && decimals.len() <= 3
                            && decimals.chars().all(|c| c.is_digit(10))
                        {
                            qvalue
                        } else if first_digit == '1'
                            && decimals.len() <= 3
                            && decimals.chars().all(|c| c == '0')
                        {
                            qvalue
                        } else {
                            return Err(AcceptLanguageError::InvalidWeight);
                        }
                    } else {
                        qvalue
                    }
                } else {
                    return Err(AcceptLanguageError::InvalidWeight);
                }
            } else {
                return Err(AcceptLanguageError::InvalidWeight);
            };

            weight = Weight(Some(
                f32::from_str(number).map_err(|_| AcceptLanguageError::InvalidWeight)?,
            ));
        } else {
            weight = Weight(None);
        }

        Ok(Item { tag, weight })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_accept_language() {
        // plain tag
        assert_eq!(
            AcceptLanguage::parse("es-MX").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(None)
                }]
                .into_boxed_slice()
            )
        );

        // with quality
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // with quality
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=0").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(0.0))
                }]
                .into_boxed_slice()
            )
        );

        // zero decimals are allowed
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=0.").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(0.0))
                }]
                .into_boxed_slice()
            )
        );

        // zero decimals are allowed
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // one decimal
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.0").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // two decimals
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.00").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // three decimals
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.000").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // multiple elements
        assert_eq!(
            AcceptLanguage::parse("es-MX, en; q=0.5").unwrap(),
            AcceptLanguage(
                vec![
                    Item {
                        tag: LanguageTag::parse("es-MX").unwrap(),
                        weight: Weight(None)
                    },
                    Item {
                        tag: LanguageTag::parse("en").unwrap(),
                        weight: Weight(Some(0.5))
                    },
                ]
                .into_boxed_slice()
            )
        );

        // superfluous whitespace
        assert_eq!(
            AcceptLanguage::parse(",es-MX;q=1.000  , en; q=0.125  ,  ,").unwrap(),
            AcceptLanguage(
                vec![
                    Item {
                        tag: LanguageTag::parse("es-MX").unwrap(),
                        weight: Weight(Some(1.0))
                    },
                    Item {
                        tag: LanguageTag::parse("en").unwrap(),
                        weight: Weight(Some(0.125))
                    },
                ]
                .into_boxed_slice()
            )
        );
    }

    #[test]
    fn empty_lists() {
        assert!(matches!(AcceptLanguage::parse(""), Err(AcceptLanguageError::NoElements)));

        assert!(matches!(AcceptLanguage::parse(","), Err(AcceptLanguageError::NoElements)));

        assert!(matches!(
            AcceptLanguage::parse(", , ,,,"),
            Err(AcceptLanguageError::NoElements)
        ));
    }

    #[test]
    fn ascii_only() {
        assert!(matches!(
            AcceptLanguage::parse("ës"),
            Err(AcceptLanguageError::InvalidCharacters)
        ));
    }

    #[test]
    fn invalid_tag() {
        assert!(matches!(
            AcceptLanguage::parse("no_underscores"),
            Err(AcceptLanguageError::InvalidLanguageTag(_))
        ));
    }

    #[test]
    fn invalid_weight() {
        assert!(matches!(
            AcceptLanguage::parse("es;"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q="),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=2"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.1"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.12"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.123"),
            Err(AcceptLanguageError::InvalidWeight)
        ));

        // Up to three decimals allowed per RFC 7231
        assert!(matches!(
            AcceptLanguage::parse("es;q=0.1234"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
    }

    #[test]
    fn iter() {
        let accept_language = AcceptLanguage::parse("es-MX, en; q=0.5").unwrap();
        let mut iter = accept_language.iter();

        let (tag, weight) = iter.next().unwrap();
        assert_eq!(*tag, LanguageTag::parse("es-MX").unwrap());
        assert_eq!(weight, 1.0);

        let (tag, weight) = iter.next().unwrap();
        assert_eq!(*tag, LanguageTag::parse("en").unwrap());
        assert_eq!(weight, 0.5);

        assert!(iter.next().is_none());
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::mem;
use std::rc::Rc;

use alloc::AllocBox;
use gc_error::{GcError, Result};
use js_types::js_type::{JsPtrEnum, JsType, JsVar, Binding};

// Tunable GC parameter. Probably should not be a constant, but good enough for now.
const GC_THRESHOLD: usize = 64;

/// A logical scope in the AST. Represents any scoped block of Javascript code.
/// roots: A set of all root references into the heap
/// parent: An optional parent scope, e.g. the caller of this function scope,
///         or the function that owns an `if` statement
/// heap: A shared reference to the heap allocator.
/// stack: The stack of the current scope, containing all variables allocated
///        by this scope.
pub struct Scope {
    roots: HashSet<Binding>,
    pub parent: Option<Box<Scope>>,
    heap: Rc<RefCell<AllocBox>>,
    stack: HashMap<Binding, JsVar>,
}

impl Scope {
    /// Create a new, parentless scope node.
    pub fn new(heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: HashSet::new(),
            parent: None,
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Create a scope as a child of another scope. Clones all of bindings of
    /// root references from the parent.
    pub fn as_child(parent: Scope, heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: parent.roots.clone(),
            parent: Some(Box::new(parent)),
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Sets the parent of a scope, and clones and unions its root bindings.
    pub fn set_parent(&mut self, parent: Scope) {
        self.parent = Some(Box::new(parent));
    }

    /// Push a new JsVar onto the stack, and maybe allocate a pointer in the heap.
    pub fn push(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        let res = match &var.t {
            &JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // Creating a new pointer creates a new root
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().alloc(var.binding.clone(), ptr)
                } else {
                    return Err(GcError::PtrError);
                },
            _ => Ok(()),
        };
        self.stack.insert(var.binding.clone(), var);
        res
    }

    /// Take ownership of a variable (usually from another scope).
    pub fn own(&mut self, var: JsVar) {
        self.stack.insert(var.binding.clone(), var);
    }

    /// Return an optional copy of a variable and an optional pointer into the heap.
    pub fn get_var_copy(&self, bnd: &Binding) -> (Option<JsVar>, Option<JsPtrEnum>) {
        if let Some(var) = self.stack.get(bnd) {
            match var.t {
                JsType::JsPtr => {
                    if let Some(alloc) = self.heap.borrow().find_id(bnd) {
                        (Some(var.clone()), Some(alloc.borrow().clone()))
                    } else {
                        // This case should be impossible unless you have an
                        // invalid ptr, which should also be impossible.
                        (None, None)
                    }
                },
                _ => (Some(var.clone()), None),
            }
        } else if let Some(ref parent) = self.parent {
            // FIXME? This is slow.
            parent.get_var_copy(bnd)
        } else { (None, None) }
    }

    /// Try to update a variable that's been allocated.
    pub fn update_var(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        match var.t {
            JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // A new root was potentially created
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().update_ptr(&var.binding, ptr)
                } else {
                    Err(GcError::PtrError)
                },
            _ => {
                if let Entry::Occupied(mut view) = self.stack.entry(var.binding.clone()) {
                    // A root was potentially removed
                    self.roots.remove(&var.binding);
                    *view.get_mut() = var;
                    return Ok(());
                }
                // Hack to skirt mutable borrow of self lasting longer than it should
                if let Entry::Vacant(_) = self.stack.entry(var.binding.clone()) {
                    // TODO Need to call `push` on the root scope?
                    // Push into this scope and just give to parent when done?
                    return self.push(var, ptr);
                }
                unreachable!();
            },
        }
    }

    /// Called when a scope exits. Transfers the stack of this scope to its parent,
    /// and returns the parent scope, which may be `None`.
    pub fn transfer_stack(&mut self) -> Option<Box<Scope>> {
        if self.heap.borrow().len() > GC_THRESHOLD {
            self.heap.borrow_mut().mark_roots(&self.roots);
            self.heap.borrow_mut().mark_ptrs();
            self.heap.borrow_mut().sweep_ptrs();
        }
        if let Some(ref mut parent) = self.parent {
            for (_, var) in self.stack.drain() {
                match var.t {
                    JsType::JsPtr => {
                        // Mangle each binding before giving it to the parent
                        // scope. This avoids binding collisions, and helps
                        // identify to a human observer which bindings are
                        // not from the current scope.
                        let mut mangled_var = var.clone();
                        mangled_var.binding = Binding::mangle(var.binding);
                        parent.own(mangled_var);
                    }
                    _ => (),
                }
            }
            parent.roots = parent.roots.union(&self.roots).cloned().collect();
        }
        mem::replace(&mut self.parent, None)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use js_types::js_type::{Binding, JsPtrEnum, JsKey, JsKeyEnum};
    use js_types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_new_scope() {
        let heap = test_utils::make_alloc_box();
        let test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
    }

    #[test]
    fn test_as_child_scope() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let test_scope = Scope::as_child(parent_scope, &heap);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_set_parent() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let mut test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
        test_scope.set_parent(parent_scope);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_get_var_copy() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        test_scope.push(x, Some(x_ptr)).unwrap();
        let bad_bnd = Binding::anon();

        let (var_copy, ptr_copy) = test_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());

        let (bad_copy, ptr_copy) = test_scope.get_var_copy(&bad_bnd);
        assert!(bad_copy.is_none());
        assert!(ptr_copy.is_none());
    }

    #[test]
    fn test_get_var_copy_from_parent_scope() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        parent_scope.push(x, Some(x_ptr)).unwrap();

        let mut child_scope= Scope::as_child(parent_scope, &heap);

        let (var_copy, ptr_copy) = child_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());
    }

    #[test]
    fn test_update_var() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        assert!(test_scope.push(x, Some(x_ptr)).is_ok());
        let (update, _) = test_scope.get_var_copy(&x_bnd);
        let update_ptr = Some(JsPtrEnum::JsStr(JsStrStruct::new("test")));
        assert!(test_scope.update_var(update.unwrap(), update_ptr).is_ok());

        let (update, update_ptr) = test_scope.get_var_copy(&x_bnd);
        match update_ptr.unwrap() {
            JsPtrEnum::JsStr(JsStrStruct{text: ref s}) => assert_eq!(s, "test"),
            _ => panic!("Updated var was not equal to expected!")
        }
        assert_eq!(update.unwrap().binding, x_bnd);
    }

    #[test]
    fn test_transfer_stack() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        {
            let mut test_scope = Scope::as_child(parent_scope, &heap);
            test_scope.push(test_utils::make_num(0.), None).unwrap();
            test_scope.push(test_utils::make_num(1.), None).unwrap();
            test_scope.push(test_utils::make_num(2.), None).unwrap();
            let kvs = vec![(JsKey::new(JsKeyEnum::JsBool(true)),
                            test_utils::make_num(1.))];
            let (var, ptr) = test_utils::make_obj(kvs);
            test_scope.push(var, Some(ptr)).unwrap();
            parent_scope = *test_scope.transfer_stack().unwrap();
        }
        assert_eq!(parent_scope.stack.len(), 1);
    }
}
<commit_msg>Union parent's roots when a parent scope is set<commit_after>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::mem;
use std::rc::Rc;

use alloc::AllocBox;
use gc_error::{GcError, Result};
use js_types::js_type::{JsPtrEnum, JsType, JsVar, Binding};

// Tunable GC parameter. Probably should not be a constant, but good enough for now.
const GC_THRESHOLD: usize = 64;

/// A logical scope in the AST. Represents any scoped block of Javascript code.
/// roots: A set of all root references into the heap
/// parent: An optional parent scope, e.g. the caller of this function scope,
///         or the function that owns an `if` statement
/// heap: A shared reference to the heap allocator.
/// stack: The stack of the current scope, containing all variables allocated
///        by this scope.
pub struct Scope {
    roots: HashSet<Binding>,
    pub parent: Option<Box<Scope>>,
    heap: Rc<RefCell<AllocBox>>,
    stack: HashMap<Binding, JsVar>,
}

impl Scope {
    /// Create a new, parentless scope node.
    pub fn new(heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: HashSet::new(),
            parent: None,
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Create a scope as a child of another scope. Clones all of bindings of
    /// root references from the parent.
    pub fn as_child(parent: Scope, heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: parent.roots.clone(),
            parent: Some(Box::new(parent)),
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Sets the parent of a scope, and clones and unions its root bindings.
    pub fn set_parent(&mut self, parent: Scope) {
        self.roots = self.roots.union(&parent.roots).cloned().collect();
        self.parent = Some(Box::new(parent));
    }

    /// Push a new JsVar onto the stack, and maybe allocate a pointer in the heap.
    pub fn push(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        let res = match &var.t {
            &JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // Creating a new pointer creates a new root
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().alloc(var.binding.clone(), ptr)
                } else {
                    return Err(GcError::PtrError);
                },
            _ => Ok(()),
        };
        self.stack.insert(var.binding.clone(), var);
        res
    }

    /// Take ownership of a variable (usually from another scope).
    pub fn own(&mut self, var: JsVar) {
        self.stack.insert(var.binding.clone(), var);
    }

    /// Return an optional copy of a variable and an optional pointer into the heap.
    pub fn get_var_copy(&self, bnd: &Binding) -> (Option<JsVar>, Option<JsPtrEnum>) {
        if let Some(var) = self.stack.get(bnd) {
            match var.t {
                JsType::JsPtr => {
                    if let Some(alloc) = self.heap.borrow().find_id(bnd) {
                        (Some(var.clone()), Some(alloc.borrow().clone()))
                    } else {
                        // This case should be impossible unless you have an
                        // invalid ptr, which should also be impossible.
                        (None, None)
                    }
                },
                _ => (Some(var.clone()), None),
            }
        } else if let Some(ref parent) = self.parent {
            // FIXME? This is slow.
            parent.get_var_copy(bnd)
        } else { (None, None) }
    }

    /// Try to update a variable that's been allocated.
    pub fn update_var(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        match var.t {
            JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // A new root was potentially created
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().update_ptr(&var.binding, ptr)
                } else {
                    Err(GcError::PtrError)
                },
            _ => {
                if let Entry::Occupied(mut view) = self.stack.entry(var.binding.clone()) {
                    // A root was potentially removed
                    self.roots.remove(&var.binding);
                    *view.get_mut() = var;
                    return Ok(());
                }
                // Hack to skirt mutable borrow of self lasting longer than it should
                if let Entry::Vacant(_) = self.stack.entry(var.binding.clone()) {
                    // TODO Need to call `push` on the root scope?
                    // Push into this scope and just give to parent when done?
                    return self.push(var, ptr);
                }
                unreachable!();
            },
        }
    }

    /// Called when a scope exits. Transfers the stack of this scope to its parent,
    /// and returns the parent scope, which may be `None`.
    pub fn transfer_stack(&mut self) -> Option<Box<Scope>> {
        if self.heap.borrow().len() > GC_THRESHOLD {
            self.heap.borrow_mut().mark_roots(&self.roots);
            self.heap.borrow_mut().mark_ptrs();
            self.heap.borrow_mut().sweep_ptrs();
        }
        if let Some(ref mut parent) = self.parent {
            for (_, var) in self.stack.drain() {
                match var.t {
                    JsType::JsPtr => {
                        // Mangle each binding before giving it to the parent
                        // scope. This avoids binding collisions, and helps
                        // identify to a human observer which bindings are
                        // not from the current scope.
                        let mut mangled_var = var.clone();
                        mangled_var.binding = Binding::mangle(var.binding);
                        parent.own(mangled_var);
                    }
                    _ => (),
                }
            }
            parent.roots = parent.roots.union(&self.roots).cloned().collect();
        }
        mem::replace(&mut self.parent, None)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use js_types::js_type::{Binding, JsPtrEnum, JsKey, JsKeyEnum};
    use js_types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_new_scope() {
        let heap = test_utils::make_alloc_box();
        let test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
    }

    #[test]
    fn test_as_child_scope() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let test_scope = Scope::as_child(parent_scope, &heap);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_set_parent() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let mut test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
        test_scope.set_parent(parent_scope);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_get_var_copy() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        test_scope.push(x, Some(x_ptr)).unwrap();
        let bad_bnd = Binding::anon();

        let (var_copy, ptr_copy) = test_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());

        let (bad_copy, ptr_copy) = test_scope.get_var_copy(&bad_bnd);
        assert!(bad_copy.is_none());
        assert!(ptr_copy.is_none());
    }

    #[test]
    fn test_get_var_copy_from_parent_scope() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        parent_scope.push(x, Some(x_ptr)).unwrap();

        let mut child_scope= Scope::as_child(parent_scope, &heap);

        let (var_copy, ptr_copy) = child_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());
    }

    #[test]
    fn test_update_var() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        assert!(test_scope.push(x, Some(x_ptr)).is_ok());
        let (update, _) = test_scope.get_var_copy(&x_bnd);
        let update_ptr = Some(JsPtrEnum::JsStr(JsStrStruct::new("test")));
        assert!(test_scope.update_var(update.unwrap(), update_ptr).is_ok());

        let (update, update_ptr) = test_scope.get_var_copy(&x_bnd);
        match update_ptr.unwrap() {
            JsPtrEnum::JsStr(JsStrStruct{text: ref s}) => assert_eq!(s, "test"),
            _ => panic!("Updated var was not equal to expected!")
        }
        assert_eq!(update.unwrap().binding, x_bnd);
    }

    #[test]
    fn test_transfer_stack() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        {
            let mut test_scope = Scope::as_child(parent_scope, &heap);
            test_scope.push(test_utils::make_num(0.), None).unwrap();
            test_scope.push(test_utils::make_num(1.), None).unwrap();
            test_scope.push(test_utils::make_num(2.), None).unwrap();
            let kvs = vec![(JsKey::new(JsKeyEnum::JsBool(true)),
                            test_utils::make_num(1.))];
            let (var, ptr) = test_utils::make_obj(kvs);
            test_scope.push(var, Some(ptr)).unwrap();
            parent_scope = *test_scope.transfer_stack().unwrap();
        }
        assert_eq!(parent_scope.stack.len(), 1);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Implements the `GraphDot` trait for `SSAStorage`

use petgraph::graph;
use petgraph::visit::{IntoEdgeReferences, EdgeRef};
use petgraph::graph::NodeIndex;

use middle::ir::MOpcode;
use middle::dot::{DotAttrBlock, GraphDot};
use super::ssastorage::{EdgeData, NodeData, SSAStorage};
use super::ssa_traits::{SSA, SSAExtra};
use middle::ssa::cfg_traits::CFG;

///////////////////////////////////////////////////////////////////////////////
//// Implementation of GraphDot to emit Dot for SSAStorage.
///////////////////////////////////////////////////////////////////////////////

impl GraphDot for SSAStorage {
    type NodeIndex = graph::NodeIndex;
    type EdgeIndex = graph::EdgeIndex;

    fn configure(&self) -> String {
        "digraph cfg {\nsplines=\"ortho\"\nranksep=1\nnodesep=1;\ngraph [fontsize=12 fontname=\"Verdana\" compound=true \
         rankdir=TB;]\n"
            .to_owned()
    }

    fn nodes(&self) -> Vec<Self::NodeIndex> {
        self.g.node_indices().collect()
    }

    fn edges(&self) -> Vec<Self::EdgeIndex> {
        self.g.edge_references().map(|x| x.id()).collect()
    }

    fn node_count(&self) -> usize {
        self.g.node_count()
    }

    fn edge_count(&self) -> usize {
        self.g.edge_count()
    }

    fn node_index_new(i: usize) -> Self::NodeIndex {
        graph::NodeIndex::new(i)
    }

    fn edge_index_new(i: usize) -> Self::EdgeIndex {
        graph::EdgeIndex::new(i)
    }

    fn node_cluster(&self, i: &Self::NodeIndex) -> Option<usize> {
        let invalid_block = self.invalid_action().expect("Invalid Action is not defined");
        match self.g.node_weight(*i) {
            Some(&NodeData::BasicBlock(_, _)) | Some(&NodeData::DynamicAction) => Some(i.index()),
            _ => Some(self.block_for(*i).unwrap_or(invalid_block).index()),
        }
    }

    fn edge_source(&self, i: &Self::EdgeIndex) -> Self::NodeIndex {
        let edge_opt = &self.g.edge_references().find(|x| x.id() == *i);
        if edge_opt.is_none() {
            radeco_err!("Invalid edge index");
            return NodeIndex::end();
        };
        let edge = edge_opt.unwrap();
        match *edge.weight() {
            EdgeData::Data(_) => edge.target(),
            _ => edge.source(),
        }
    }

    fn edge_target(&self, i: &Self::EdgeIndex) -> Self::NodeIndex {
        let edge_opt = &self.g.edge_references().find(|x| x.id() == *i);
        if edge_opt.is_none() {
            radeco_err!("Invalid edge index");
            return NodeIndex::end();
        };
        let edge = edge_opt.unwrap();
         match *edge.weight() {
            EdgeData::Data(_) => edge.source(),
            _ => edge.target(),
        }
    }

    fn edge_skip(&self, i: &Self::EdgeIndex) -> bool {
        let edge_opt = &self.g.edge_references().find(|x| x.id() == *i);
        if edge_opt.is_none() {
            radeco_err!("Invalid edge index");
            return false;
        };
        let edge = edge_opt.unwrap();
        match *edge.weight() {
            EdgeData::ContainedInBB(_) | EdgeData::RegisterState => true,
            EdgeData::Data(_) => {
                // Skip data edges from registers to registerstates.
                if let NodeData::RegisterState = self.g[edge.source()] {
                    self.comment(edge.target()).is_some()
                } else {
                    false
                }
            },
            _ => false,
        }
    }

    // TODO: Ordering of clusters for ssa is kind of hacky and may not run top to
    // bottom in some
    // cases.
    fn edge_attrs(&self, i: &Self::EdgeIndex) -> DotAttrBlock {
        let edge_opt = &self.g.edge_references().find(|x| x.id() == *i);
        if edge_opt.is_none() {
            radeco_err!("Invalid edge index");
            return DotAttrBlock::Raw(String::new());
        };
        let edge = edge_opt.unwrap();
        let mut prefix = String::new();
        let src = edge.source();
        let target = edge.target();

        prefix.push_str(&format!("n{} -> n{}",
                                 src.index(),
                                 target.index()));
        let target_is_bb = if let NodeData::BasicBlock(_, _) = self.g[edge.target()] {
            true
        } else {
            false
        };
        let attr = match *edge.weight() {
            EdgeData::Control(_) if !target_is_bb => {
                vec![("color".to_string(), "red".to_string())]
            }
            EdgeData::Control(i) => {
                // Determine the source and destination clusters.
                let source_cluster = edge.source().index();
                let dst_cluster = edge.target().index();
                let (color, label) = match i {
                    0 => ("red", "F"),
                    1 => ("green", "T"),
                    2 => ("blue", "U"),
                    _ => unreachable!(),
                };
                vec![("color".to_string(), color.to_string()),
                     ("xlabel".to_string(), label.to_string()),
                     ("ltail".to_string(), format!("cluster_{}", source_cluster)),
                     ("lhead".to_string(), format!("cluster_{}", dst_cluster)),
                     ("minlen".to_string(), "9".to_owned())]
            }
            EdgeData::Data(i) => {
                vec![("dir".to_string(), "back".to_string()),
                     ("xlabel".to_string(), format!("{}", i))]
            }
            EdgeData::ContainedInBB(_) => {
                vec![("color".to_string(), "gray".to_string())]
            }
            EdgeData::Selector => {
                vec![("color".to_string(), "purple".to_string())]
            }
            EdgeData::ReplacedBy => {
                vec![("color".to_string(), "brown".to_string())]
            }
            EdgeData::RegisterInfo => {
                vec![("color".to_string(), "yellow".to_string())]
            }
            EdgeData::RegisterState => unreachable!(),
        };

        DotAttrBlock::Hybrid(prefix, attr)
    }

    fn node_attrs(&self, i: &Self::NodeIndex) -> DotAttrBlock {
        let node = &self.g[*i];
        let mut prefix = String::new();
        prefix.push_str(&format!("n{}", i.index()));

        let attr = match *node {
            NodeData::Op(ref opc, vi) => {
                let w = vi.width().get_width().unwrap_or(64);
                let mut attrs = Vec::new();
                let mut r = String::new();
                let addr = self.addr(i);
                if addr.is_some() {
                    r.push_str(&format!("<{}: ",
                                        addr.as_ref().unwrap()))
                }
                r.push_str(&format!("\"[i{}] {:?}\"", w, opc));
                if addr.is_some() {
                    r.push_str(">");
                }

                if let MOpcode::OpConst(_) = *opc {
                    attrs.push(("style".to_owned(), "filled".to_owned()));
                    attrs.push(("color".to_owned(), "black".to_owned()));
                    attrs.push(("fillcolor".to_owned(), "yellow".to_owned()));
                }
                if self.is_marked(i) {
                    attrs.push(("label".to_string(), r));
                    attrs.push(("style".to_owned(), "filled".to_owned()));
                    attrs.push(("color".to_owned(), "black".to_owned()));
                    attrs.push(("fillcolor".to_owned(), "green".to_owned()));
                } else {
                    attrs.push(("fillcolor".to_owned(), "white".to_owned()));
                }
                attrs
            }
            NodeData::BasicBlock(addr, _) => {
                let label_str = format!("<Basic Block \
                                         Information
Start Address: {}>",
                                        addr);
                let mut attrs = Vec::new();
                if let Some(e) = self.entry_node() {
                    if *i == e {
                        attrs.push(("rank".to_string(), "min".to_string()));
                    }
                };

                attrs.extend([("style".to_string(), "filled".to_string()),
                              ("fillcolor".to_string(), "white".to_string()),
                              ("label".to_string(), label_str),
                              ("shape".to_string(), "box".to_string()),
                              ("color".to_string(), "\"grey\"".to_string()),]
                                 .iter()
                                 .cloned());
                attrs
            }
            NodeData::Comment(_, ref msg) => {
                vec![("label".to_string(),
                      format!("\"{}\"", msg.replace("\"", "\\\""))),
                     ("shape".to_owned(), "box".to_owned()),
                     ("style".to_owned(), "filled".to_owned()),
                     ("color".to_owned(), "black".to_owned()),
                     ("fillcolor".to_owned(), "greenyellow".to_owned())]
            }
            NodeData::Phi(_, _) => {
                let mut attrs = Vec::new();
                let mut label = format!("{:?}", node);
                label = label.replace("\"", "\\\"");
                label = format!("\"{}\"", label);
                if let Some(addr) = self.addr(i) {
                    label = format!("<{}:  {}>", addr, label);
                }
                attrs.push(("label".to_string(), label));
                attrs.push(("style".to_owned(), "filled".to_owned()));
                attrs.push(("color".to_owned(), "black".to_owned()));
                if self.is_marked(i) {
                    attrs.push(("fillcolor".to_owned(), "green".to_owned()));
                } else {
                    attrs.push(("fillcolor".to_owned(), "orange".to_owned()));
                }
                attrs
            }
            _ => {
                let mut attrs = Vec::new();
                let mut label = format!("{:?}", node);
                label = label.replace("\"", "\\\"");
                label = format!("\"{}\"", label);
                if let Some(addr) = self.addr(i) {
                    label = format!("<{}:  {}>", addr, label);
                }
                attrs.push(("label".to_string(), label));
                attrs.push(("style".to_owned(), "filled".to_owned()));
                attrs.push(("color".to_owned(), "black".to_owned()));
                if self.is_marked(i) {
                    attrs.push(("fillcolor".to_owned(), "green".to_owned()));
                } else {
                    attrs.push(("fillcolor".to_owned(), "grey90".to_owned()));
                }
                attrs
            }
        };
        DotAttrBlock::Hybrid(prefix, attr)
    }
}
<commit_msg>Fix the attributes for op nodes<commit_after>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Implements the `GraphDot` trait for `SSAStorage`

use petgraph::graph;
use petgraph::visit::{IntoEdgeReferences, EdgeRef};
use petgraph::graph::NodeIndex;

use middle::ir::MOpcode;
use middle::dot::{DotAttrBlock, GraphDot};
use super::ssastorage::{EdgeData, NodeData, SSAStorage};
use super::ssa_traits::{SSA, SSAExtra};
use middle::ssa::cfg_traits::CFG;

///////////////////////////////////////////////////////////////////////////////
//// Implementation of GraphDot to emit Dot for SSAStorage.
///////////////////////////////////////////////////////////////////////////////

impl GraphDot for SSAStorage {
    type NodeIndex = graph::NodeIndex;
    type EdgeIndex = graph::EdgeIndex;

    fn configure(&self) -> String {
        "digraph cfg {\nsplines=\"ortho\"\nranksep=1\nnodesep=1;\ngraph [fontsize=12 fontname=\"Verdana\" compound=true \
         rankdir=TB;]\n"
            .to_owned()
    }

    fn nodes(&self) -> Vec<Self::NodeIndex> {
        self.g.node_indices().collect()
    }

    fn edges(&self) -> Vec<Self::EdgeIndex> {
        self.g.edge_references().map(|x| x.id()).collect()
    }

    fn node_count(&self) -> usize {
        self.g.node_count()
    }

    fn edge_count(&self) -> usize {
        self.g.edge_count()
    }

    fn node_index_new(i: usize) -> Self::NodeIndex {
        graph::NodeIndex::new(i)
    }

    fn edge_index_new(i: usize) -> Self::EdgeIndex {
        graph::EdgeIndex::new(i)
    }

    fn node_cluster(&self, i: &Self::NodeIndex) -> Option<usize> {
        let invalid_block = self.invalid_action().expect("Invalid Action is not defined");
        match self.g.node_weight(*i) {
            Some(&NodeData::BasicBlock(_, _)) | Some(&NodeData::DynamicAction) => Some(i.index()),
            _ => Some(self.block_for(*i).unwrap_or(invalid_block).index()),
        }
    }

    fn edge_source(&self, i: &Self::EdgeIndex) -> Self::NodeIndex {
        let edge_opt = &self.g.edge_references().find(|x| x.id() == *i);
        if edge_opt.is_none() {
            radeco_err!("Invalid edge index");
            return NodeIndex::end();
        };
        let edge = edge_opt.unwrap();
        match *edge.weight() {
            EdgeData::Data(_) => edge.target(),
            _ => edge.source(),
        }
    }

    fn edge_target(&self, i: &Self::EdgeIndex) -> Self::NodeIndex {
        let edge_opt = &self.g.edge_references().find(|x| x.id() == *i);
        if edge_opt.is_none() {
            radeco_err!("Invalid edge index");
            return NodeIndex::end();
        };
        let edge = edge_opt.unwrap();
         match *edge.weight() {
            EdgeData::Data(_) => edge.source(),
            _ => edge.target(),
        }
    }

    fn edge_skip(&self, i: &Self::EdgeIndex) -> bool {
        let edge_opt = &self.g.edge_references().find(|x| x.id() == *i);
        if edge_opt.is_none() {
            radeco_err!("Invalid edge index");
            return false;
        };
        let edge = edge_opt.unwrap();
        match *edge.weight() {
            EdgeData::ContainedInBB(_) | EdgeData::RegisterState => true,
            EdgeData::Data(_) => {
                // Skip data edges from registers to registerstates.
                if let NodeData::RegisterState = self.g[edge.source()] {
                    self.comment(edge.target()).is_some()
                } else {
                    false
                }
            },
            _ => false,
        }
    }

    // TODO: Ordering of clusters for ssa is kind of hacky and may not run top to
    // bottom in some
    // cases.
    fn edge_attrs(&self, i: &Self::EdgeIndex) -> DotAttrBlock {
        let edge_opt = &self.g.edge_references().find(|x| x.id() == *i);
        if edge_opt.is_none() {
            radeco_err!("Invalid edge index");
            return DotAttrBlock::Raw(String::new());
        };
        let edge = edge_opt.unwrap();
        let mut prefix = String::new();
        let src = edge.source();
        let target = edge.target();

        prefix.push_str(&format!("n{} -> n{}",
                                 src.index(),
                                 target.index()));
        let target_is_bb = if let NodeData::BasicBlock(_, _) = self.g[edge.target()] {
            true
        } else {
            false
        };
        let attr = match *edge.weight() {
            EdgeData::Control(_) if !target_is_bb => {
                vec![("color".to_string(), "red".to_string())]
            }
            EdgeData::Control(i) => {
                // Determine the source and destination clusters.
                let source_cluster = edge.source().index();
                let dst_cluster = edge.target().index();
                let (color, label) = match i {
                    0 => ("red", "F"),
                    1 => ("green", "T"),
                    2 => ("blue", "U"),
                    _ => unreachable!(),
                };
                vec![("color".to_string(), color.to_string()),
                     ("xlabel".to_string(), label.to_string()),
                     ("ltail".to_string(), format!("cluster_{}", source_cluster)),
                     ("lhead".to_string(), format!("cluster_{}", dst_cluster)),
                     ("minlen".to_string(), "9".to_owned())]
            }
            EdgeData::Data(i) => {
                vec![("dir".to_string(), "back".to_string()),
                     ("xlabel".to_string(), format!("{}", i))]
            }
            EdgeData::ContainedInBB(_) => {
                vec![("color".to_string(), "gray".to_string())]
            }
            EdgeData::Selector => {
                vec![("color".to_string(), "purple".to_string())]
            }
            EdgeData::ReplacedBy => {
                vec![("color".to_string(), "brown".to_string())]
            }
            EdgeData::RegisterInfo => {
                vec![("color".to_string(), "yellow".to_string())]
            }
            EdgeData::RegisterState => unreachable!(),
        };

        DotAttrBlock::Hybrid(prefix, attr)
    }

    fn node_attrs(&self, i: &Self::NodeIndex) -> DotAttrBlock {
        let node = &self.g[*i];
        let mut prefix = String::new();
        prefix.push_str(&format!("n{}", i.index()));

        let attr = match *node {
            NodeData::Op(ref opc, vi) => {
                let w = vi.width().get_width().unwrap_or(64);
                let mut attrs = Vec::new();
                let mut r = String::new();
                let addr = self.addr(i);
                if addr.is_some() {
                    r.push_str(&format!("<{}: ",
                                        addr.as_ref().unwrap()))
                }
                r.push_str(&format!("\"[i{}] {:?}\"", w, opc));
                if addr.is_some() {
                    r.push_str(">");
                }

                attrs.push(("style".to_owned(), "filled".to_owned()));
                if let MOpcode::OpConst(c) = *opc {
                    attrs.push(("color".to_owned(), "black".to_owned()));
                    attrs.push(("fillcolor".to_owned(), "yellow".to_owned()));
                    attrs.push(("label".to_string(), format!("\"0x{:x}\"", c)));
                } else {
                    attrs.push(("color".to_owned(), "black".to_owned()));
                    attrs.push(("label".to_string(), r));

                    if self.is_marked(i) {
                        attrs.push(("fillcolor".to_owned(), "green".to_owned()));
                    } else {
                        attrs.push(("fillcolor".to_owned(), "white".to_owned()));
                    }
                }
                attrs
            }
            NodeData::BasicBlock(addr, _) => {
                let label_str = format!("<Basic Block \
                                         Information
Start Address: {}>",
                                        addr);
                let mut attrs = Vec::new();
                if let Some(e) = self.entry_node() {
                    if *i == e {
                        attrs.push(("rank".to_string(), "min".to_string()));
                    }
                };

                attrs.extend([("style".to_string(), "filled".to_string()),
                              ("fillcolor".to_string(), "white".to_string()),
                              ("label".to_string(), label_str),
                              ("shape".to_string(), "box".to_string()),
                              ("color".to_string(), "\"grey\"".to_string()),]
                                 .iter()
                                 .cloned());
                attrs
            }
            NodeData::Comment(_, ref msg) => {
                vec![("label".to_string(),
                      format!("\"{}\"", msg.replace("\"", "\\\""))),
                     ("shape".to_owned(), "box".to_owned()),
                     ("style".to_owned(), "filled".to_owned()),
                     ("color".to_owned(), "black".to_owned()),
                     ("fillcolor".to_owned(), "greenyellow".to_owned())]
            }
            NodeData::Phi(_, _) => {
                let mut attrs = Vec::new();
                let mut label = format!("{:?}", node);
                label = label.replace("\"", "\\\"");
                label = format!("\"{}\"", label);
                if let Some(addr) = self.addr(i) {
                    label = format!("<{}:  {}>", addr, label);
                }
                attrs.push(("label".to_string(), label));
                attrs.push(("style".to_owned(), "filled".to_owned()));
                attrs.push(("color".to_owned(), "black".to_owned()));
                if self.is_marked(i) {
                    attrs.push(("fillcolor".to_owned(), "green".to_owned()));
                } else {
                    attrs.push(("fillcolor".to_owned(), "orange".to_owned()));
                }
                attrs
            }
            _ => {
                let mut attrs = Vec::new();
                let mut label = format!("{:?}", node);
                label = label.replace("\"", "\\\"");
                label = format!("\"{}\"", label);
                if let Some(addr) = self.addr(i) {
                    label = format!("<{}:  {}>", addr, label);
                }
                attrs.push(("label".to_string(), label));
                attrs.push(("style".to_owned(), "filled".to_owned()));
                attrs.push(("color".to_owned(), "black".to_owned()));
                if self.is_marked(i) {
                    attrs.push(("fillcolor".to_owned(), "green".to_owned()));
                } else {
                    attrs.push(("fillcolor".to_owned(), "grey90".to_owned()));
                }
                attrs
            }
        };
        DotAttrBlock::Hybrid(prefix, attr)
    }
}
<|endoftext|>


<commit_before>//! Models about OAuth2 applications.

use std::fmt;

use super::{id::UserId, user::User, utils::*};

/// Information about a user's application. An application does not necessarily
/// have an associated bot user.
#[derive(Clone, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ApplicationInfo {
    /// The bot user associated with the application. See [`BotApplication`] for
    /// more information.
    pub bot: Option<BotApplication>,
    /// Indicator of whether the bot is public.
    ///
    /// If a bot is public, anyone may invite it to their [`Guild`]. While a bot
    /// is private, only the owner may add it to a guild.
    ///
    /// [`Guild`]: super::guild::Guild
    #[serde(default = "default_true")]
    pub bot_public: bool,
    /// Indicator of whether the bot requires an OAuth2 code grant.
    pub bot_require_code_grant: bool,
    /// A description of the application, assigned by the application owner.
    pub description: String,
    /// A set of bitflags assigned to the application, which represent gated
    /// feature flags that have been enabled for the application.
    pub flags: Option<u64>,
    /// A hash pointing to the application's icon.
    ///
    /// This is not necessarily equivalent to the bot user's avatar.
    pub icon: Option<String>,
    /// The unique numeric Id of the application.
    pub id: UserId,
    /// The name assigned to the application by the application owner.
    pub name: String,
    /// A list of redirect URIs assigned to the application.
    pub redirect_uris: Vec<String>,
    /// A list of RPC Origins assigned to the application.
    pub rpc_origins: Vec<String>,
    /// The application team group.
    pub team: Option<Vec<Team>>,
    /// The given secret to the application.
    ///
    /// This is not equivalent to the application's bot user's token.
    pub secret: String,
}

impl fmt::Debug for ApplicationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ApplicationInfo")
            .field("bot", &self.bot)
            .field("bot_public", &self.bot_public)
            .field("bot_require_code_grant", &self.bot_require_code_grant)
            .field("description", &self.description)
            .field("flags", &self.flags)
            .field("icon", &self.icon)
            .field("id", &self.id)
            .field("name", &self.name)
            .field("redirect_uris", &self.redirect_uris)
            .field("rpc_origins", &self.rpc_origins)
            .field("team", &self.team)
            .finish()
    }
}

/// Information about an application with an application's bot user.
#[derive(Clone, Deserialize, Serialize)]
#[non_exhaustive]
pub struct BotApplication {
    /// The unique Id of the bot user.
    pub id: UserId,
    /// A hash of the avatar, if one is assigned.
    ///
    /// Can be used to generate a full URL to the avatar.
    pub avatar: Option<String>,
    /// Indicator of whether it is a bot.
    #[serde(default)]
    pub bot: bool,
    /// The discriminator assigned to the bot user.
    ///
    /// While discriminators are not unique, the `username#discriminator` pair
    /// is.
    pub discriminator: u16,
    /// The bot user's username.
    pub name: String,
    /// The token used to authenticate as the bot user.
    ///
    /// **Note**: Keep this information private, as untrusted sources can use it
    /// to perform any action with a bot user.
    pub token: String,
}

impl fmt::Debug for BotApplication {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("BotApplication")
            .field("id", &self.id)
            .field("avatar", &self.avatar)
            .field("bot", &self.bot)
            .field("discriminator", &self.discriminator)
            .field("name", &self.name)
            .finish()
    }
}

/// Partial information about the given application.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PartialCurrentApplicationInfo {
    /// The unique Id of the user.
    pub id: UserId,
    /// The flags associated with the application.
    ///
    /// These flags are unknown and are not yet documented in the Discord API
    /// documentation.
    pub flags: u64,
}

/// Information about the current application and its owner.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct CurrentApplicationInfo {
    pub description: String,
    pub icon: Option<String>,
    pub id: UserId,
    pub name: String,
    pub owner: User,
    #[serde(default)]
    pub rpc_origins: Vec<String>,
    pub bot_public: bool,
    pub bot_require_code_grant: bool,
    pub team: Option<Team>,
}

/// Information about the Team group of the application.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Team {
    /// The icon of the team.
    pub icon: Option<String>,
    /// The snowflake ID of the team.
    #[serde(deserialize_with = "deserialize_u64")]
    pub id: u64,
    /// The members of the team
    pub members: Vec<TeamMember>,
    /// The user id of the team owner.
    pub owner_user_id: UserId,
}

/// Infromation about a Member on a Team.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TeamMember {
    /// The member's membership state.
    pub membership_state: MembershipState,
    /// The list of permissions of the member on the team.
    ///
    /// NOTE: Will always be ["*"] for now.
    pub permissions: Vec<String>,
    /// The ID of the team they are a member of.
    #[serde(deserialize_with = "deserialize_u64")]
    pub team_id: u64,
    /// The user type of the team member.
    pub user: User,
}

#[derive(Clone, Debug, Copy, PartialEq)]
pub enum MembershipState {
    Invited = 1,
    Accepted = 2,
    Unknown = !0,
}

enum_number!(MembershipState {
    Invited,
    Accepted
});
<commit_msg>Support the `Team::name` field (#1334)<commit_after>//! Models about OAuth2 applications.

use std::fmt;

use super::{id::UserId, user::User, utils::*};

/// Information about a user's application. An application does not necessarily
/// have an associated bot user.
#[derive(Clone, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ApplicationInfo {
    /// The bot user associated with the application. See [`BotApplication`] for
    /// more information.
    pub bot: Option<BotApplication>,
    /// Indicator of whether the bot is public.
    ///
    /// If a bot is public, anyone may invite it to their [`Guild`]. While a bot
    /// is private, only the owner may add it to a guild.
    ///
    /// [`Guild`]: super::guild::Guild
    #[serde(default = "default_true")]
    pub bot_public: bool,
    /// Indicator of whether the bot requires an OAuth2 code grant.
    pub bot_require_code_grant: bool,
    /// A description of the application, assigned by the application owner.
    pub description: String,
    /// A set of bitflags assigned to the application, which represent gated
    /// feature flags that have been enabled for the application.
    pub flags: Option<u64>,
    /// A hash pointing to the application's icon.
    ///
    /// This is not necessarily equivalent to the bot user's avatar.
    pub icon: Option<String>,
    /// The unique numeric Id of the application.
    pub id: UserId,
    /// The name assigned to the application by the application owner.
    pub name: String,
    /// A list of redirect URIs assigned to the application.
    pub redirect_uris: Vec<String>,
    /// A list of RPC Origins assigned to the application.
    pub rpc_origins: Vec<String>,
    /// The application team group.
    pub team: Option<Vec<Team>>,
    /// The given secret to the application.
    ///
    /// This is not equivalent to the application's bot user's token.
    pub secret: String,
}

impl fmt::Debug for ApplicationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ApplicationInfo")
            .field("bot", &self.bot)
            .field("bot_public", &self.bot_public)
            .field("bot_require_code_grant", &self.bot_require_code_grant)
            .field("description", &self.description)
            .field("flags", &self.flags)
            .field("icon", &self.icon)
            .field("id", &self.id)
            .field("name", &self.name)
            .field("redirect_uris", &self.redirect_uris)
            .field("rpc_origins", &self.rpc_origins)
            .field("team", &self.team)
            .finish()
    }
}

/// Information about an application with an application's bot user.
#[derive(Clone, Deserialize, Serialize)]
#[non_exhaustive]
pub struct BotApplication {
    /// The unique Id of the bot user.
    pub id: UserId,
    /// A hash of the avatar, if one is assigned.
    ///
    /// Can be used to generate a full URL to the avatar.
    pub avatar: Option<String>,
    /// Indicator of whether it is a bot.
    #[serde(default)]
    pub bot: bool,
    /// The discriminator assigned to the bot user.
    ///
    /// While discriminators are not unique, the `username#discriminator` pair
    /// is.
    pub discriminator: u16,
    /// The bot user's username.
    pub name: String,
    /// The token used to authenticate as the bot user.
    ///
    /// **Note**: Keep this information private, as untrusted sources can use it
    /// to perform any action with a bot user.
    pub token: String,
}

impl fmt::Debug for BotApplication {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("BotApplication")
            .field("id", &self.id)
            .field("avatar", &self.avatar)
            .field("bot", &self.bot)
            .field("discriminator", &self.discriminator)
            .field("name", &self.name)
            .finish()
    }
}

/// Partial information about the given application.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PartialCurrentApplicationInfo {
    /// The unique Id of the user.
    pub id: UserId,
    /// The flags associated with the application.
    ///
    /// These flags are unknown and are not yet documented in the Discord API
    /// documentation.
    pub flags: u64,
}

/// Information about the current application and its owner.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct CurrentApplicationInfo {
    pub description: String,
    pub icon: Option<String>,
    pub id: UserId,
    pub name: String,
    pub owner: User,
    #[serde(default)]
    pub rpc_origins: Vec<String>,
    pub bot_public: bool,
    pub bot_require_code_grant: bool,
    pub team: Option<Team>,
}

/// Information about the Team group of the application.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Team {
    /// The icon of the team.
    pub icon: Option<String>,
    /// The snowflake ID of the team.
    #[serde(deserialize_with = "deserialize_u64")]
    pub id: u64,
    /// The name of the team.
    pub name: String,
    /// The members of the team
    pub members: Vec<TeamMember>,
    /// The user id of the team owner.
    pub owner_user_id: UserId,
}

/// Infromation about a Member on a Team.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TeamMember {
    /// The member's membership state.
    pub membership_state: MembershipState,
    /// The list of permissions of the member on the team.
    ///
    /// NOTE: Will always be ["*"] for now.
    pub permissions: Vec<String>,
    /// The ID of the team they are a member of.
    #[serde(deserialize_with = "deserialize_u64")]
    pub team_id: u64,
    /// The user type of the team member.
    pub user: User,
}

#[derive(Clone, Debug, Copy, PartialEq)]
pub enum MembershipState {
    Invited = 1,
    Accepted = 2,
    Unknown = !0,
}

enum_number!(MembershipState {
    Invited,
    Accepted
});
<|endoftext|>