<commit_before>// run-pass
// only-linux - pidfds are a linux-specific concept

#![feature(linux_pidfd)]
use std::os::linux::process::{CommandExt, ChildExt};
use std::process::Command;

fn main() {
    // We don't assert the precise value, since the standard library
    // might have opened other file descriptors before our code runs.
    let _ = Command::new("echo")
        .create_pidfd(true)
        .spawn()
        .unwrap()
        .pidfd().expect("failed to obtain pidfd");

    let _ = Command::new("echo")
        .create_pidfd(false)
        .spawn()
        .unwrap()
        .pidfd().expect_err("pidfd should not have been created when create_pid(false) is set");

    let _ = Command::new("echo")
        .spawn()
        .unwrap()
        .pidfd().expect_err("pidfd should not have been created");
}
<commit_msg>Check whether clone3 syscall exists in pidfd test<commit_after>// run-pass
// only-linux - pidfds are a linux-specific concept

#![feature(linux_pidfd)]
#![feature(rustc_private)]

extern crate libc;

use std::io::Error;
use std::os::linux::process::{ChildExt, CommandExt};
use std::process::Command;

fn has_clone3() -> bool {
    let res = unsafe { libc::syscall(libc::SYS_clone3, 0, 0) };
    let err = (res == -1)
        .then(|| Error::last_os_error())
        .expect("probe syscall should not succeed");
    err.raw_os_error() != Some(libc::ENOSYS)
}

fn main() {
    // pidfds require the clone3 syscall
    if !has_clone3() {
        return;
    }

    // We don't assert the precise value, since the standard library
    // might have opened other file descriptors before our code runs.
    let _ = Command::new("echo")
        .create_pidfd(true)
        .spawn()
        .unwrap()
        .pidfd().expect("failed to obtain pidfd");

    let _ = Command::new("echo")
        .create_pidfd(false)
        .spawn()
        .unwrap()
        .pidfd().expect_err("pidfd should not have been created when create_pid(false) is set");

    let _ = Command::new("echo")
        .spawn()
        .unwrap()
        .pidfd().expect_err("pidfd should not have been created");
}
<|endoftext|>


<commit_before>use cube_shell::cube_shell;
use id_allocator::IdAllocator;
use terrain_vram_buffers::TerrainVRAMBuffers;
use terrain::BlockPosition;
use terrain::Terrain;
use physics::Physics;
use state::EntityId;
use std::collections::HashSet;
use std::collections::RingBuf;
use std::iter::range_inclusive;
use stopwatch::TimerSet;
use yaglw::gl_context::GLContext;

pub const BLOCK_LOAD_SPEED: uint = 8;
pub const LOAD_DISTANCE: int = 10;

/// Keep surroundings loaded around a given world position.
pub struct SurroundingsLoader<'a> {
  pub terrain: Terrain<'a>,

  pub load_queue: RingBuf<BlockPosition>,
  pub unload_queue: RingBuf<BlockPosition>,

  // the set of blocks that are currently loaded
  pub loaded: HashSet<BlockPosition>,
  // The set of all blocks we want loaded.
  pub want_loaded: HashSet<BlockPosition>,

  pub last_position: Option<BlockPosition>,
}

impl<'a> SurroundingsLoader<'a> {
  pub fn new() -> SurroundingsLoader<'a> {
    SurroundingsLoader {
      terrain: Terrain::new(),

      load_queue: RingBuf::new(),
      unload_queue: RingBuf::new(),

      loaded: HashSet::new(),
      want_loaded: HashSet::new(),

      last_position: None,
    }
  }

  pub fn update(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    terrain_buffers: &mut TerrainVRAMBuffers<'a>,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics<EntityId>,
    position: BlockPosition,
  ) {
    timers.time("update.update_queues", || {
      self.update_queues(timers, position);
    });
    timers.time("update.load_some", || {
      self.load_some(timers, gl, terrain_buffers, id_allocator, physics);
    });
  }

  #[inline]
  fn update_queues(&mut self, timers: &TimerSet, block_position: BlockPosition) {
    if Some(block_position) != self.last_position {
      self.last_position = Some(block_position);

      // TODO: Order this in rings around block_position.
      let mut want_loaded = Vec::new();
      let mut want_loaded_set = HashSet::new();

      timers.time("update.update_queues.want_loaded", || {
        want_loaded.push(block_position);
        want_loaded_set.insert(block_position);

        for radius in range_inclusive(1, LOAD_DISTANCE) {
          let blocks_at_radius = cube_shell(block_position, radius);
          want_loaded.push_all(blocks_at_radius.as_slice());
          for block_position in blocks_at_radius.into_iter() {
            want_loaded_set.insert(block_position);
          }
        }
      });

      self.load_queue.clear();

      timers.time("update.update_queues.unload_queue", || {
        for block_position in self.want_loaded.iter() {
          let is_loaded = self.loaded.contains(block_position);
          if is_loaded {
            let is_needed = want_loaded_set.contains(block_position);
            if !is_needed {
              self.unload_queue.push_back(*block_position);
            }
          }
        }
      });

      timers.time("update.update_queues.load_queue", || {
        for block_position in want_loaded.iter() {
          let is_loaded = self.loaded.contains(block_position);
          if !is_loaded {
            self.load_queue.push_back(*block_position);
          }
        }
      });

      self.want_loaded = want_loaded_set;
    }
  }

  #[inline]
  fn load_some(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    terrain_buffers: &mut TerrainVRAMBuffers<'a>,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics<EntityId>,
  ) {
    for _ in range(0, BLOCK_LOAD_SPEED) {
      match self.unload_queue.pop_front() {
        None =>
          match self.load_queue.pop_front() {
            None => {
              break;
            },
            Some(block_position) => {
              timers.time("update.load_some.load", || {
                let block = self.terrain.load(timers, id_allocator, &block_position);

                timers.time("update.load_some.load.physics", || {
                  for (&id, bounds) in block.bounds.iter() {
                    physics.insert(id, bounds);
                  }
                });

                timers.time("update.load_some.load.vram", || {
                  terrain_buffers.push(
                    gl,
                    block.vertices.as_slice(),
                    block.normals.as_slice(),
                    block.typs.as_slice(),
                    block.ids.as_slice(),
                  );
                });
              });

              self.loaded.insert(block_position);
            },
          },
        Some(block_position) => {
          timers.time("update.load_some.unload", || {
            let block = self.terrain.all_blocks.get(&block_position).unwrap();
            for id in block.ids.iter() {
              physics.remove(*id);
              terrain_buffers.swap_remove(gl, *id);
            }

            self.loaded.remove(&block_position);
          })
        }
      }
    }
  }
}
<commit_msg>add a terrain load budget: loads and unloads cost different amounts<commit_after>use cube_shell::cube_shell;
use id_allocator::IdAllocator;
use terrain_vram_buffers::TerrainVRAMBuffers;
use terrain::BlockPosition;
use terrain::Terrain;
use physics::Physics;
use state::EntityId;
use std::collections::HashSet;
use std::collections::RingBuf;
use std::iter::range_inclusive;
use stopwatch::TimerSet;
use yaglw::gl_context::GLContext;

pub const LOAD_DISTANCE: int = 10;

pub const BLOCK_UPDATE_BUDGET: int = 16;
pub const BLOCK_LOAD_COST: int = 2;
pub const BLOCK_UNLOAD_COST: int = 1;

/// Keep surroundings loaded around a given world position.
pub struct SurroundingsLoader<'a> {
  pub terrain: Terrain<'a>,

  pub load_queue: RingBuf<BlockPosition>,
  pub unload_queue: RingBuf<BlockPosition>,

  // the set of blocks that are currently loaded
  pub loaded: HashSet<BlockPosition>,
  // The set of all blocks we want loaded.
  pub want_loaded: HashSet<BlockPosition>,

  pub last_position: Option<BlockPosition>,
}

impl<'a> SurroundingsLoader<'a> {
  pub fn new() -> SurroundingsLoader<'a> {
    SurroundingsLoader {
      terrain: Terrain::new(),

      load_queue: RingBuf::new(),
      unload_queue: RingBuf::new(),

      loaded: HashSet::new(),
      want_loaded: HashSet::new(),

      last_position: None,
    }
  }

  pub fn update(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    terrain_buffers: &mut TerrainVRAMBuffers<'a>,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics<EntityId>,
    position: BlockPosition,
  ) {
    timers.time("update.update_queues", || {
      self.update_queues(timers, position);
    });
    timers.time("update.load_some", || {
      self.load_some(timers, gl, terrain_buffers, id_allocator, physics);
    });
  }

  #[inline]
  fn update_queues(&mut self, timers: &TimerSet, block_position: BlockPosition) {
    if Some(block_position) != self.last_position {
      self.last_position = Some(block_position);

      // TODO: Order this in rings around block_position.
      let mut want_loaded = Vec::new();
      let mut want_loaded_set = HashSet::new();

      timers.time("update.update_queues.want_loaded", || {
        want_loaded.push(block_position);
        want_loaded_set.insert(block_position);

        for radius in range_inclusive(1, LOAD_DISTANCE) {
          let blocks_at_radius = cube_shell(block_position, radius);
          want_loaded.push_all(blocks_at_radius.as_slice());
          for block_position in blocks_at_radius.into_iter() {
            want_loaded_set.insert(block_position);
          }
        }
      });

      self.load_queue.clear();

      timers.time("update.update_queues.unload_queue", || {
        for block_position in self.want_loaded.iter() {
          let is_loaded = self.loaded.contains(block_position);
          if is_loaded {
            let is_needed = want_loaded_set.contains(block_position);
            if !is_needed {
              self.unload_queue.push_back(*block_position);
            }
          }
        }
      });

      timers.time("update.update_queues.load_queue", || {
        for block_position in want_loaded.iter() {
          let is_loaded = self.loaded.contains(block_position);
          if !is_loaded {
            self.load_queue.push_back(*block_position);
          }
        }
      });

      self.want_loaded = want_loaded_set;
    }
  }

  #[inline]
  fn load_some(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    terrain_buffers: &mut TerrainVRAMBuffers<'a>,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics<EntityId>,
  ) {
    let mut budget = BLOCK_UPDATE_BUDGET;
    while budget > 0 {
      match self.unload_queue.pop_front() {
        None =>
          match self.load_queue.pop_front() {
            None => {
              break;
            },
            Some(block_position) => {
              timers.time("update.load_some.load", || {
                let block = self.terrain.load(timers, id_allocator, &block_position);

                timers.time("update.load_some.load.physics", || {
                  for (&id, bounds) in block.bounds.iter() {
                    physics.insert(id, bounds);
                  }
                });

                timers.time("update.load_some.load.vram", || {
                  terrain_buffers.push(
                    gl,
                    block.vertices.as_slice(),
                    block.normals.as_slice(),
                    block.typs.as_slice(),
                    block.ids.as_slice(),
                  );
                });
              });

              self.loaded.insert(block_position);
              budget -= BLOCK_LOAD_COST;
            },
          },
        Some(block_position) => {
          timers.time("update.load_some.unload", || {
            let block = self.terrain.all_blocks.get(&block_position).unwrap();
            for id in block.ids.iter() {
              physics.remove(*id);
              terrain_buffers.swap_remove(gl, *id);
            }

            self.loaded.remove(&block_position);
            budget -= BLOCK_UNLOAD_COST;
          })
        }
      }
    }
  }
}
<|endoftext|>


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

use bindgen::callbacks::{IntKind, ParseCallbacks};
use proc_macro2::Span;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Mutex;

/// Keeps track of all known preprocessor invocations.
#[derive(Debug, Default)]
pub(crate) struct PreprocessorDefinitions {
    integral: HashMap<String, i64>,
    string: HashMap<String, Vec<u8>>,
}

impl PreprocessorDefinitions {
    pub fn new() -> Self {
        PreprocessorDefinitions {
            integral: HashMap::new(),
            string: HashMap::new(),
        }
    }

    fn insert_int_macro(&mut self, name: &str, val: i64) {
        self.integral.insert(name.to_string(), val);
    }

    fn insert_str_macro(&mut self, name: &str, val: &[u8]) {
        self.string.insert(name.to_string(), val.to_vec());
    }

    pub fn to_tokenstream(&self) -> TokenStream2 {
        if self.integral.is_empty() && self.string.is_empty() {
            TokenStream2::new()
        } else {
            let span = Span::call_site();
            let idefs = self.integral.iter().map(|(k, v)| {
                let k = syn::Ident::new(k, span);
                quote! {
                    pub const #k: i64 = #v;
                }
            });
            let sdefs = self.string.iter().filter_map(|(k, v)| {
                let k = syn::Ident::new(k, span);
                // TODO _consider_ doing something with non-UTF8 string values. I'm not sure what.
                String::from_utf8(v.clone()).ok().and_then(|v| {
                    Some(quote! {
                        pub const #k: &'static str = #v;
                    })
                })
            });
            let r = quote! {
                mod ffidefs {
                    #(#idefs)*
                    #(#sdefs)*
                }
            };
            r
        }
    }
}

/// Callbacks for bindgen.
#[derive(Debug)]
pub(crate) struct PreprocessorParseCallbacks {
    // We use a mutex rather than a RefCell not because we need thread
    // safety, but because we need poisoning in order to avoid problems
    // with UnwindSafe.
    definitions: Rc<Mutex<PreprocessorDefinitions>>,
}

impl PreprocessorParseCallbacks {
    pub fn new(definitions: Rc<Mutex<PreprocessorDefinitions>>) -> Self {
        PreprocessorParseCallbacks { definitions }
    }

    fn get_defs(&self) -> std::sync::MutexGuard<PreprocessorDefinitions> {
        self.definitions
            .try_lock()
            .expect("would block whilst adding macro")
    }
}

impl ParseCallbacks for PreprocessorParseCallbacks {
    fn int_macro(&self, name: &str, value: i64) -> Option<IntKind> {
        self.get_defs().insert_int_macro(name, value);
        None
    }

    fn str_macro(&self, name: &str, value: &[u8]) {
        self.get_defs().insert_str_macro(name, value)
    }
}
<commit_msg>Small adjustment.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use bindgen::callbacks::{IntKind, ParseCallbacks};
use proc_macro2::Span;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Mutex;

/// Keeps track of all known preprocessor invocations.
#[derive(Debug, Default)]
pub(crate) struct PreprocessorDefinitions {
    integral: HashMap<String, i64>,
    string: HashMap<String, Vec<u8>>,
}

impl PreprocessorDefinitions {
    pub fn new() -> Self {
        PreprocessorDefinitions {
            integral: HashMap::new(),
            string: HashMap::new(),
        }
    }

    fn insert_int_macro(&mut self, name: &str, val: i64) {
        self.integral.insert(name.to_string(), val);
    }

    fn insert_str_macro(&mut self, name: &str, val: &[u8]) {
        self.string.insert(name.to_string(), val.to_vec());
    }

    pub fn to_tokenstream(&self) -> TokenStream2 {
        if self.integral.is_empty() && self.string.is_empty() {
            TokenStream2::new()
        } else {
            let span = Span::call_site();
            let idefs = self.integral.iter().map(|(k, v)| {
                let k = syn::Ident::new(k, span);
                quote! {
                    pub const #k: i64 = #v;
                }
            });
            let sdefs = self.string.iter().filter_map(|(k, v)| {
                let k = syn::Ident::new(k, span);
                // TODO _consider_ doing something with non-UTF8 string values. I'm not sure what.
                String::from_utf8(v.clone()).ok().and_then(|v| {
                    Some(quote! {
                        pub const #k: &'static str = #v;
                    })
                })
            });
            quote! {
                mod ffidefs {
                    #(#idefs)*
                    #(#sdefs)*
                }
            }
        }
    }
}

/// Callbacks for bindgen.
#[derive(Debug)]
pub(crate) struct PreprocessorParseCallbacks {
    // We use a mutex rather than a RefCell not because we need thread
    // safety, but because we need poisoning in order to avoid problems
    // with UnwindSafe.
    definitions: Rc<Mutex<PreprocessorDefinitions>>,
}

impl PreprocessorParseCallbacks {
    pub fn new(definitions: Rc<Mutex<PreprocessorDefinitions>>) -> Self {
        PreprocessorParseCallbacks { definitions }
    }

    fn get_defs(&self) -> std::sync::MutexGuard<PreprocessorDefinitions> {
        self.definitions
            .try_lock()
            .expect("would block whilst adding macro")
    }
}

impl ParseCallbacks for PreprocessorParseCallbacks {
    fn int_macro(&self, name: &str, value: i64) -> Option<IntKind> {
        self.get_defs().insert_int_macro(name, value);
        None
    }

    fn str_macro(&self, name: &str, value: &[u8]) {
        self.get_defs().insert_str_macro(name, value)
    }
}
<|endoftext|>


<commit_before>// A variation on cares-event-loop.rs.
//
// Here we:
//
// - Have the event loop take an `Arc<Mutex<Channel>>`, so that even after it
// is running we still have the ability to submit new queries
//
// - Have the event loop be run by a `Resolver`, hiding away the event loop
// details from the writer of `main()`.
//
// - Show one way of transforming the asynchronous c-ares interface into
// a synchronous, blocking interface by using a std::sync::mpsc::channel.
extern crate c_ares;
extern crate mio;

use std::collections::HashSet;
use std::error::Error;
use std::sync::{
    Arc,
    Mutex,
    mpsc,
};
use std::thread;

// Messages for the event loop.
enum CAresHandlerMessage {
    // 'Notify me when this file descriptor becomes readable, or writable'.
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(c_ares::Socket, bool, bool),

    // 'Shut down'.
    ShutDown,
}

struct CAresEventHandler {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    tracked_fds: HashSet<c_ares::Socket>,
}

impl CAresEventHandler {
    fn new(ares_channel: Arc<Mutex<c_ares::Channel>>) -> CAresEventHandler {
        CAresEventHandler {
            ares_channel: ares_channel,
            tracked_fds: HashSet::new(),
        }
    }
}

impl mio::Handler for CAresEventHandler {
    type Timeout = ();
    type Message = CAresHandlerMessage;

    // mio notifies us that a file descriptor is readable or writable, so we
    // tell the Channel the same.
    fn ready(
        &mut self,
        _event_loop: &mut mio::EventLoop<CAresEventHandler>,
        token: mio::Token,
        events: mio::EventSet) {
        let fd = token.as_usize() as c_ares::Socket;
        let read_fd = if events.is_readable() {
            fd
        } else {
            c_ares::SOCKET_BAD
        };
        let write_fd = if events.is_writable() {
            fd
        } else {
            c_ares::SOCKET_BAD
        };
        self.ares_channel.lock().unwrap().process_fd(read_fd, write_fd);
    }

    // Process received messages.  Either:
    // - we're asked to register interest (or non-interest) in a file
    // descriptor
    // - we're asked to shut down the event loop.
    fn notify(
        &mut self,
        event_loop:&mut mio::EventLoop<CAresEventHandler>,
        msg: Self::Message) {
        match msg {
            CAresHandlerMessage::RegisterInterest(fd, read, write) => {
                let efd = mio::unix::EventedFd(&fd);
                if !read && !write {
                    self.tracked_fds.remove(&fd);
                    event_loop
                        .deregister(&efd)
                        .expect("failed to deregister interest");
                } else {
                    let mut interest = mio::EventSet::none();
                    if read{
                        interest = interest | mio::EventSet::readable();
                    }
                    if write {
                        interest = interest | mio::EventSet::writable();
                    }
                    let token = mio::Token(fd as usize);
                    let register_result = if !self.tracked_fds.insert(fd) {
                        event_loop
                            .reregister(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::edge())
                   } else {
                        event_loop
                            .register(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::edge())
                    };
                    register_result.expect("failed to register interest");
                }
            },

            CAresHandlerMessage::ShutDown => event_loop.shutdown(),
        }
    }

    // We run a recurring timer so that we can spot non-responsive servers.
    //
    // In that case we won't get a callback saying that anything is happening
    // on any file descriptor, but nevertheless need to give the Channel an
    // opportunity to notice that it has timed-out requests pending.
    fn timeout(
        &mut self,
        event_loop: &mut mio::EventLoop<CAresEventHandler>,
        _timeout: Self::Timeout) {
        event_loop.timeout_ms((), 500).unwrap();
        self.ares_channel
            .lock()
            .unwrap()
            .process_fd(c_ares::SOCKET_BAD, c_ares::SOCKET_BAD);
    }
}

struct Resolver {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    event_loop_channel: mio::Sender<CAresHandlerMessage>,
    event_loop_handle: Option<thread::JoinHandle<()>>,
}

impl Resolver {
    // Create a new Resolver.
    pub fn new() -> Resolver {
        // Create an event loop.
        let mut event_loop = mio::EventLoop::new()
            .expect("failed to create event loop");
        let event_loop_channel = event_loop.channel();

        // Socket state callback for the c_ares::Channel will be to kick the
        // event loop.
        let event_loop_channel_clone = event_loop_channel.clone();
        let sock_callback =
            move |sock: c_ares::Socket, readable: bool, writable: bool| {
                let _ = event_loop_channel_clone
                    .send(
                        CAresHandlerMessage::RegisterInterest(
                            sock,
                            readable,
                            writable));
            };

        // Create a c_ares::Channel.
        let mut options = c_ares::Options::new();
        options
            .set_socket_state_callback(sock_callback)
            .set_flags(c_ares::flags::STAYOPEN | c_ares::flags::EDNS)
            .set_timeout(500)
            .set_tries(3);
        let mut ares_channel = c_ares::Channel::new(options)
            .expect("Failed to create channel");
        ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Set the first instance of the recurring timer on the event loop.
        event_loop.timeout_ms((), 500).unwrap();

        // Kick off the event loop.
        let mut event_handler = CAresEventHandler::new(locked_channel.clone());
        let event_loop_handle = thread::spawn(move || {
            event_loop
                .run(&mut event_handler)
                .expect("failed to run event loop")
        });

        Resolver {
            ares_channel: locked_channel,
            event_loop_channel: event_loop_channel,
            event_loop_handle: Some(event_loop_handle),
        }
    }

    // A blocking CNAME query.  Achieve this by having the callback send the
    // result to a std::sync::mpsc::channel, and waiting on that channel.
    pub fn query_cname(&self, name: &str)
        -> Result<c_ares::CNameResults, c_ares::AresError> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_cname(name, move |result| {
            tx.send(result).unwrap();
        });
        rx.recv().unwrap()
    }

    // A blocking MX query.
    pub fn query_mx(&self, name: &str)
        -> Result<c_ares::MXResults, c_ares::AresError> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_mx(name, move |result| {
            tx.send(result).unwrap();
        });
        rx.recv().unwrap()
    }

    // A blocking NAPTR query.
    pub fn query_naptr(&self, name: &str)
        -> Result<c_ares::NAPTRResults, c_ares::AresError> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_naptr(name, move |result| {
            tx.send(result).unwrap();
        });
        rx.recv().unwrap()
    }
}

impl Drop for Resolver {
    fn drop(&mut self) {
        // Shut down the event loop and wait for it to finish.
        self.event_loop_channel
            .send(CAresHandlerMessage::ShutDown)
            .expect("failed to shut down event loop");
       for handle in self.event_loop_handle.take() {
           handle.join().unwrap();
       }
    }
}

fn print_cname_result(
    result: Result<c_ares::CNameResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("CNAME lookup failed with error '{}'", e.description());
        }
        Ok(cname_results) => {
            println!("Successful CNAME lookup...");
            println!("Hostname: {}", cname_results.hostname());
            for alias in cname_results.aliases() {
                println!("Alias: {}", alias);
            }
        }
    }
}

fn print_mx_results(result: Result<c_ares::MXResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("MX lookup failed with error '{}'", e.description());
        }
        Ok(mx_results) => {
            println!("Successful MX lookup...");
            for mx_result in &mx_results {
                println!(
                    "host {}, priority {}",
                    mx_result.host(),
                    mx_result.priority());
            }
        }
    }
}

fn print_naptr_results(
    result: Result<c_ares::NAPTRResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("NAPTR lookup failed with error '{}'", e.description());
        }
        Ok(naptr_results) => {
            println!("Successful NAPTR lookup...");
            for naptr_result in &naptr_results {
                println!("flags: {}", naptr_result.flags());
                println!("service name: {}", naptr_result.service_name());
                println!("regular expression: {}", naptr_result.reg_exp());
                println!(
                    "replacement pattern: {}",
                    naptr_result.replacement_pattern());
                println!("order: {}", naptr_result.order());
                println!("preference: {}", naptr_result.preference());
            }
        }
    }
}

pub fn main() {
    // Create a Resolver.  Then make some requests.
    let resolver = Resolver::new();
    let result = resolver.query_cname("dimbleby.github.io");
    println!("");
    print_cname_result(result);

    let result = resolver.query_mx("gmail.com");
    println!("");
    print_mx_results(result);

    let result = resolver.query_naptr("4.3.2.1.5.5.5.0.0.8.1.e164.arpa");
    println!("");
    print_naptr_results(result);
}
<commit_msg>A NAPTR example that resolves to something<commit_after>// A variation on cares-event-loop.rs.
//
// Here we:
//
// - Have the event loop take an `Arc<Mutex<Channel>>`, so that even after it
// is running we still have the ability to submit new queries
//
// - Have the event loop be run by a `Resolver`, hiding away the event loop
// details from the writer of `main()`.
//
// - Show one way of transforming the asynchronous c-ares interface into
// a synchronous, blocking interface by using a std::sync::mpsc::channel.
extern crate c_ares;
extern crate mio;

use std::collections::HashSet;
use std::error::Error;
use std::sync::{
    Arc,
    Mutex,
    mpsc,
};
use std::thread;

// Messages for the event loop.
enum CAresHandlerMessage {
    // 'Notify me when this file descriptor becomes readable, or writable'.
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(c_ares::Socket, bool, bool),

    // 'Shut down'.
    ShutDown,
}

struct CAresEventHandler {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    tracked_fds: HashSet<c_ares::Socket>,
}

impl CAresEventHandler {
    fn new(ares_channel: Arc<Mutex<c_ares::Channel>>) -> CAresEventHandler {
        CAresEventHandler {
            ares_channel: ares_channel,
            tracked_fds: HashSet::new(),
        }
    }
}

impl mio::Handler for CAresEventHandler {
    type Timeout = ();
    type Message = CAresHandlerMessage;

    // mio notifies us that a file descriptor is readable or writable, so we
    // tell the Channel the same.
    fn ready(
        &mut self,
        _event_loop: &mut mio::EventLoop<CAresEventHandler>,
        token: mio::Token,
        events: mio::EventSet) {
        let fd = token.as_usize() as c_ares::Socket;
        let read_fd = if events.is_readable() {
            fd
        } else {
            c_ares::SOCKET_BAD
        };
        let write_fd = if events.is_writable() {
            fd
        } else {
            c_ares::SOCKET_BAD
        };
        self.ares_channel.lock().unwrap().process_fd(read_fd, write_fd);
    }

    // Process received messages.  Either:
    // - we're asked to register interest (or non-interest) in a file
    // descriptor
    // - we're asked to shut down the event loop.
    fn notify(
        &mut self,
        event_loop:&mut mio::EventLoop<CAresEventHandler>,
        msg: Self::Message) {
        match msg {
            CAresHandlerMessage::RegisterInterest(fd, read, write) => {
                let efd = mio::unix::EventedFd(&fd);
                if !read && !write {
                    self.tracked_fds.remove(&fd);
                    event_loop
                        .deregister(&efd)
                        .expect("failed to deregister interest");
                } else {
                    let mut interest = mio::EventSet::none();
                    if read{
                        interest = interest | mio::EventSet::readable();
                    }
                    if write {
                        interest = interest | mio::EventSet::writable();
                    }
                    let token = mio::Token(fd as usize);
                    let register_result = if !self.tracked_fds.insert(fd) {
                        event_loop
                            .reregister(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::edge())
                   } else {
                        event_loop
                            .register(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::edge())
                    };
                    register_result.expect("failed to register interest");
                }
            },

            CAresHandlerMessage::ShutDown => event_loop.shutdown(),
        }
    }

    // We run a recurring timer so that we can spot non-responsive servers.
    //
    // In that case we won't get a callback saying that anything is happening
    // on any file descriptor, but nevertheless need to give the Channel an
    // opportunity to notice that it has timed-out requests pending.
    fn timeout(
        &mut self,
        event_loop: &mut mio::EventLoop<CAresEventHandler>,
        _timeout: Self::Timeout) {
        event_loop.timeout_ms((), 500).unwrap();
        self.ares_channel
            .lock()
            .unwrap()
            .process_fd(c_ares::SOCKET_BAD, c_ares::SOCKET_BAD);
    }
}

struct Resolver {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    event_loop_channel: mio::Sender<CAresHandlerMessage>,
    event_loop_handle: Option<thread::JoinHandle<()>>,
}

impl Resolver {
    // Create a new Resolver.
    pub fn new() -> Resolver {
        // Create an event loop.
        let mut event_loop = mio::EventLoop::new()
            .expect("failed to create event loop");
        let event_loop_channel = event_loop.channel();

        // Socket state callback for the c_ares::Channel will be to kick the
        // event loop.
        let event_loop_channel_clone = event_loop_channel.clone();
        let sock_callback =
            move |sock: c_ares::Socket, readable: bool, writable: bool| {
                let _ = event_loop_channel_clone
                    .send(
                        CAresHandlerMessage::RegisterInterest(
                            sock,
                            readable,
                            writable));
            };

        // Create a c_ares::Channel.
        let mut options = c_ares::Options::new();
        options
            .set_socket_state_callback(sock_callback)
            .set_flags(c_ares::flags::STAYOPEN | c_ares::flags::EDNS)
            .set_timeout(500)
            .set_tries(3);
        let mut ares_channel = c_ares::Channel::new(options)
            .expect("Failed to create channel");
        ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Set the first instance of the recurring timer on the event loop.
        event_loop.timeout_ms((), 500).unwrap();

        // Kick off the event loop.
        let mut event_handler = CAresEventHandler::new(locked_channel.clone());
        let event_loop_handle = thread::spawn(move || {
            event_loop
                .run(&mut event_handler)
                .expect("failed to run event loop")
        });

        Resolver {
            ares_channel: locked_channel,
            event_loop_channel: event_loop_channel,
            event_loop_handle: Some(event_loop_handle),
        }
    }

    // A blocking CNAME query.  Achieve this by having the callback send the
    // result to a std::sync::mpsc::channel, and waiting on that channel.
    pub fn query_cname(&self, name: &str)
        -> Result<c_ares::CNameResults, c_ares::AresError> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_cname(name, move |result| {
            tx.send(result).unwrap();
        });
        rx.recv().unwrap()
    }

    // A blocking MX query.
    pub fn query_mx(&self, name: &str)
        -> Result<c_ares::MXResults, c_ares::AresError> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_mx(name, move |result| {
            tx.send(result).unwrap();
        });
        rx.recv().unwrap()
    }

    // A blocking NAPTR query.
    pub fn query_naptr(&self, name: &str)
        -> Result<c_ares::NAPTRResults, c_ares::AresError> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_naptr(name, move |result| {
            tx.send(result).unwrap();
        });
        rx.recv().unwrap()
    }
}

impl Drop for Resolver {
    fn drop(&mut self) {
        // Shut down the event loop and wait for it to finish.
        self.event_loop_channel
            .send(CAresHandlerMessage::ShutDown)
            .expect("failed to shut down event loop");
       for handle in self.event_loop_handle.take() {
           handle.join().unwrap();
       }
    }
}

fn print_cname_result(
    result: Result<c_ares::CNameResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("CNAME lookup failed with error '{}'", e.description());
        }
        Ok(cname_results) => {
            println!("Successful CNAME lookup...");
            println!("Hostname: {}", cname_results.hostname());
            for alias in cname_results.aliases() {
                println!("Alias: {}", alias);
            }
        }
    }
}

fn print_mx_results(result: Result<c_ares::MXResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("MX lookup failed with error '{}'", e.description());
        }
        Ok(mx_results) => {
            println!("Successful MX lookup...");
            for mx_result in &mx_results {
                println!(
                    "host {}, priority {}",
                    mx_result.host(),
                    mx_result.priority());
            }
        }
    }
}

fn print_naptr_results(
    result: Result<c_ares::NAPTRResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("NAPTR lookup failed with error '{}'", e.description());
        }
        Ok(naptr_results) => {
            println!("Successful NAPTR lookup...");
            for naptr_result in &naptr_results {
                println!("flags: {}", naptr_result.flags());
                println!("service name: {}", naptr_result.service_name());
                println!("regular expression: {}", naptr_result.reg_exp());
                println!(
                    "replacement pattern: {}",
                    naptr_result.replacement_pattern());
                println!("order: {}", naptr_result.order());
                println!("preference: {}", naptr_result.preference());
            }
        }
    }
}

pub fn main() {
    // Create a Resolver.  Then make some requests.
    let resolver = Resolver::new();
    let result = resolver.query_cname("dimbleby.github.io");
    println!("");
    print_cname_result(result);

    let result = resolver.query_mx("gmail.com");
    println!("");
    print_mx_results(result);

    let result = resolver.query_naptr("apple.com");
    println!("");
    print_naptr_results(result);
}
<|endoftext|>


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

use api::{BorderRadius, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{DevicePoint, DeviceRect, DeviceSize, LayerPoint, LayerRect, LayerSize};
use api::{LayerToWorldTransform, LayoutRect, WorldRect};
use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D, TypedTransform2D};
use euclid::TypedTransform3D;
use num_traits::Zero;
use std::f32::consts::FRAC_1_SQRT_2;
use std::i32;
use std::f32;

// Matches the definition of SK_ScalarNearlyZero in Skia.
const NEARLY_ZERO: f32 = 1.0 / 4096.0;

// TODO: Implement these in euclid!
pub trait MatrixHelpers<Src, Dst> {
    fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst>;
    fn is_identity(&self) -> bool;
    fn preserves_2d_axis_alignment(&self) -> bool;
    fn has_perspective_component(&self) -> bool;
    fn has_2d_inverse(&self) -> bool;
    fn inverse_project(&self, target: &TypedPoint2D<f32, Dst>) -> Option<TypedPoint2D<f32, Src>>;
    fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> TypedRect<f32, Src>;
    fn transform_kind(&self) -> TransformedRectKind;
}

impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
    fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst> {
        let top_left = self.transform_point2d(&rect.origin);
        let top_right = self.transform_point2d(&rect.top_right());
        let bottom_left = self.transform_point2d(&rect.bottom_left());
        let bottom_right = self.transform_point2d(&rect.bottom_right());
        TypedRect::from_points(&[top_left, top_right, bottom_right, bottom_left])
    }

    fn is_identity(&self) -> bool {
        *self == TypedTransform3D::identity()
    }

    // A port of the preserves2dAxisAlignment function in Skia.
    // Defined in the SkMatrix44 class.
    fn preserves_2d_axis_alignment(&self) -> bool {
        if self.m14 != 0.0 || self.m24 != 0.0 {
            return false;
        }

        let mut col0 = 0;
        let mut col1 = 0;
        let mut row0 = 0;
        let mut row1 = 0;

        if self.m11.abs() > NEARLY_ZERO {
            col0 += 1;
            row0 += 1;
        }
        if self.m12.abs() > NEARLY_ZERO {
            col1 += 1;
            row0 += 1;
        }
        if self.m21.abs() > NEARLY_ZERO {
            col0 += 1;
            row1 += 1;
        }
        if self.m22.abs() > NEARLY_ZERO {
            col1 += 1;
            row1 += 1;
        }

        col0 < 2 && col1 < 2 && row0 < 2 && row1 < 2
    }

    fn has_perspective_component(&self) -> bool {
         self.m14 != 0.0 || self.m24 != 0.0 || self.m34 != 0.0 || self.m44 != 1.0
    }

    fn has_2d_inverse(&self) -> bool {
        self.m11 * self.m22 - self.m12 * self.m21 != 0.0
    }

    fn inverse_project(&self, target: &TypedPoint2D<f32, Dst>) -> Option<TypedPoint2D<f32, Src>> {
        let m: TypedTransform2D<f32, Src, Dst>;
        m = TypedTransform2D::column_major(
            self.m11 - target.x * self.m14,
            self.m21 - target.x * self.m24,
            self.m41 - target.x * self.m44,
            self.m12 - target.y * self.m14,
            self.m22 - target.y * self.m24,
            self.m42 - target.y * self.m44,
        );
        m.inverse().map(|inv| TypedPoint2D::new(inv.m31, inv.m32))
    }

    fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> TypedRect<f32, Src> {
        TypedRect::from_points(&[
            self.inverse_project(&rect.origin).unwrap_or(TypedPoint2D::zero()),
            self.inverse_project(&rect.top_right()).unwrap_or(TypedPoint2D::zero()),
            self.inverse_project(&rect.bottom_left()).unwrap_or(TypedPoint2D::zero()),
            self.inverse_project(&rect.bottom_right()).unwrap_or(TypedPoint2D::zero()),
        ])
    }

    fn transform_kind(&self) -> TransformedRectKind {
        if self.preserves_2d_axis_alignment() {
            TransformedRectKind::AxisAligned
        } else {
            TransformedRectKind::Complex
        }
    }
}

pub trait RectHelpers<U>
where
    Self: Sized,
{
    fn contains_rect(&self, other: &Self) -> bool;
    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self;
    fn is_well_formed_and_nonempty(&self) -> bool;
}

impl<U> RectHelpers<U> for TypedRect<f32, U> {
    fn contains_rect(&self, other: &Self) -> bool {
        self.origin.x <= other.origin.x && self.origin.y <= other.origin.y &&
            self.max_x() >= other.max_x() && self.max_y() >= other.max_y()
    }

    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
        TypedRect::new(
            TypedPoint2D::new(x0, y0),
            TypedSize2D::new(x1 - x0, y1 - y0),
        )
    }

    fn is_well_formed_and_nonempty(&self) -> bool {
        self.size.width > 0.0 && self.size.height > 0.0
    }
}

// Don't use `euclid`'s `is_empty` because that has effectively has an "and" in the conditional
// below instead of an "or".
pub fn rect_is_empty<N: PartialEq + Zero, U>(rect: &TypedRect<N, U>) -> bool {
    rect.size.width == Zero::zero() || rect.size.height == Zero::zero()
}

#[allow(dead_code)]
#[inline]
pub fn rect_from_points_f(x0: f32, y0: f32, x1: f32, y1: f32) -> Rect<f32> {
    Rect::new(Point2D::new(x0, y0), Size2D::new(x1 - x0, y1 - y0))
}

pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
    (b - a) * t + a
}

pub fn calculate_screen_bounding_rect(
    transform: &LayerToWorldTransform,
    rect: &LayerRect,
    device_pixel_ratio: f32
) -> DeviceIntRect {
    let rect = WorldRect::from_points(&[
        transform.transform_point2d(&rect.origin),
        transform.transform_point2d(&rect.top_right()),
        transform.transform_point2d(&rect.bottom_left()),
        transform.transform_point2d(&rect.bottom_right()),
    ]) * device_pixel_ratio;

    let rect = DeviceRect::new(
        DevicePoint::new(rect.origin.x, rect.origin.y),
        DeviceSize::new(rect.size.width, rect.size.height),
    );

    let max_rect = DeviceRect::max_rect();
    rect.round_out().intersection(&max_rect).unwrap_or(max_rect).to_i32()
}

pub fn _subtract_rect<U>(
    rect: &TypedRect<f32, U>,
    other: &TypedRect<f32, U>,
    results: &mut Vec<TypedRect<f32, U>>,
) {
    results.clear();

    let int = rect.intersection(other);
    match int {
        Some(int) => {
            let rx0 = rect.origin.x;
            let ry0 = rect.origin.y;
            let rx1 = rx0 + rect.size.width;
            let ry1 = ry0 + rect.size.height;

            let ox0 = int.origin.x;
            let oy0 = int.origin.y;
            let ox1 = ox0 + int.size.width;
            let oy1 = oy0 + int.size.height;

            let r = TypedRect::from_untyped(&rect_from_points_f(rx0, ry0, ox0, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, ry0, ox1, oy0));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, oy1, ox1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox1, ry0, rx1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
        }
        None => {
            results.push(*rect);
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[repr(u32)]
pub enum TransformedRectKind {
    AxisAligned = 0,
    Complex = 1,
}

#[inline(always)]
pub fn pack_as_float(value: u32) -> f32 {
    value as f32 + 0.5
}

pub trait ComplexClipRegionHelpers {
    /// Return the approximately largest aligned rectangle that is fully inside
    /// the provided clip region.
    fn get_inner_rect_full(&self) -> Option<LayoutRect>;
}

impl ComplexClipRegionHelpers for ComplexClipRegion {
    fn get_inner_rect_full(&self) -> Option<LayoutRect> {
        // this `k` is optimal for a simple case of all border radii being equal
        let k = 1.0 - 0.5 * FRAC_1_SQRT_2; // could be nicely approximated to `0.3`
        extract_inner_rect_impl(&self.rect, &self.radii, k)
    }
}

#[inline]
fn extract_inner_rect_impl<U>(
    rect: &TypedRect<f32, U>,
    radii: &BorderRadius,
    k: f32,
) -> Option<TypedRect<f32, U>> {
    // `k` defines how much border is taken into account
    // We enforce the offsets to be rounded to pixel boundaries
    // by `ceil`-ing and `floor`-ing them

    let xl = (k * radii.top_left.width.max(radii.bottom_left.width)).ceil();
    let xr = (rect.size.width - k * radii.top_right.width.max(radii.bottom_right.width)).floor();
    let yt = (k * radii.top_left.height.max(radii.top_right.height)).ceil();
    let yb =
        (rect.size.height - k * radii.bottom_left.height.max(radii.bottom_right.height)).floor();

    if xl <= xr && yt <= yb {
        Some(TypedRect::new(
            TypedPoint2D::new(rect.origin.x + xl, rect.origin.y + yt),
            TypedSize2D::new(xr - xl, yb - yt),
        ))
    } else {
        None
    }
}

/// Return an aligned rectangle that is inside the clip region and doesn't intersect
/// any of the bounding rectangles of the rounded corners.
pub fn extract_inner_rect_safe<U>(
    rect: &TypedRect<f32, U>,
    radii: &BorderRadius,
) -> Option<TypedRect<f32, U>> {
    // value of `k==1.0` is used for extraction of the corner rectangles
    // see `SEGMENT_CORNER_*` in `clip_shared.glsl`
    extract_inner_rect_impl(rect, radii, 1.0)
}

/// Consumes the old vector and returns a new one that may reuse the old vector's allocated
/// memory.
pub fn recycle_vec<T>(mut old_vec: Vec<T>) -> Vec<T> {
    if old_vec.capacity() > 2 * old_vec.len() {
        // Avoid reusing the buffer if it is a lot larger than it needs to be. This prevents
        // a frame with exceptionally large allocations to cause subsequent frames to retain
        // more memory than they need.
        return Vec::with_capacity(old_vec.len());
    }

    old_vec.clear();

    return old_vec;
}

#[cfg(test)]
pub mod test {
    use super::*;
    use euclid::{Point2D, Radians, Transform3D};
    use std::f32::consts::PI;

    #[test]
    fn inverse_project() {
        let m0 = Transform3D::identity();
        let p0 = Point2D::new(1.0, 2.0);
        // an identical transform doesn't need any inverse projection
        assert_eq!(m0.inverse_project(&p0), Some(p0));
        let m1 = Transform3D::create_rotation(0.0, 1.0, 0.0, Radians::new(PI / 3.0));
        // rotation by 60 degrees would imply scaling of X component by a factor of 2
        assert_eq!(m1.inverse_project(&p0), Some(Point2D::new(2.0, 2.0)));
    }
}

pub trait MaxRect {
    fn max_rect() -> Self;
}

impl MaxRect for LayerRect {
    fn max_rect() -> Self {
        LayerRect::new(
            LayerPoint::new(f32::MIN / 2.0, f32::MIN / 2.0),
            LayerSize::new(f32::MAX, f32::MAX),
        )
    }
}

impl MaxRect for DeviceIntRect {
    fn max_rect() -> Self {
        DeviceIntRect::new(
            DeviceIntPoint::new(i32::MIN / 2, i32::MIN / 2),
            DeviceIntSize::new(i32::MAX, i32::MAX),
        )
    }
}

impl MaxRect for DeviceRect {
    fn max_rect() -> Self {
        // Having an unlimited bounding box is fine up until we try
        // to cast it to `i32`, where we get `-2147483648` for any
        // values larger than or equal to 2^31.
        //
        // Note: clamping to i32::MIN and i32::MAX is not a solution,
        // with explanation left as an exercise for the reader.
        const MAX_COORD: f32 = 1.0e9;

        DeviceRect::new(
            DevicePoint::new(-MAX_COORD, -MAX_COORD),
            DeviceSize::new(2.0 * MAX_COORD, 2.0 * MAX_COORD),
        )
    }
}
<commit_msg>Remove some unused code from util.rs<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{BorderRadius, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePoint, DeviceRect};
use api::{DeviceSize, LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, WorldRect};
use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D, TypedTransform2D};
use euclid::TypedTransform3D;
use num_traits::Zero;
use std::i32;
use std::f32;

// Matches the definition of SK_ScalarNearlyZero in Skia.
const NEARLY_ZERO: f32 = 1.0 / 4096.0;

// TODO: Implement these in euclid!
pub trait MatrixHelpers<Src, Dst> {
    fn preserves_2d_axis_alignment(&self) -> bool;
    fn has_perspective_component(&self) -> bool;
    fn has_2d_inverse(&self) -> bool;
    fn inverse_project(&self, target: &TypedPoint2D<f32, Dst>) -> Option<TypedPoint2D<f32, Src>>;
    fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> TypedRect<f32, Src>;
    fn transform_kind(&self) -> TransformedRectKind;
}

impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
    // A port of the preserves2dAxisAlignment function in Skia.
    // Defined in the SkMatrix44 class.
    fn preserves_2d_axis_alignment(&self) -> bool {
        if self.m14 != 0.0 || self.m24 != 0.0 {
            return false;
        }

        let mut col0 = 0;
        let mut col1 = 0;
        let mut row0 = 0;
        let mut row1 = 0;

        if self.m11.abs() > NEARLY_ZERO {
            col0 += 1;
            row0 += 1;
        }
        if self.m12.abs() > NEARLY_ZERO {
            col1 += 1;
            row0 += 1;
        }
        if self.m21.abs() > NEARLY_ZERO {
            col0 += 1;
            row1 += 1;
        }
        if self.m22.abs() > NEARLY_ZERO {
            col1 += 1;
            row1 += 1;
        }

        col0 < 2 && col1 < 2 && row0 < 2 && row1 < 2
    }

    fn has_perspective_component(&self) -> bool {
         self.m14 != 0.0 || self.m24 != 0.0 || self.m34 != 0.0 || self.m44 != 1.0
    }

    fn has_2d_inverse(&self) -> bool {
        self.m11 * self.m22 - self.m12 * self.m21 != 0.0
    }

    fn inverse_project(&self, target: &TypedPoint2D<f32, Dst>) -> Option<TypedPoint2D<f32, Src>> {
        let m: TypedTransform2D<f32, Src, Dst>;
        m = TypedTransform2D::column_major(
            self.m11 - target.x * self.m14,
            self.m21 - target.x * self.m24,
            self.m41 - target.x * self.m44,
            self.m12 - target.y * self.m14,
            self.m22 - target.y * self.m24,
            self.m42 - target.y * self.m44,
        );
        m.inverse().map(|inv| TypedPoint2D::new(inv.m31, inv.m32))
    }

    fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> TypedRect<f32, Src> {
        TypedRect::from_points(&[
            self.inverse_project(&rect.origin).unwrap_or(TypedPoint2D::zero()),
            self.inverse_project(&rect.top_right()).unwrap_or(TypedPoint2D::zero()),
            self.inverse_project(&rect.bottom_left()).unwrap_or(TypedPoint2D::zero()),
            self.inverse_project(&rect.bottom_right()).unwrap_or(TypedPoint2D::zero()),
        ])
    }

    fn transform_kind(&self) -> TransformedRectKind {
        if self.preserves_2d_axis_alignment() {
            TransformedRectKind::AxisAligned
        } else {
            TransformedRectKind::Complex
        }
    }
}

pub trait RectHelpers<U>
where
    Self: Sized,
{
    fn contains_rect(&self, other: &Self) -> bool;
    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self;
    fn is_well_formed_and_nonempty(&self) -> bool;
}

impl<U> RectHelpers<U> for TypedRect<f32, U> {
    fn contains_rect(&self, other: &Self) -> bool {
        self.origin.x <= other.origin.x && self.origin.y <= other.origin.y &&
            self.max_x() >= other.max_x() && self.max_y() >= other.max_y()
    }

    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
        TypedRect::new(
            TypedPoint2D::new(x0, y0),
            TypedSize2D::new(x1 - x0, y1 - y0),
        )
    }

    fn is_well_formed_and_nonempty(&self) -> bool {
        self.size.width > 0.0 && self.size.height > 0.0
    }
}

// Don't use `euclid`'s `is_empty` because that has effectively has an "and" in the conditional
// below instead of an "or".
pub fn rect_is_empty<N: PartialEq + Zero, U>(rect: &TypedRect<N, U>) -> bool {
    rect.size.width == Zero::zero() || rect.size.height == Zero::zero()
}

#[allow(dead_code)]
#[inline]
pub fn rect_from_points_f(x0: f32, y0: f32, x1: f32, y1: f32) -> Rect<f32> {
    Rect::new(Point2D::new(x0, y0), Size2D::new(x1 - x0, y1 - y0))
}

pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
    (b - a) * t + a
}

pub fn calculate_screen_bounding_rect(
    transform: &LayerToWorldTransform,
    rect: &LayerRect,
    device_pixel_ratio: f32
) -> DeviceIntRect {
    let rect = WorldRect::from_points(&[
        transform.transform_point2d(&rect.origin),
        transform.transform_point2d(&rect.top_right()),
        transform.transform_point2d(&rect.bottom_left()),
        transform.transform_point2d(&rect.bottom_right()),
    ]) * device_pixel_ratio;

    let rect = DeviceRect::new(
        DevicePoint::new(rect.origin.x, rect.origin.y),
        DeviceSize::new(rect.size.width, rect.size.height),
    );

    let max_rect = DeviceRect::max_rect();
    rect.round_out().intersection(&max_rect).unwrap_or(max_rect).to_i32()
}

pub fn _subtract_rect<U>(
    rect: &TypedRect<f32, U>,
    other: &TypedRect<f32, U>,
    results: &mut Vec<TypedRect<f32, U>>,
) {
    results.clear();

    let int = rect.intersection(other);
    match int {
        Some(int) => {
            let rx0 = rect.origin.x;
            let ry0 = rect.origin.y;
            let rx1 = rx0 + rect.size.width;
            let ry1 = ry0 + rect.size.height;

            let ox0 = int.origin.x;
            let oy0 = int.origin.y;
            let ox1 = ox0 + int.size.width;
            let oy1 = oy0 + int.size.height;

            let r = TypedRect::from_untyped(&rect_from_points_f(rx0, ry0, ox0, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, ry0, ox1, oy0));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, oy1, ox1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox1, ry0, rx1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
        }
        None => {
            results.push(*rect);
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[repr(u32)]
pub enum TransformedRectKind {
    AxisAligned = 0,
    Complex = 1,
}

#[inline(always)]
pub fn pack_as_float(value: u32) -> f32 {
    value as f32 + 0.5
}

#[inline]
fn extract_inner_rect_impl<U>(
    rect: &TypedRect<f32, U>,
    radii: &BorderRadius,
    k: f32,
) -> Option<TypedRect<f32, U>> {
    // `k` defines how much border is taken into account
    // We enforce the offsets to be rounded to pixel boundaries
    // by `ceil`-ing and `floor`-ing them

    let xl = (k * radii.top_left.width.max(radii.bottom_left.width)).ceil();
    let xr = (rect.size.width - k * radii.top_right.width.max(radii.bottom_right.width)).floor();
    let yt = (k * radii.top_left.height.max(radii.top_right.height)).ceil();
    let yb =
        (rect.size.height - k * radii.bottom_left.height.max(radii.bottom_right.height)).floor();

    if xl <= xr && yt <= yb {
        Some(TypedRect::new(
            TypedPoint2D::new(rect.origin.x + xl, rect.origin.y + yt),
            TypedSize2D::new(xr - xl, yb - yt),
        ))
    } else {
        None
    }
}

/// Return an aligned rectangle that is inside the clip region and doesn't intersect
/// any of the bounding rectangles of the rounded corners.
pub fn extract_inner_rect_safe<U>(
    rect: &TypedRect<f32, U>,
    radii: &BorderRadius,
) -> Option<TypedRect<f32, U>> {
    // value of `k==1.0` is used for extraction of the corner rectangles
    // see `SEGMENT_CORNER_*` in `clip_shared.glsl`
    extract_inner_rect_impl(rect, radii, 1.0)
}

/// Consumes the old vector and returns a new one that may reuse the old vector's allocated
/// memory.
pub fn recycle_vec<T>(mut old_vec: Vec<T>) -> Vec<T> {
    if old_vec.capacity() > 2 * old_vec.len() {
        // Avoid reusing the buffer if it is a lot larger than it needs to be. This prevents
        // a frame with exceptionally large allocations to cause subsequent frames to retain
        // more memory than they need.
        return Vec::with_capacity(old_vec.len());
    }

    old_vec.clear();

    return old_vec;
}

#[cfg(test)]
pub mod test {
    use super::*;
    use euclid::{Point2D, Radians, Transform3D};
    use std::f32::consts::PI;

    #[test]
    fn inverse_project() {
        let m0 = Transform3D::identity();
        let p0 = Point2D::new(1.0, 2.0);
        // an identical transform doesn't need any inverse projection
        assert_eq!(m0.inverse_project(&p0), Some(p0));
        let m1 = Transform3D::create_rotation(0.0, 1.0, 0.0, Radians::new(PI / 3.0));
        // rotation by 60 degrees would imply scaling of X component by a factor of 2
        assert_eq!(m1.inverse_project(&p0), Some(Point2D::new(2.0, 2.0)));
    }
}

pub trait MaxRect {
    fn max_rect() -> Self;
}

impl MaxRect for LayerRect {
    fn max_rect() -> Self {
        LayerRect::new(
            LayerPoint::new(f32::MIN / 2.0, f32::MIN / 2.0),
            LayerSize::new(f32::MAX, f32::MAX),
        )
    }
}

impl MaxRect for DeviceIntRect {
    fn max_rect() -> Self {
        DeviceIntRect::new(
            DeviceIntPoint::new(i32::MIN / 2, i32::MIN / 2),
            DeviceIntSize::new(i32::MAX, i32::MAX),
        )
    }
}

impl MaxRect for DeviceRect {
    fn max_rect() -> Self {
        // Having an unlimited bounding box is fine up until we try
        // to cast it to `i32`, where we get `-2147483648` for any
        // values larger than or equal to 2^31.
        //
        // Note: clamping to i32::MIN and i32::MAX is not a solution,
        // with explanation left as an exercise for the reader.
        const MAX_COORD: f32 = 1.0e9;

        DeviceRect::new(
            DevicePoint::new(-MAX_COORD, -MAX_COORD),
            DeviceSize::new(2.0 * MAX_COORD, 2.0 * MAX_COORD),
        )
    }
}
<|endoftext|>


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

//! The `ByteString` struct.

use std::ascii::AsciiExt;
use std::borrow::{ToOwned, Cow};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops;
use std::ops::{Deref, DerefMut};
use std::str;
use std::str::{Bytes, FromStr};
use string_cache::Atom;

/// Encapsulates the IDL `ByteString` type.
#[derive(JSTraceable, Clone, Eq, PartialEq, HeapSizeOf, Debug)]
pub struct ByteString(Vec<u8>);

impl ByteString {
    /// Creates a new `ByteString`.
    pub fn new(value: Vec<u8>) -> ByteString {
        ByteString(value)
    }

    /// Returns `self` as a string, if it encodes valid UTF-8, and `None`
    /// otherwise.
    pub fn as_str(&self) -> Option<&str> {
        str::from_utf8(&self.0).ok()
    }

    /// Returns the length.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Compare `self` to `other`, matching A–Z and a–z as equal.
    pub fn eq_ignore_case(&self, other: &ByteString) -> bool {
        self.0.eq_ignore_ascii_case(&other.0)
    }

    /// Returns `self` with A–Z replaced by a–z.
    pub fn to_lower(&self) -> ByteString {
        ByteString::new(self.0.to_ascii_lowercase())
    }
}

impl Into<Vec<u8>> for ByteString {
    fn into(self) -> Vec<u8> {
        self.0
    }
}

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

impl FromStr for ByteString {
    type Err = ();
    fn from_str(s: &str) -> Result<ByteString, ()> {
        Ok(ByteString::new(s.to_owned().into_bytes()))
    }
}

impl ops::Deref for ByteString {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        &self.0
    }
}

/// A string that is constructed from a UCS-2 buffer by replacing invalid code
/// points with the replacement character.
#[derive(Clone, HeapSizeOf)]
pub struct USVString(pub String);

/// Returns whether `s` is a `token`, as defined by
/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
pub fn is_token(s: &[u8]) -> bool {
    if s.is_empty() {
        return false; // A token must be at least a single character
    }
    s.iter().all(|&x| {
        // http://tools.ietf.org/html/rfc2616#section-2.2
        match x {
            0...31 | 127 => false, // CTLs
            40 |
            41 |
            60 |
            62 |
            64 |
            44 |
            59 |
            58 |
            92 |
            34 |
            47 |
            91 |
            93 |
            63 |
            61 |
            123 |
            125 |
            32 => false, // separators
            x if x > 127 => false, // non-CHARs
            _ => true,
        }
    })
}

/// A DOMString.
///
/// This type corresponds to the [`DOMString`](idl) type in WebIDL.
///
/// [idl]: https://heycam.github.io/webidl/#idl-DOMString
///
/// Cenceptually, a DOMString has the same value space as a JavaScript String,
/// i.e., an array of 16-bit *code units* representing UTF-16, potentially with
/// unpaired surrogates present (also sometimes called WTF-16).
///
/// Currently, this type stores a Rust `String`, in order to avoid issues when
/// integrating with the rest of the Rust ecosystem and even the rest of the
/// browser itself.
///
/// However, Rust `String`s are guaranteed to be valid UTF-8, and as such have
/// a *smaller value space* than WTF-16 (i.e., some JavaScript String values
/// can not be represented as a Rust `String`). This introduces the question of
/// what to do with values being passed from JavaScript to Rust that contain
/// unpaired surrogates.
///
/// The hypothesis is that it does not matter much how exactly those values are
/// transformed, because passing unpaired surrogates into the DOM is very rare.
/// In order to test this hypothesis, Servo will panic when encountering any
/// unpaired surrogates on conversion to `DOMString` by default. (The command
/// line option `-Z replace-surrogates` instead causes Servo to replace the
/// unpaired surrogate by a U+FFFD replacement character.)
///
/// Currently, the lack of crash reports about this issue provides some
/// evidence to support the hypothesis. This evidence will hopefully be used to
/// convince other browser vendors that it would be safe to replace unpaired
/// surrogates at the boundary between JavaScript and native code. (This would
/// unify the `DOMString` and `USVString` types, both in the WebIDL standard
/// and in Servo.)
///
/// This type is currently `!Send`, in order to help with an independent
/// experiment to store `JSString`s rather than Rust `String`s.
#[derive(Clone, Debug, Eq, Hash, HeapSizeOf, Ord, PartialEq, PartialOrd)]
pub struct DOMString(String);

impl !Send for DOMString {}

impl DOMString {
    /// Creates a new `DOMString`.
    pub fn new() -> DOMString {
        DOMString(String::new())
    }

    /// Creates a new `DOMString` from a `String`.
    pub fn from_string(s: String) -> DOMString {
        DOMString(s)
    }

    /// Appends a given string slice onto the end of this String.
    pub fn push_str(&mut self, string: &str) {
        self.0.push_str(string)
    }

    /// Truncates this `DOMString`, removing all contents.
    pub fn clear(&mut self) {
        self.0.clear()
    }

    /// An iterator over the bytes of this `DOMString`.
    pub fn bytes(&self) -> Bytes {
        self.0.bytes()
    }
}

impl Default for DOMString {
    fn default() -> Self {
        DOMString(String::new())
    }
}

impl Deref for DOMString {
    type Target = str;

    #[inline]
    fn deref(&self) -> &str {
        &self.0
    }
}

impl DerefMut for DOMString {
    #[inline]
    fn deref_mut(&mut self) -> &mut str {
        &mut self.0
    }
}

impl AsRef<str> for DOMString {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for DOMString {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl PartialEq<str> for DOMString {
    fn eq(&self, other: &str) -> bool {
        &**self == other
    }
}

impl<'a> PartialEq<&'a str> for DOMString {
    fn eq(&self, other: &&'a str) -> bool {
        &**self == *other
    }
}

impl From<String> for DOMString {
    fn from(contents: String) -> DOMString {
        DOMString(contents)
    }
}

impl<'a> From<&'a str> for DOMString {
    fn from(contents: &str) -> DOMString {
        DOMString::from(String::from(contents))
    }
}

impl<'a> From<Cow<'a, str>> for DOMString {
    fn from(contents: Cow<'a, str>) -> DOMString {
        match contents {
            Cow::Owned(s) => DOMString::from(s),
            Cow::Borrowed(s) => DOMString::from(s),
        }
    }
}

impl From<DOMString> for Atom {
    fn from(contents: DOMString) -> Atom {
        Atom::from(contents.0)
    }
}

impl From<DOMString> for String {
    fn from(contents: DOMString) -> String {
        contents.0
    }
}

impl Into<Vec<u8>> for DOMString {
    fn into(self) -> Vec<u8> {
        self.0.into()
    }
}

impl Extend<char> for DOMString {
    fn extend<I>(&mut self, iterable: I) where I: IntoIterator<Item=char> {
        self.0.extend(iterable)
    }
}
<commit_msg>Implement Borrow<str> for DOMString<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The `ByteString` struct.

use std::ascii::AsciiExt;
use std::borrow::{Borrow, Cow, ToOwned};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops;
use std::ops::{Deref, DerefMut};
use std::str;
use std::str::{Bytes, FromStr};
use string_cache::Atom;

/// Encapsulates the IDL `ByteString` type.
#[derive(JSTraceable, Clone, Eq, PartialEq, HeapSizeOf, Debug)]
pub struct ByteString(Vec<u8>);

impl ByteString {
    /// Creates a new `ByteString`.
    pub fn new(value: Vec<u8>) -> ByteString {
        ByteString(value)
    }

    /// Returns `self` as a string, if it encodes valid UTF-8, and `None`
    /// otherwise.
    pub fn as_str(&self) -> Option<&str> {
        str::from_utf8(&self.0).ok()
    }

    /// Returns the length.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Compare `self` to `other`, matching A–Z and a–z as equal.
    pub fn eq_ignore_case(&self, other: &ByteString) -> bool {
        self.0.eq_ignore_ascii_case(&other.0)
    }

    /// Returns `self` with A–Z replaced by a–z.
    pub fn to_lower(&self) -> ByteString {
        ByteString::new(self.0.to_ascii_lowercase())
    }
}

impl Into<Vec<u8>> for ByteString {
    fn into(self) -> Vec<u8> {
        self.0
    }
}

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

impl FromStr for ByteString {
    type Err = ();
    fn from_str(s: &str) -> Result<ByteString, ()> {
        Ok(ByteString::new(s.to_owned().into_bytes()))
    }
}

impl ops::Deref for ByteString {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        &self.0
    }
}

/// A string that is constructed from a UCS-2 buffer by replacing invalid code
/// points with the replacement character.
#[derive(Clone, HeapSizeOf)]
pub struct USVString(pub String);

/// Returns whether `s` is a `token`, as defined by
/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
pub fn is_token(s: &[u8]) -> bool {
    if s.is_empty() {
        return false; // A token must be at least a single character
    }
    s.iter().all(|&x| {
        // http://tools.ietf.org/html/rfc2616#section-2.2
        match x {
            0...31 | 127 => false, // CTLs
            40 |
            41 |
            60 |
            62 |
            64 |
            44 |
            59 |
            58 |
            92 |
            34 |
            47 |
            91 |
            93 |
            63 |
            61 |
            123 |
            125 |
            32 => false, // separators
            x if x > 127 => false, // non-CHARs
            _ => true,
        }
    })
}

/// A DOMString.
///
/// This type corresponds to the [`DOMString`](idl) type in WebIDL.
///
/// [idl]: https://heycam.github.io/webidl/#idl-DOMString
///
/// Cenceptually, a DOMString has the same value space as a JavaScript String,
/// i.e., an array of 16-bit *code units* representing UTF-16, potentially with
/// unpaired surrogates present (also sometimes called WTF-16).
///
/// Currently, this type stores a Rust `String`, in order to avoid issues when
/// integrating with the rest of the Rust ecosystem and even the rest of the
/// browser itself.
///
/// However, Rust `String`s are guaranteed to be valid UTF-8, and as such have
/// a *smaller value space* than WTF-16 (i.e., some JavaScript String values
/// can not be represented as a Rust `String`). This introduces the question of
/// what to do with values being passed from JavaScript to Rust that contain
/// unpaired surrogates.
///
/// The hypothesis is that it does not matter much how exactly those values are
/// transformed, because passing unpaired surrogates into the DOM is very rare.
/// In order to test this hypothesis, Servo will panic when encountering any
/// unpaired surrogates on conversion to `DOMString` by default. (The command
/// line option `-Z replace-surrogates` instead causes Servo to replace the
/// unpaired surrogate by a U+FFFD replacement character.)
///
/// Currently, the lack of crash reports about this issue provides some
/// evidence to support the hypothesis. This evidence will hopefully be used to
/// convince other browser vendors that it would be safe to replace unpaired
/// surrogates at the boundary between JavaScript and native code. (This would
/// unify the `DOMString` and `USVString` types, both in the WebIDL standard
/// and in Servo.)
///
/// This type is currently `!Send`, in order to help with an independent
/// experiment to store `JSString`s rather than Rust `String`s.
#[derive(Clone, Debug, Eq, Hash, HeapSizeOf, Ord, PartialEq, PartialOrd)]
pub struct DOMString(String);

impl !Send for DOMString {}

impl DOMString {
    /// Creates a new `DOMString`.
    pub fn new() -> DOMString {
        DOMString(String::new())
    }

    /// Creates a new `DOMString` from a `String`.
    pub fn from_string(s: String) -> DOMString {
        DOMString(s)
    }

    /// Appends a given string slice onto the end of this String.
    pub fn push_str(&mut self, string: &str) {
        self.0.push_str(string)
    }

    /// Truncates this `DOMString`, removing all contents.
    pub fn clear(&mut self) {
        self.0.clear()
    }

    /// An iterator over the bytes of this `DOMString`.
    pub fn bytes(&self) -> Bytes {
        self.0.bytes()
    }
}

impl Borrow<str> for DOMString {
    #[inline]
    fn borrow(&self) -> &str {
        &self.0
    }
}

impl Default for DOMString {
    fn default() -> Self {
        DOMString(String::new())
    }
}

impl Deref for DOMString {
    type Target = str;

    #[inline]
    fn deref(&self) -> &str {
        &self.0
    }
}

impl DerefMut for DOMString {
    #[inline]
    fn deref_mut(&mut self) -> &mut str {
        &mut self.0
    }
}

impl AsRef<str> for DOMString {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for DOMString {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl PartialEq<str> for DOMString {
    fn eq(&self, other: &str) -> bool {
        &**self == other
    }
}

impl<'a> PartialEq<&'a str> for DOMString {
    fn eq(&self, other: &&'a str) -> bool {
        &**self == *other
    }
}

impl From<String> for DOMString {
    fn from(contents: String) -> DOMString {
        DOMString(contents)
    }
}

impl<'a> From<&'a str> for DOMString {
    fn from(contents: &str) -> DOMString {
        DOMString::from(String::from(contents))
    }
}

impl<'a> From<Cow<'a, str>> for DOMString {
    fn from(contents: Cow<'a, str>) -> DOMString {
        match contents {
            Cow::Owned(s) => DOMString::from(s),
            Cow::Borrowed(s) => DOMString::from(s),
        }
    }
}

impl From<DOMString> for Atom {
    fn from(contents: DOMString) -> Atom {
        Atom::from(contents.0)
    }
}

impl From<DOMString> for String {
    fn from(contents: DOMString) -> String {
        contents.0
    }
}

impl Into<Vec<u8>> for DOMString {
    fn into(self) -> Vec<u8> {
        self.0.into()
    }
}

impl Extend<char> for DOMString {
    fn extend<I>(&mut self, iterable: I) where I: IntoIterator<Item=char> {
        self.0.extend(iterable)
    }
}
<|endoftext|>