<commit_before>use crate::*;

use async_std::{net::SocketAddr, prelude::*};

use futures::{
    self,
    sink::SinkExt,
    stream::{self, select, SelectAll, StreamExt},
};
use futures_timer::Delay;

use serde::Serialize;
use std::str::FromStr;
use std::{
    collections::HashMap,
    iter::FromIterator,
    time::{Duration, Instant},
};
use structopt::StructOpt;

#[derive(Clone, Copy, Debug, Serialize)]
pub struct TripReport {
    stream_id: StreamId,
    index: u64,
    round_trip: f64,
}

#[derive(Clone)]
pub struct Summary {
    pub mean_ms: f64,
    pub deviation_ms: f64,
    pub trip_reports: Vec<TripReport>,
}

impl FromIterator<Summary> for Summary {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = Summary>,
    {
        let (trip_reports, count, mean_sum, deviation_sum) =
            iter.into_iter().fold(
                (vec![], 0, 0.0, 0.0),
                |(
                    mut trip_reports,
                    mut count,
                    mut mean_sum,
                    mut deviation_sum,
                ),
                 mut result| {
                    mean_sum += result.mean_ms;
                    deviation_sum += result.deviation_ms;
                    count += 1;
                    trip_reports.append(&mut result.trip_reports);

                    (trip_reports, count, mean_sum, deviation_sum)
                },
            );

        Summary {
            mean_ms: mean_sum / count as f64,
            deviation_ms: deviation_sum / count as f64,
            trip_reports,
        }
    }
}

impl std::fmt::Debug for Summary {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("Summary")
            .field("Mean", &self.mean_ms)
            .field("Deviation", &self.deviation_ms)
            .finish()
    }
}

impl From<Vec<TripReport>> for Summary {
    fn from(src: Vec<TripReport>) -> Self {
        let sum: f64 = src.iter().map(|r| r.round_trip).sum();
        let n = src.len() as f64;
        let mean = sum / n;

        let square_difference = |r: &TripReport| (r.round_trip - mean).powi(2);
        let sum_of_squares: f64 = src.iter().map(square_difference).sum();
        let variance = sum_of_squares / (n - 1.0);
        let deviation = variance.sqrt();

        Summary {
            mean_ms: mean,
            deviation_ms: deviation,
            trip_reports: src,
        }
    }
}

/// Returns a stream that yields `()` `hertz` times per second.
fn ticker(hertz: u32) -> impl Stream<Item = ()> {
    let tick_rate = Duration::from_secs(1) / hertz;
    stream::repeat(0u8).then(move |_| Delay::new(tick_rate))
}

#[derive(Debug)]
struct TransferTracker {
    stream_id: StreamId,
    total_expected: usize,
    live: HashMap<u64, Instant>,
    returned: Vec<TripReport>,
}

impl TransferTracker {
    fn track_send(&mut self, id: u64) {
        self.live.insert(id, Instant::now());
    }

    fn track_return(&mut self, id: u64) {
        if let Some(sent_time) = self.live.remove(&id) {
            self.returned.push(TripReport {
                stream_id: self.stream_id,
                index: id,
                round_trip: Instant::now().duration_since(sent_time).as_secs_f64() * 1e3,
            });
        }
    }

    fn done(&self) -> bool {
        self.returned.len() >= self.total_expected
    }
}

async fn run(
    options: Options,
    client: impl Connection + Unpin,
) -> Result<Summary> {
    enum Input {
        Transfer(TransferCmd),
        Wire(Result<Datagram>),
    }

    let (mut client_sink, client_stream) = client.split();
    let returned_datagrams = client_stream.map(Input::Wire);

    let mut tracking = options
        .transfers
        .iter()
        .filter_map(|tx| {
            tx.return_count.map(|total_expected| {
                (
                    tx.stream_id,
                    TransferTracker {
                        stream_id: tx.stream_id,
                        total_expected,
                        live: HashMap::new(),
                        returned: vec![],
                    },
                )
            })
        })
        .collect::<HashMap<StreamId, TransferTracker>>();
    let transfers: SelectAll<_> = options
        .transfers
        .into_iter()
        .map(Transfer::stream)
        .collect();

    let mut input_stream =
        select(transfers.map(Input::Transfer), returned_datagrams);

    loop {
        let input = input_stream.next().await.unwrap();
        match input {
            Input::Wire(returned_datagram) => {
                let returned_datagram: Datagram =
                    returned_datagram.expect("datagram");
                let stream = returned_datagram
                    .stream_position
                    .expect("stream position")
                    .stream_id;
                let benchmark_datagram =
                    bincode::deserialize::<BenchmarkDatagram>(
                        returned_datagram.data.as_slice(),
                    )?;

                if let Some(tracker) = tracking.get_mut(&stream) {
                    tracker.track_return(benchmark_datagram.id);
                }

                if tracking.values().all(TransferTracker::done) {
                    return Ok(tracking
                        .into_iter()
                        .map(|(_, tracker)| tracker.returned)
                        .map(Summary::from)
                        .collect());
                }
            }
            Input::Transfer(transfer_cmd) => {
                client_sink.send(transfer_cmd.send_cmd).await?;
                if let Some((cumulative_tracking, cmd_tracking)) =
                    transfer_cmd.tracking.and_then(|cmd_tracking| {
                        let cumulative_tracking =
                            tracking.get_mut(&cmd_tracking.stream_id)?;
                        Some((cumulative_tracking, cmd_tracking))
                    })
                {
                    cumulative_tracking.track_send(cmd_tracking.id);
                }
            }
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct Options {
    /// Address of the server to run the benchmark against;
    #[structopt(short = "a", default_value = "127.0.0.1:33333")]
    pub address: SocketAddr,
    /// Periodic transfers, specified in terms of
    /// `stream_id:size:hertz:[return_count]`.
    #[structopt(short = "b", long)]
    pub transfers: Vec<Transfer>,
    #[structopt(subcommand)]
    pub protocol: Protocol,
}

struct TransferCmd {
    send_cmd: SendCmd,
    tracking: Option<TransferMessageTracking>,
}

/// Tracking information for a transfer message on the wire.
struct TransferMessageTracking {
    stream_id: StreamId,
    id: u64,
}

#[derive(Clone, Debug, Copy)]
pub struct Transfer {
    pub stream_id: StreamId,
    pub size: usize,
    pub hertz: u32,
    pub return_count: Option<usize>,
}

impl Transfer {
    fn stream(self) -> impl Stream<Item = TransferCmd> {
        let ticker = ticker(self.hertz);
        let mut id = 0;
        ticker.map(move |_| {
            id += 1;
            match self.return_count {
                Some(_) => TransferCmd {
                    send_cmd: self.send_cmd(id),
                    tracking: Some(TransferMessageTracking {
                        stream_id: self.stream_id,
                        id,
                    }),
                },
                None => TransferCmd {
                    send_cmd: self.send_cmd(ID_DO_NOT_RETURN),
                    tracking: None,
                },
            }
        })
    }

    fn send_cmd(&self, id: u64) -> SendCmd {
        let delivery_mode = DeliveryMode::ReliableOrdered(self.stream_id);
        SendCmd {
            delivery_mode,
            data: bincode::serialize(&BenchmarkDatagram {
                id,
                delivery_mode,
                data: vec![0; self.size],
            })
            .expect("to serialize bulk transfer"),
            ..SendCmd::default()
        }
    }
}

impl FromStr for Transfer {
    type Err = std::num::ParseIntError;
    fn from_str(src: &str) -> std::result::Result<Self, Self::Err> {
        let args: Vec<&str> = src.split(":").collect();

        let stream_id = args[0].parse::<u8>()?;
        let size = args[1].parse::<usize>()?;
        let hertz = args[2].parse::<u32>()?;
        let return_count =
            args.get(3).map(|a| a.parse::<usize>()).transpose()?;

        Ok(Self {
            stream_id: StreamId(stream_id),
            size,
            hertz,
            return_count,
        })
    }
}

pub async fn client_main(options: Options) -> Result<Summary> {
    let address = options.address;
    match options.protocol {
        Protocol::Tcp => {
            run(
                options,
                loop {
                    let result = tcp::TcpConnection::connect(address).await;

                    let error = match result {
                        Ok(results) => break results,
                        Err(e) => e,
                    };

                    // The server port is not yet open; give it time.
                    if error.is::<std::io::Error>()
                        && error
                            .downcast_ref::<std::io::Error>()
                            .map(std::io::Error::kind)
                            == Some(std::io::ErrorKind::ConnectionRefused)
                    {
                        continue;
                    }

                    panic!(
                        "Failed to connect to benchmark server: {:?}",
                        error
                    );
                },
            )
            .await
        }
        Protocol::Enet => {
            run(options, enet::EnetConnection::connect(address).await).await
        }
    }
}
<commit_msg>Track send time<commit_after>use crate::*;

use async_std::{net::SocketAddr, prelude::*};

use futures::{
    self,
    sink::SinkExt,
    stream::{self, select, SelectAll, StreamExt},
};
use futures_timer::Delay;

use serde::Serialize;
use std::str::FromStr;
use std::{
    collections::HashMap,
    iter::FromIterator,
    time::{Duration, Instant},
};
use structopt::StructOpt;

#[derive(Clone, Copy, Debug, Serialize)]
pub struct TripReport {
    stream_id: StreamId,
    index: u64,
    round_trip: f64,
    send_time: f64,
}

#[derive(Clone)]
pub struct Summary {
    pub mean_ms: f64,
    pub deviation_ms: f64,
    pub trip_reports: Vec<TripReport>,
}

impl FromIterator<Summary> for Summary {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = Summary>,
    {
        let (trip_reports, count, mean_sum, deviation_sum) =
            iter.into_iter().fold(
                (vec![], 0, 0.0, 0.0),
                |(
                    mut trip_reports,
                    mut count,
                    mut mean_sum,
                    mut deviation_sum,
                ),
                 mut result| {
                    mean_sum += result.mean_ms;
                    deviation_sum += result.deviation_ms;
                    count += 1;
                    trip_reports.append(&mut result.trip_reports);

                    (trip_reports, count, mean_sum, deviation_sum)
                },
            );

        Summary {
            mean_ms: mean_sum / count as f64,
            deviation_ms: deviation_sum / count as f64,
            trip_reports,
        }
    }
}

impl std::fmt::Debug for Summary {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("Summary")
            .field("Mean", &self.mean_ms)
            .field("Deviation", &self.deviation_ms)
            .finish()
    }
}

impl From<Vec<TripReport>> for Summary {
    fn from(src: Vec<TripReport>) -> Self {
        let sum: f64 = src.iter().map(|r| r.round_trip).sum();
        let n = src.len() as f64;
        let mean = sum / n;

        let square_difference = |r: &TripReport| (r.round_trip - mean).powi(2);
        let sum_of_squares: f64 = src.iter().map(square_difference).sum();
        let variance = sum_of_squares / (n - 1.0);
        let deviation = variance.sqrt();

        Summary {
            mean_ms: mean,
            deviation_ms: deviation,
            trip_reports: src,
        }
    }
}

/// Returns a stream that yields `()` `hertz` times per second.
fn ticker(hertz: u32) -> impl Stream<Item = ()> {
    let tick_rate = Duration::from_secs(1) / hertz;
    stream::repeat(0u8).then(move |_| Delay::new(tick_rate))
}

#[derive(Debug)]
struct TransferTracker {
    epoch: Instant,
    stream_id: StreamId,
    total_expected: usize,
    live: HashMap<u64, Instant>,
    returned: Vec<TripReport>,
}

impl TransferTracker {
    fn track_send(&mut self, id: u64) {
        self.live.insert(id, Instant::now());
    }

    fn track_return(&mut self, id: u64) {
        let now = Instant::now();
        if let Some(sent_time) = self.live.remove(&id) {
            let round_trip = now.duration_since(sent_time);
            self.returned.push(TripReport {
                stream_id: self.stream_id,
                index: id,
                send_time: (now.duration_since(self.epoch) - round_trip).as_secs_f64() * 1e3,
                round_trip: round_trip.as_secs_f64() * 1e3,
            });
        }
    }

    fn done(&self) -> bool {
        self.returned.len() >= self.total_expected
    }
}

async fn run(
    options: Options,
    client: impl Connection + Unpin,
) -> Result<Summary> {
    enum Input {
        Transfer(TransferCmd),
        Wire(Result<Datagram>),
    }

    let (mut client_sink, client_stream) = client.split();
    let returned_datagrams = client_stream.map(Input::Wire);

    let epoch = Instant::now();
    let mut tracking = options
        .transfers
        .iter()
        .filter_map(|tx| {
            tx.return_count.map(|total_expected| {
                (
                    tx.stream_id,
                    TransferTracker {
                        epoch,
                        stream_id: tx.stream_id,
                        total_expected,
                        live: HashMap::new(),
                        returned: vec![],
                    },
                )
            })
        })
        .collect::<HashMap<StreamId, TransferTracker>>();
    let transfers: SelectAll<_> = options
        .transfers
        .into_iter()
        .map(Transfer::stream)
        .collect();

    let mut input_stream =
        select(transfers.map(Input::Transfer), returned_datagrams);

    loop {
        let input = input_stream.next().await.unwrap();
        match input {
            Input::Wire(returned_datagram) => {
                let returned_datagram: Datagram =
                    returned_datagram.expect("datagram");
                let stream = returned_datagram
                    .stream_position
                    .expect("stream position")
                    .stream_id;
                let benchmark_datagram =
                    bincode::deserialize::<BenchmarkDatagram>(
                        returned_datagram.data.as_slice(),
                    )?;

                if let Some(tracker) = tracking.get_mut(&stream) {
                    tracker.track_return(benchmark_datagram.id);
                }

                if tracking.values().all(TransferTracker::done) {
                    return Ok(tracking
                        .into_iter()
                        .map(|(_, tracker)| tracker.returned)
                        .map(Summary::from)
                        .collect());
                }
            }
            Input::Transfer(transfer_cmd) => {
                client_sink.send(transfer_cmd.send_cmd).await?;
                if let Some((cumulative_tracking, cmd_tracking)) =
                    transfer_cmd.tracking.and_then(|cmd_tracking| {
                        let cumulative_tracking =
                            tracking.get_mut(&cmd_tracking.stream_id)?;
                        Some((cumulative_tracking, cmd_tracking))
                    })
                {
                    cumulative_tracking.track_send(cmd_tracking.id);
                }
            }
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct Options {
    /// Address of the server to run the benchmark against;
    #[structopt(short = "a", default_value = "127.0.0.1:33333")]
    pub address: SocketAddr,
    /// Periodic transfers, specified in terms of
    /// `stream_id:size:hertz:[return_count]`.
    #[structopt(short = "b", long)]
    pub transfers: Vec<Transfer>,
    #[structopt(subcommand)]
    pub protocol: Protocol,
}

struct TransferCmd {
    send_cmd: SendCmd,
    tracking: Option<TransferMessageTracking>,
}

/// Tracking information for a transfer message on the wire.
struct TransferMessageTracking {
    stream_id: StreamId,
    id: u64,
}

#[derive(Clone, Debug, Copy)]
pub struct Transfer {
    pub stream_id: StreamId,
    pub size: usize,
    pub hertz: u32,
    pub return_count: Option<usize>,
}

impl Transfer {
    fn stream(self) -> impl Stream<Item = TransferCmd> {
        let ticker = ticker(self.hertz);
        let mut id = 0;
        ticker.map(move |_| {
            id += 1;
            match self.return_count {
                Some(_) => TransferCmd {
                    send_cmd: self.send_cmd(id),
                    tracking: Some(TransferMessageTracking {
                        stream_id: self.stream_id,
                        id,
                    }),
                },
                None => TransferCmd {
                    send_cmd: self.send_cmd(ID_DO_NOT_RETURN),
                    tracking: None,
                },
            }
        })
    }

    fn send_cmd(&self, id: u64) -> SendCmd {
        let delivery_mode = DeliveryMode::ReliableOrdered(self.stream_id);
        SendCmd {
            delivery_mode,
            data: bincode::serialize(&BenchmarkDatagram {
                id,
                delivery_mode,
                data: vec![0; self.size],
            })
            .expect("to serialize bulk transfer"),
            ..SendCmd::default()
        }
    }
}

impl FromStr for Transfer {
    type Err = std::num::ParseIntError;
    fn from_str(src: &str) -> std::result::Result<Self, Self::Err> {
        let args: Vec<&str> = src.split(":").collect();

        let stream_id = args[0].parse::<u8>()?;
        let size = args[1].parse::<usize>()?;
        let hertz = args[2].parse::<u32>()?;
        let return_count =
            args.get(3).map(|a| a.parse::<usize>()).transpose()?;

        Ok(Self {
            stream_id: StreamId(stream_id),
            size,
            hertz,
            return_count,
        })
    }
}

pub async fn client_main(options: Options) -> Result<Summary> {
    let address = options.address;
    match options.protocol {
        Protocol::Tcp => {
            run(
                options,
                loop {
                    let result = tcp::TcpConnection::connect(address).await;

                    let error = match result {
                        Ok(results) => break results,
                        Err(e) => e,
                    };

                    // The server port is not yet open; give it time.
                    if error.is::<std::io::Error>()
                        && error
                            .downcast_ref::<std::io::Error>()
                            .map(std::io::Error::kind)
                            == Some(std::io::ErrorKind::ConnectionRefused)
                    {
                        continue;
                    }

                    panic!(
                        "Failed to connect to benchmark server: {:?}",
                        error
                    );
                },
            )
            .await
        }
        Protocol::Enet => {
            run(options, enet::EnetConnection::connect(address).await).await
        }
    }
}
<|endoftext|>


<commit_before>use criterion::{criterion_group, criterion_main, Criterion};

criterion_main!(benches);
criterion_group!(benches, analysis_bench);

fn analysis_bench(c: &mut Criterion) {
    let data = load_soundings();

    let mut group = c.benchmark_group("Analysis");
    group.sample_size(10);

    for (key, data_vec) in data {
        group.bench_function(key, |b| {
            b.iter_batched(
                || data_vec.clone(),
                |dvec| {
                    for mut anal in dvec {
                        anal.fill_in_missing_analysis_mut();
                    }
                },
                criterion::BatchSize::LargeInput,
            )
        });
    }

    group.finish();
}

fn load_soundings() -> std::collections::HashMap<String, Vec<sonde::Analysis>> {
    use std::collections::HashMap;

    let paths = std::fs::read_dir("bench_data").expect("Error reading bench data directory");

    let mut data = HashMap::new();
    for path in paths {
        let path = path.expect("Error unwrapping DirEntry");

        let key: String = path.file_name().to_string_lossy().to_string();

        if key.contains(".DS_Store") {
            continue;
        }

        let file_type = path.file_type().expect("Error getting file type");
        if file_type.is_dir() {
            let inner_paths =
                std::fs::read_dir(path.path()).expect("Error reading bench data sub-directory");
            let mut inner_data = vec![];
            for inner_path in inner_paths {
                let inner_path = inner_path.expect("Error unwraping DirEntry");
                let file_type = inner_path.file_type().expect("Error getting file type");
                assert!(file_type.is_file());
                let inner_vec = sonde::load_file(&inner_path.path()).expect("Error loading file");
                inner_data.extend(inner_vec);
            }

            let assume_none = data.insert(key, inner_data);
            if assume_none.is_some() {
                panic!("How did we get a file twice?");
            }
        } else {
            let anal_vec = sonde::load_file(&path.path()).expect("Error loading file.");
            let assume_none = data.insert(key, anal_vec);
            if assume_none.is_some() {
                panic!("How did we get a file twice?");
            }
        }
    }

    data
}
<commit_msg>Benches now measure a per sounding/analysis time.<commit_after>use criterion::{criterion_group, criterion_main, Criterion};

criterion_main!(benches);
criterion_group!(benches, analysis_bench);

fn analysis_bench(c: &mut Criterion) {
    let data = load_soundings();

    let mut group = c.benchmark_group("Analysis");
    group.sample_size(100);

    for (key, data_vec) in data {
        group.bench_function(key, |b| {
            let mut dvec = data_vec.clone();
            b.iter_batched(
                || {
                    if dvec.is_empty() {
                        dvec = data_vec.clone();
                    }

                    dvec.pop().unwrap()
                },
                |mut anal| {
                    anal.fill_in_missing_analysis_mut();
                },
                criterion::BatchSize::LargeInput,
            )
        });
    }

    group.finish();
}

fn load_soundings() -> std::collections::HashMap<String, Vec<sonde::Analysis>> {
    use std::collections::HashMap;

    let paths = std::fs::read_dir("bench_data").expect("Error reading bench data directory");

    let mut data = HashMap::new();
    for path in paths {
        let path = path.expect("Error unwrapping DirEntry");

        let key: String = path.file_name().to_string_lossy().to_string();

        if key.contains(".DS_Store") {
            continue;
        }

        let file_type = path.file_type().expect("Error getting file type");
        if file_type.is_dir() {
            let inner_paths =
                std::fs::read_dir(path.path()).expect("Error reading bench data sub-directory");
            let mut inner_data = vec![];
            for inner_path in inner_paths {
                let inner_path = inner_path.expect("Error unwraping DirEntry");
                let file_type = inner_path.file_type().expect("Error getting file type");
                assert!(file_type.is_file());
                let inner_vec = sonde::load_file(&inner_path.path()).expect("Error loading file");
                inner_data.extend(inner_vec);
            }

            let assume_none = data.insert(key, inner_data);
            if assume_none.is_some() {
                panic!("How did we get a file twice?");
            }
        } else {
            let anal_vec = sonde::load_file(&path.path()).expect("Error loading file.");
            let assume_none = data.insert(key, anal_vec);
            if assume_none.is_some() {
                panic!("How did we get a file twice?");
            }
        }
    }

    data
}
<|endoftext|>


<commit_before>fn main() {
    // Get the memory address of a variable
    let var = 1_i32;
    println!("address of var: {:p}", &var);

    // Get the value at a certain memory address
    let address = &var as *const i32;
    println!("value at {:p}: {:?}", &address, var);

    // Set the value at a certain memory address
    unsafe {
        *(address as *mut i32) = 0;
        println!("value at {:p}: {:?}", address, var);
    }
}
<commit_msg>Update main.rs<commit_after>fn main() {
    // Get the memory address of a variable
    let var = 1_i32;
    println!("address of var: {:p}", &var);

    // Get the value at a certain memory address
    let address = &var as *const i32;
    println!("value at {:p}: {:?}", address, var);

    // Set the value at a certain memory address
    unsafe {
        *(address as *mut i32) = 0;
        println!("value at {:p}: {:?}", address, var);
    }
}
<|endoftext|>


<commit_before>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut VISITOR_COUNT: int = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println(format!("Received request :\n{:s}", request_str));
            unsafe { VISITOR_COUNT += 1 };

            let response: ~str =
                ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!
" +
                 format!("
Number of visits: {:d}
", unsafe { VISITOR_COUNT }) +
                 "\r\n";
            stream.write(response.as_bytes());
            println!("Connection terminates.");
        }
    }
}
<commit_msg>added response to requested files<commit_after>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut VISITOR_COUNT: int = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println(format!("Received request :\n{:s}", request_str));
            let pa = match request_str.find_str("/") {
                Some(x) => x,
                None => -1,
            };
            let th = match request_str.find_str(" HTTP") {
                Some(x) => x,
                None => -1,
            };

            if pa == -1 || th == -1 {
                println!("Error parsing request");
            }
            else if (pa+1) == th {
                unsafe { VISITOR_COUNT += 1 };

                let response: ~str =
                    ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                     <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!
" +
                     format!("
Number of visits: {:d}
", unsafe { VISITOR_COUNT }) +
                     "\r\n";
                stream.write(response.as_bytes());
            }
            else {
                match File::open(&Path::new(request_str.slice(pa+1, th))) {
                    Some(mut file) => {
                        let contents =
                            "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes() +
                            file.read_to_end();
                        stream.write(contents);
                    },
                    None => println!("Error reading file"),
                }
            }

            println!("Connection terminates.");
        }
    }
}

<|endoftext|>


<commit_before>use log::{debug};

use super::arch::RVA;

const PAGE_SIZE: usize = 0x1000;

#[derive(Debug)]
pub enum Error {
    NotMapped,
}

fn page(rva: RVA) -> usize {
    // depends on PAGE_SIZE
    let v: u64 = rva.into();
    // #yolo
    (v as usize) >> 12
}

fn page_offset(rva: RVA) -> usize {
    // depends on PAGE_SIZE
    let v: u64 = rva.into();
    // #yolo
    (v as usize) & 0xFFF
}

pub struct Page<T: Default + Copy> {
    pub elements: [T; PAGE_SIZE],
}

impl<T: Default + Copy> Page<T> {
    pub fn new(items: &[T]) -> Page<T> {
        let mut page: Page<T> = Default::default();
        page.elements.copy_from_slice(items);
        page
    }
}

impl<T: Default + Copy> Default for Page<T> {
    fn default() -> Self {
        Page {
            elements: [Default::default(); PAGE_SIZE]
        }
    }
}

pub struct PageMap<T: Default + Copy> {
    pages: Vec<Option<Page<T>>>
}

impl<T: Default + Copy> PageMap<T> {
    pub fn with_capacity(capacity: RVA) -> PageMap<T>{
        let page_count = page(capacity) + 1;
        let mut pages = Vec::with_capacity(page_count);
        pages.resize_with(page_count, || None);

        PageMap {
            pages
        }
    }

    /// error if rva is not in a valid page.
    /// panic due to:
    ///   - rva must be page aligned.
    ///   - must be PAGE_SIZE number of items.
    fn map_page(&mut self, rva: RVA, items: &[T]) -> Result<(), Error> {
        if page_offset(rva) != 0 {
            panic!("invalid map address");
        }
        if items.len() != PAGE_SIZE {
            panic!("invalid map buffer size");
        }
        debug!("mapping page: {}", rva);
        if page(rva) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        self.pages[page(rva)] = Some(Page::new(items));

        Ok(())
    }

    /// map the given items at the given address.
    ///
    /// error if rva or items are not in a valid page.
    /// panic due to:
    ///   - rva must be page aligned.
    ///   - must be multiple of PAGE_SIZE number of items.
    ///
    /// see example under `get`.
    pub fn map(&mut self, rva: RVA, items: &[T]) -> Result<(), Error> {
        for (i, chunk) in items.chunks_exact(PAGE_SIZE).enumerate() {
            self.map_page(rva + i * PAGE_SIZE, chunk)?;
        }
        Ok(())
    }

    /// map the default value (probably zero) at the given address for the given size.
    ///
    /// same error conditions as `map`.
    /// see example under `probe`.
    pub fn map_empty(&mut self, rva: RVA, size: usize) -> Result<(), Error> {
        self.map(rva, &vec![Default::default(); size])
    }

    /// is the given address mapped?
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::pagemap::PageMap;
    ///
    /// let mut d: PageMap<u32> = PageMap::with_capacity(0x2000.into());
    /// assert_eq!(d.probe(0x0.into()), false);
    /// assert_eq!(d.probe(0x1000.into()), false);
    ///
    /// d.map_empty(0x0.into(), 0x1000).expect("failed to map");
    /// assert_eq!(d.probe(0x0.into()), true);
    /// assert_eq!(d.probe(0x1000.into()), false);
    /// ```
    pub fn probe(&self, rva: RVA) -> bool {
        if page(rva) > self.pages.len() {
            return false;
        }

        return self.pages[page(rva)].is_some()
    }

    /// fetch one item from the given address.
    /// if the address is not mapped, then the result is `None`.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::pagemap::PageMap;
    ///
    /// let mut d: PageMap<u32> = PageMap::with_capacity(0x2000.into());
    /// assert_eq!(d.get(0x0.into()), None);
    /// assert_eq!(d.get(0x1000.into()), None);
    ///
    /// d.map(0x1000.into(), &[0x1; 0x1000]).expect("failed to map");
    /// assert_eq!(d.get(0x0.into()), None);
    /// assert_eq!(d.get(0x1000.into()), Some(0x1));
    ///
    /// d.map(0x0.into(), &[0x2; 0x2000]).expect("failed to map");
    ///  assert_eq!(d.get(0x0.into()), Some(0x2));
    ///  assert_eq!(d.get(0x1000.into()), Some(0x2));
    /// ```
    pub fn get(&self, rva: RVA) -> Option<T> {
        if page(rva) > self.pages.len() {
            return None;
        }

        let page = match &self.pages[page(rva)] {
            // page is not mapped
            None => return None,
            // page is mapped
            Some(page) => page,
        };

        Some(page.elements[page_offset(rva)])

    }

    /// handle the simple slice case: when start and end fall within the same page.
    /// for example, reading a dword from address 0x10.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::pagemap::PageMap;
    ///
    /// let mut d: PageMap<u32> = PageMap::with_capacity(0x2000.into());
    /// d.map_empty(0x0.into(), 0x1000).expect("failed to map");
    /// assert_eq!(d.slice(0x0.into(), 0x2.into()).unwrap(), [0x0, 0x0]);
    /// ```
    fn slice_simple(&self, start: RVA, end: RVA) -> Result<Vec<T>, Error> {
        if page(start) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        let page = match &self.pages[page(start)] {
            // page is not mapped
            None => return Err(Error::NotMapped),
            // page is mapped
            Some(page) => page,
        };

        Ok(page.elements[page_offset(start)..page_offset(end)].to_vec())
    }

    /// handle the complex slice case: when start and end are on different pages.
    /// for example, reading a dword from address 0xFFE.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::pagemap::PageMap;
    ///
    /// let mut d: PageMap<u32> = PageMap::with_capacity(0x5000.into());
    /// d.map_empty(0x1000.into(), 0x3000).expect("failed to map");
    ///
    /// // 0     unmapped
    /// //       unmapped
    /// // 1000  0 0 0 0
    /// //       0 0 0 0
    /// // 2000  0 0 0 0
    /// //       0 0 0 0
    /// // 3000  0 0 0 0
    /// //       0 0 0 0
    /// // 4000  unmapped
    /// //       unmapped
    /// // 5000  unmapped
    ///
    /// assert_eq!(d.slice(0x1FFC.into(), 0x2000.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "no overlap");
    /// assert_eq!(d.slice(0x1FFD.into(), 0x2001.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 1");
    /// assert_eq!(d.slice(0x1FFE.into(), 0x2002.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 2");
    /// assert_eq!(d.slice(0x1FFF.into(), 0x2003.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 3");
    /// assert_eq!(d.slice(0x2000.into(), 0x2004.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 4");
    ///
    /// assert_eq!(d.slice(0x1FFC.into(), 0x3004.into()).unwrap().len(), 0x1008, "4, page, 4");
    ///
    /// assert_eq!(d.slice(0x1FFC.into(), 0x3000.into()).unwrap().len(), 0x1004, "4, page");
    ///
    /// assert_eq!(d.slice(0x2000.into(), 0x3004.into()).unwrap().len(), 0x1004, "page, 4");
    /// ```
    fn slice_split(&self, start: RVA, end: RVA) -> Result<Vec<T>, Error> {
        // precondition: end > start

        if page(end) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        // ensure each page within the requested region is mapped.
        let start_page = page(start);
        let end_page = if page_offset(end) == 0 { page(end) - 1} else { page(end) };
        for page in start_page..end_page {
            if ! self.probe((page * PAGE_SIZE).into()) {
                return Err(Error::NotMapped);
            }
        }

        let mut ret: Vec<T> = Vec::with_capacity((end - start).into());

        // region one: from `start` to the end of its page
        // region two: any intermediate complete pages
        // region three: from start of final page until `end`

        // one.
        {
            let page = self.pages[page(start)].as_ref().unwrap();
            let buf = &page.elements[page_offset(start)..];
            ret.extend_from_slice(buf);
        }

        // two.
        if page(start) != page(end) - 1 {
            let start_index = page(start) + 1;
            let end_index = page(end);
            for page_index in start_index..end_index {
                let page = self.pages[page_index].as_ref().unwrap();
                let buf = &page.elements[..];
                ret.extend_from_slice(buf);
            }
        }

        // three.
        if page_offset(end) != 0x0 {
            let page = self.pages[page(end)].as_ref().unwrap();
            let buf = &page.elements[..page_offset(end)];
            ret.extend_from_slice(buf);
        }

        Ok(ret)
    }

    /// fetch the items found in the given range.
    ///
    /// errors:
    ///   - Error::NotMapped: if any requested address is not mapped
    ///
    /// panic if:
    ///   - start > end
    pub fn slice(&self, start: RVA, end: RVA) -> Result<Vec<T>, Error> {
        if start > end {
            panic!("start > end");
        }

        if page(start) == page(end) {
            self.slice_simple(start, end)
        } else {
            self.slice_split(start, end)
        }
    }

    // TODO: slice_into
}
<commit_msg>pagemap: implement slice_into<commit_after>use log::{debug};

use super::arch::RVA;

const PAGE_SIZE: usize = 0x1000;

#[derive(Debug)]
pub enum Error {
    NotMapped,
}

fn page(rva: RVA) -> usize {
    // depends on PAGE_SIZE
    let v: u64 = rva.into();
    // #yolo
    (v as usize) >> 12
}

fn page_offset(rva: RVA) -> usize {
    // depends on PAGE_SIZE
    let v: u64 = rva.into();
    // #yolo
    (v as usize) & 0xFFF
}

struct Page<T: Default + Copy> {
    elements: [T; PAGE_SIZE],
}

impl<T: Default + Copy> Page<T> {
    fn new(items: &[T]) -> Page<T> {
        let mut page: Page<T> = Default::default();
        page.elements.copy_from_slice(items);
        page
    }
}

impl<T: Default + Copy> Default for Page<T> {
    fn default() -> Self {
        Page {
            elements: [Default::default(); PAGE_SIZE]
        }
    }
}

/// PageMap is a map-like data structure that stores `Copy` elements in pages of 0x1000.
///
/// Its a good choice when representing lots of small elements that are found at
/// contiguous indices. At the moment, indices are `RVA`.
///
/// Lookups should be quick, as they boil down to just a couple dereferences.
pub struct PageMap<T: Default + Copy> {
    pages: Vec<Option<Page<T>>>
}

impl<T: Default + Copy> PageMap<T> {
    pub fn with_capacity(capacity: RVA) -> PageMap<T>{
        let page_count = page(capacity) + 1;
        let mut pages = Vec::with_capacity(page_count);
        pages.resize_with(page_count, || None);

        PageMap {
            pages
        }
    }

    /// error if rva is not in a valid page.
    /// panic due to:
    ///   - rva must be page aligned.
    ///   - must be PAGE_SIZE number of items.
    fn map_page(&mut self, rva: RVA, items: &[T]) -> Result<(), Error> {
        if page_offset(rva) != 0 {
            panic!("invalid map address");
        }
        if items.len() != PAGE_SIZE {
            panic!("invalid map buffer size");
        }
        debug!("mapping page: {}", rva);
        if page(rva) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        self.pages[page(rva)] = Some(Page::new(items));

        Ok(())
    }

    /// map the given items at the given address.
    ///
    /// error if rva or items are not in a valid page.
    /// panic due to:
    ///   - rva must be page aligned.
    ///   - must be multiple of PAGE_SIZE number of items.
    ///
    /// see example under `get`.
    pub fn map(&mut self, rva: RVA, items: &[T]) -> Result<(), Error> {
        for (i, chunk) in items.chunks_exact(PAGE_SIZE).enumerate() {
            self.map_page(rva + i * PAGE_SIZE, chunk)?;
        }
        Ok(())
    }

    /// map the default value (probably zero) at the given address for the given size.
    ///
    /// same error conditions as `map`.
    /// see example under `probe`.
    pub fn map_empty(&mut self, rva: RVA, size: usize) -> Result<(), Error> {
        self.map(rva, &vec![Default::default(); size])
    }

    /// is the given address mapped?
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::pagemap::PageMap;
    ///
    /// let mut d: PageMap<u32> = PageMap::with_capacity(0x2000.into());
    /// assert_eq!(d.probe(0x0.into()), false);
    /// assert_eq!(d.probe(0x1000.into()), false);
    ///
    /// d.map_empty(0x0.into(), 0x1000).expect("failed to map");
    /// assert_eq!(d.probe(0x0.into()), true);
    /// assert_eq!(d.probe(0x1000.into()), false);
    /// ```
    pub fn probe(&self, rva: RVA) -> bool {
        if page(rva) > self.pages.len() {
            return false;
        }

        return self.pages[page(rva)].is_some()
    }

    /// fetch one item from the given address.
    /// if the address is not mapped, then the result is `None`.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::pagemap::PageMap;
    ///
    /// let mut d: PageMap<u32> = PageMap::with_capacity(0x2000.into());
    /// assert_eq!(d.get(0x0.into()), None);
    /// assert_eq!(d.get(0x1000.into()), None);
    ///
    /// d.map(0x1000.into(), &[0x1; 0x1000]).expect("failed to map");
    /// assert_eq!(d.get(0x0.into()), None);
    /// assert_eq!(d.get(0x1000.into()), Some(0x1));
    ///
    /// d.map(0x0.into(), &[0x2; 0x2000]).expect("failed to map");
    ///  assert_eq!(d.get(0x0.into()), Some(0x2));
    ///  assert_eq!(d.get(0x1000.into()), Some(0x2));
    /// ```
    pub fn get(&self, rva: RVA) -> Option<T> {
        if page(rva) > self.pages.len() {
            return None;
        }

        let page = match &self.pages[page(rva)] {
            // page is not mapped
            None => return None,
            // page is mapped
            Some(page) => page,
        };

        Some(page.elements[page_offset(rva)])
    }

    /// fetch one mutable item from the given address.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::pagemap::PageMap;
    ///
    /// let mut d: PageMap<u32> = PageMap::with_capacity(0x2000.into());
    /// d.map_empty(0x0.into(), 0x1000).expect("failed to map");
    ///
    /// // address 0x0 starts at 0
    /// assert_eq!(d.get(0x0.into()), Some(0x0));
    ///
    /// // set address 0x0 to 1
    /// let v = d.get_mut(0x0.into()).expect("should be mapped");
    /// *v = 1;
    ///
    /// // address 0x0 is 1
    /// assert_eq!(d.get(0x0.into()), Some(0x1));
    /// ```
    pub fn get_mut(&mut self, rva: RVA) -> Option<&mut T> {
        if page(rva) > self.pages.len() {
            return None;
        }

        let page = match &mut self.pages[page(rva)] {
            // page is not mapped
            None => return None,
            // page is mapped
            Some(page) => page,
        };

        Some(&mut page.elements[page_offset(rva)])
    }

    /// handle the simple slice case: when start and end fall within the same page.
    /// for example, reading a dword from address 0x10.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::pagemap::PageMap;
    ///
    /// let mut d: PageMap<u32> = PageMap::with_capacity(0x2000.into());
    /// d.map_empty(0x0.into(), 0x1000).expect("failed to map");
    /// assert_eq!(d.slice(0x0.into(), 0x2.into()).unwrap(), [0x0, 0x0]);
    /// ```
    fn slice_into_simple(&self, start: RVA, buf: &mut [T]) -> Result<(), Error> {
        // precondition: page(start) == page(start + buf.len())

        if page(start) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        let page = match &self.pages[page(start)] {
            // page is not mapped
            None => return Err(Error::NotMapped),
            // page is mapped
            Some(page) => page,
        };

        let end = start + buf.len();
        let elements = &page.elements[page_offset(start)..page_offset(end)];
        buf.copy_from_slice(elements);

        Ok(())
    }

    /// handle the complex slice case: when start and end are on different pages.
    /// for example, reading a dword from address 0xFFE.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::pagemap::PageMap;
    ///
    /// let mut d: PageMap<u32> = PageMap::with_capacity(0x5000.into());
    /// d.map_empty(0x1000.into(), 0x3000).expect("failed to map");
    ///
    /// // 0     unmapped
    /// //       unmapped
    /// // 1000  0 0 0 0
    /// //       0 0 0 0
    /// // 2000  0 0 0 0
    /// //       0 0 0 0
    /// // 3000  0 0 0 0
    /// //       0 0 0 0
    /// // 4000  unmapped
    /// //       unmapped
    /// // 5000  unmapped
    ///
    /// assert_eq!(d.slice(0x1FFC.into(), 0x2000.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "no overlap");
    /// assert_eq!(d.slice(0x1FFD.into(), 0x2001.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 1");
    /// assert_eq!(d.slice(0x1FFE.into(), 0x2002.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 2");
    /// assert_eq!(d.slice(0x1FFF.into(), 0x2003.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 3");
    /// assert_eq!(d.slice(0x2000.into(), 0x2004.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 4");
    ///
    /// assert_eq!(d.slice(0x1FFC.into(), 0x3004.into()).unwrap().len(), 0x1008, "4, page, 4");
    ///
    /// assert_eq!(d.slice(0x1FFC.into(), 0x3000.into()).unwrap().len(), 0x1004, "4, page");
    ///
    /// assert_eq!(d.slice(0x2000.into(), 0x3004.into()).unwrap().len(), 0x1004, "page, 4");
    /// ```
    fn slice_into_split(&self, start: RVA, buf: &mut [T]) -> Result<(), Error> {
        let end = start + buf.len();

        if page(end) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        // ensure each page within the requested region is mapped.
        let start_page = page(start);
        let end_page = if page_offset(end) == 0 { page(end) - 1} else { page(end) };
        for page in start_page..end_page {
            if ! self.probe((page * PAGE_SIZE).into()) {
                return Err(Error::NotMapped);
            }
        }

        let mut offset: usize = 0;

        // region one: from `start` to the end of its page
        // region two: any intermediate complete pages
        // region three: from start of final page until `end`

        // one.
        {
            let page = self.pages[page(start)].as_ref().unwrap();
            let elements = &page.elements[page_offset(start)..];
            {
                let dst = &mut buf[offset..offset+elements.len()];
                dst.copy_from_slice(elements);
                offset += elements.len();
            }
        }

        // two.
        if page(start) != page(end) - 1 {
            let start_index = page(start) + 1;
            let end_index = page(end);
            for page_index in start_index..end_index {
                let page = self.pages[page_index].as_ref().unwrap();
                let elements = &page.elements[..];
                {
                    let dst = &mut buf[offset..offset+elements.len()];
                    dst.copy_from_slice(elements);
                    offset += elements.len();
                }
            }
        }

        // three.
        if page_offset(end) != 0x0 {
            let page = self.pages[page(end)].as_ref().unwrap();
            let elements = &page.elements[..page_offset(end)];
            {
                let dst = &mut buf[offset..offset+elements.len()];
                dst.copy_from_slice(elements);
            }
        }

        Ok(())
    }

    /// fetch the items found in the given range, placing them into the given slice.
    /// compared with `slice`, this routine avoids an allocation.
    ///
    /// errors:
    ///   - Error::NotMapped: if any requested address is not mapped
    pub fn slice_into(&self, start: RVA, buf: &mut [T]) -> Result<(), Error> {
        let end = start + buf.len();
        if page(start) == page(end) {
            self.slice_into_simple(start, buf)
        } else {
            self.slice_into_split(start, buf)
        }
    }

    /// fetch the items found in the given range.
    ///
    /// errors:
    ///   - Error::NotMapped: if any requested address is not mapped
    ///
    /// panic if:
    ///   - start > end
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::pagemap::PageMap;
    ///
    /// let mut d: PageMap<u32> = PageMap::with_capacity(0x2000.into());
    /// d.map_empty(0x0.into(), 0x1000).expect("failed to map");
    /// assert_eq!(d.slice(0x0.into(), 0x2.into()).unwrap(), [0x0, 0x0]);
    /// ```
    pub fn slice(&self, start: RVA, end: RVA) -> Result<Vec<T>, Error> {
        if start > end {
            panic!("start > end");
        }

        let mut ret = vec![Default::default(); (end - start).into()];
        self.slice_into(start, &mut ret)?;

        Ok(ret)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::env;
use std::ffi::OsStr;
use std::io;
use std::path::PathBuf;

use clap::{App, Arg, ArgMatches};
use console::style;
use failure::Error;
use if_chain::if_chain;
use proguard::ProguardMapping;
use serde::Serialize;
use symbolic::common::{ByteView, DebugId};
use uuid::Version as UuidVersion;
use walkdir::WalkDir;

use crate::utils::args::validate_id;
use crate::utils::dif::{DifFile, DifType};
use crate::utils::progress::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use crate::utils::system::QuietExit;

// text files larger than 32 megabytes are not considered to be
// valid mapping files when scanning
const MAX_MAPPING_FILE: u64 = 32 * 1024 * 1024;

#[derive(Serialize, Debug)]
struct DifMatch {
    #[serde(rename = "type")]
    pub ty: DifType,
    pub id: DebugId,
    pub path: PathBuf,
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("Locate debug information files for given debug identifiers.")
        .arg(
            Arg::with_name("types")
                .long("type")
                .short("t")
                .value_name("TYPE")
                .multiple(true)
                .number_of_values(1)
                .possible_values(&[
                    "dsym",
                    "elf",
                    "pe",
                    "pdb",
                    "proguard",
                    "breakpad",
                    "sourcebundle",
                ])
                .help(
                    "Only consider debug information files of the given \
                     type.  By default all types are considered.",
                ),
        )
        .arg(
            Arg::with_name("no_well_known")
                .long("no-well-known")
                .help("Do not look for debug symbols in well known locations."),
        )
        .arg(
            Arg::with_name("no_cwd")
                .long("no-cwd")
                .help("Do not look for debug symbols in the current working directory."),
        )
        .arg(
            Arg::with_name("paths")
                .long("path")
                .short("p")
                .multiple(true)
                .number_of_values(1)
                .help("Add a path to search recursively for debug info files."),
        )
        .arg(
            Arg::with_name("json")
                .long("json")
                .help("Format outputs as JSON."),
        )
        .arg(
            Arg::with_name("ids")
                .index(1)
                .value_name("ID")
                .help("The debug identifiers of the files to search for.")
                .validator(validate_id)
                .multiple(true)
                .number_of_values(1),
        )
}

fn id_hint(id: &DebugId) -> &'static str {
    if id.appendix() > 0 {
        return "likely PDB";
    }

    match id.uuid().get_version() {
        Some(UuidVersion::Sha1) => "likely Proguard",
        Some(UuidVersion::Md5) => "likely dSYM",
        None => "likely ELF Debug",
        _ => "unknown",
    }
}

// TODO: Reduce complexity of this function
#[allow(clippy::cognitive_complexity)]
fn find_ids(
    paths: &HashSet<PathBuf>,
    types: &HashSet<DifType>,
    ids: &HashSet<DebugId>,
    as_json: bool,
) -> Result<bool, Error> {
    let mut remaining = ids.clone();
    let mut breakpad_found = HashSet::new();
    let mut proguard_uuids: HashSet<_> = ids
        .iter()
        .map(DebugId::uuid)
        .filter(|&x| x.get_version() == Some(UuidVersion::Sha1))
        .collect();

    let iter = paths
        .iter()
        .flat_map(WalkDir::new)
        .filter_map(Result::ok)
        .filter(|e| e.file_type().is_file());

    let mut found_files = vec![];
    let pb = ProgressBar::new_spinner();
    pb.set_draw_target(ProgressDrawTarget::stdout());
    pb.set_style(
        ProgressStyle::default_spinner()
            .tick_chars("/|\\- ")
            .template(
                "{spinner} Looking for debug info files... {msg:.dim}\
                 \n  debug info files found: {prefix:.yellow}",
            ),
    );

    for dirent in iter {
        if remaining.is_empty() {
            break;
        }

        if let Some(p) = dirent.file_name().to_str() {
            pb.set_message(p);
        }
        pb.tick();
        pb.set_prefix(&format!("{}", found_files.len()));

        let mut found = vec![];

        // specifically look for proguard files.  We only look for UUID5s
        // and only if the file is a text file.
        if_chain! {
            if !proguard_uuids.is_empty();
            if types.contains(&DifType::Proguard);
            if dirent.path().extension() == Some(OsStr::new("txt"));
            if let Ok(md) = dirent.metadata();
            if md.len() < MAX_MAPPING_FILE;
            if let Ok(byteview) = ByteView::open(dirent.path());
            let mapping = ProguardMapping::new(&byteview);
            if mapping.is_valid();
            if proguard_uuids.contains(&mapping.uuid());
            then {
                found.push((mapping.uuid().into(), DifType::Proguard));
            }
        }

        // look for dsyms
        if_chain! {
            if types.contains(&DifType::Dsym);
            // we regularly match on .class files but the will never be
            // dsyms, so we can quickly skip them here
            if dirent.path().extension() != Some(OsStr::new("class"));
            if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::Dsym));
            then {
                for id in dif.ids() {
                    if remaining.contains(&id) {
                        found.push((id, DifType::Dsym));
                    }
                }
            }
        }

        // look for elfs
        if_chain! {
            if types.contains(&DifType::Elf);
            if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::Elf));
            then {
                for id in dif.ids() {
                    if remaining.contains(&id) {
                        found.push((id, DifType::Elf));
                    }
                }
            }
        }

        // look for PEs
        if_chain! {
            if types.contains(&DifType::Pe);
            if dirent.path().extension() == Some(OsStr::new("exe")) ||
            dirent.path().extension() == Some(OsStr::new("dll"));
            if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::Pe));
            then {
                for id in dif.ids() {
                    if remaining.contains(&id) {
                        found.push((id, DifType::Pe));
                    }
                }
            }
        }

        // look for PDBs
        if_chain! {
            if types.contains(&DifType::Pdb);
            if dirent.path().extension() == Some(OsStr::new("pdb"));
            if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::Pdb));
            then {
                for id in dif.ids() {
                    if remaining.contains(&id) {
                        found.push((id, DifType::Pdb));
                    }
                }
            }
        }

        // look for breakpad files
        if_chain! {
            if types.contains(&DifType::Breakpad);
            if dirent.path().extension() == Some(OsStr::new("sym"));
            if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::Breakpad));
            then {
                for id in dif.ids() {
                    if remaining.contains(&id) {
                        found.push((id, DifType::Breakpad));
                    }
                }
            }
        }

        // look for source bundles
        if_chain! {
            if types.contains(&DifType::SourceBundle);
            if dirent.path().extension() == Some(OsStr::new("zip"));
            if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::SourceBundle));
            then {
                for id in dif.ids() {
                    if remaining.contains(&id) {
                        found.push((id, DifType::SourceBundle));
                    }
                }
            }
        }

        for (id, ty) in found {
            let path = dirent.path().to_path_buf();
            found_files.push(DifMatch { ty, id, path });
            if ty == DifType::Breakpad {
                breakpad_found.insert(id);
            } else {
                remaining.remove(&id);
            }
            proguard_uuids.remove(&id.uuid());
        }
    }

    pb.finish_and_clear();

    if as_json {
        serde_json::to_writer_pretty(&mut io::stdout(), &found_files)?;
        println!();
    } else {
        for m in found_files {
            println!(
                "{} {} [{}]",
                style(m.id).dim(),
                m.path.display(),
                style(m.ty).yellow()
            );
        }
        remaining.extend(breakpad_found);
        if !remaining.is_empty() {
            eprintln!();
            eprintln!("missing debug information files:");
            for id in &remaining {
                eprintln!("  {} ({})", id, id_hint(id),);
            }
        }
    }

    Ok(remaining.is_empty())
}

pub fn execute(matches: &ArgMatches<'_>) -> Result<(), Error> {
    let mut paths = HashSet::new();
    let mut types = HashSet::new();
    let mut ids = HashSet::new();

    // which types should we consider?
    if let Some(t) = matches.values_of("types") {
        for ty in t {
            types.insert(ty.parse().unwrap());
        }
    } else {
        types.insert(DifType::Dsym);
        types.insert(DifType::Pdb);
        types.insert(DifType::Pe);
        types.insert(DifType::Proguard);
        types.insert(DifType::SourceBundle);
        types.insert(DifType::Breakpad);
    }

    let with_well_known = !matches.is_present("no_well_known");
    let with_cwd = !matches.is_present("no_cwd");

    // start adding well known locations
    if_chain! {
        if with_well_known;
        if types.contains(&DifType::Dsym);
        if let Some(path) = dirs::home_dir().map(|x| x.join("Library/Developer/Xcode/DerivedData"));
        if path.is_dir();
        then {
            paths.insert(path);
        }
    }

    // current folder if wanted
    if_chain! {
        if with_cwd;
        if let Ok(path) = env::current_dir();
        then {
            paths.insert(path);
        }
    }

    // extra paths
    if let Some(p) = matches.values_of("paths") {
        for path in p {
            paths.insert(PathBuf::from(path));
        }
    }

    // which ids are we looking for?
    if let Some(i) = matches.values_of("ids") {
        for id in i {
            ids.insert(id.parse().unwrap());
        }
    } else {
        return Ok(());
    }

    if !find_ids(&paths, &types, &ids, matches.is_present("json"))? {
        return Err(QuietExit(1).into());
    }

    Ok(())
}
<commit_msg>ref: Rework find_id function of difutil find (#1149)<commit_after>use std::collections::HashSet;
use std::env;
use std::ffi::OsStr;
use std::io;
use std::path::PathBuf;

use clap::{App, Arg, ArgMatches};
use console::style;
use failure::Error;
use if_chain::if_chain;
use proguard::ProguardMapping;
use serde::Serialize;
use symbolic::common::{ByteView, DebugId};
use uuid::{Uuid, Version as UuidVersion};
use walkdir::{DirEntry, WalkDir};

use crate::utils::args::validate_id;
use crate::utils::dif::{DifFile, DifType};
use crate::utils::progress::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use crate::utils::system::QuietExit;

// text files larger than 32 megabytes are not considered to be
// valid mapping files when scanning
const MAX_MAPPING_FILE: u64 = 32 * 1024 * 1024;

#[derive(Serialize, Debug)]
struct DifMatch {
    #[serde(rename = "type")]
    pub ty: DifType,
    pub id: DebugId,
    pub path: PathBuf,
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("Locate debug information files for given debug identifiers.")
        .arg(
            Arg::with_name("types")
                .long("type")
                .short("t")
                .value_name("TYPE")
                .multiple(true)
                .number_of_values(1)
                .possible_values(&[
                    "dsym",
                    "elf",
                    "pe",
                    "pdb",
                    "proguard",
                    "breakpad",
                    "sourcebundle",
                ])
                .help(
                    "Only consider debug information files of the given \
                     type.  By default all types are considered.",
                ),
        )
        .arg(
            Arg::with_name("no_well_known")
                .long("no-well-known")
                .help("Do not look for debug symbols in well known locations."),
        )
        .arg(
            Arg::with_name("no_cwd")
                .long("no-cwd")
                .help("Do not look for debug symbols in the current working directory."),
        )
        .arg(
            Arg::with_name("paths")
                .long("path")
                .short("p")
                .multiple(true)
                .number_of_values(1)
                .help("Add a path to search recursively for debug info files."),
        )
        .arg(
            Arg::with_name("json")
                .long("json")
                .help("Format outputs as JSON."),
        )
        .arg(
            Arg::with_name("ids")
                .index(1)
                .value_name("ID")
                .help("The debug identifiers of the files to search for.")
                .validator(validate_id)
                .multiple(true)
                .number_of_values(1),
        )
}

fn id_hint(id: &DebugId) -> &'static str {
    if id.appendix() > 0 {
        return "likely PDB";
    }

    match id.uuid().get_version() {
        Some(UuidVersion::Sha1) => "likely Proguard",
        Some(UuidVersion::Md5) => "likely dSYM",
        None => "likely ELF Debug",
        _ => "unknown",
    }
}

fn find_ids(
    paths: &HashSet<PathBuf>,
    types: &HashSet<DifType>,
    ids: &HashSet<DebugId>,
    as_json: bool,
) -> Result<bool, Error> {
    let mut remaining = ids.clone();
    let mut breakpad_found = HashSet::new();
    let mut proguard_uuids: HashSet<_> = ids
        .iter()
        .map(DebugId::uuid)
        .filter(|&x| x.get_version() == Some(UuidVersion::Sha1))
        .collect();

    let iter = paths
        .iter()
        .flat_map(WalkDir::new)
        .filter_map(Result::ok)
        .filter(|e| e.file_type().is_file());

    let mut found_files = vec![];
    let pb = ProgressBar::new_spinner();
    pb.set_draw_target(ProgressDrawTarget::stdout());
    pb.set_style(
        ProgressStyle::default_spinner()
            .tick_chars("/|\\- ")
            .template(
                "{spinner} Looking for debug info files... {msg:.dim}\
                 \n  debug info files found: {prefix:.yellow}",
            ),
    );

    for dirent in iter {
        if remaining.is_empty() {
            break;
        }

        if let Some(p) = dirent.file_name().to_str() {
            pb.set_message(p);
        }
        pb.tick();
        pb.set_prefix(&format!("{}", found_files.len()));

        let found: Vec<_> = types
            .iter()
            .filter_map(|t| match t {
                DifType::Dsym => find_ids_for_dsym(&dirent, &remaining),
                DifType::Elf => find_ids_for_elf(&dirent, &remaining),
                DifType::Pe => find_ids_for_pe(&dirent, &remaining),
                DifType::Pdb => find_ids_for_pdb(&dirent, &remaining),
                DifType::SourceBundle => find_ids_for_sourcebundle(&dirent, &remaining),
                DifType::Breakpad => find_ids_for_breakpad(&dirent, &remaining),
                DifType::Proguard => find_ids_for_proguard(&dirent, &proguard_uuids),
                DifType::Wasm => None,
            })
            .flatten()
            .collect();

        for (id, ty) in found {
            let path = dirent.path().to_path_buf();
            found_files.push(DifMatch { ty, id, path });
            if ty == DifType::Breakpad {
                breakpad_found.insert(id);
            } else {
                remaining.remove(&id);
            }
            proguard_uuids.remove(&id.uuid());
        }
    }

    pb.finish_and_clear();

    if as_json {
        serde_json::to_writer_pretty(&mut io::stdout(), &found_files)?;
        println!();
    } else {
        for m in found_files {
            println!(
                "{} {} [{}]",
                style(m.id).dim(),
                m.path.display(),
                style(m.ty).yellow()
            );
        }
        remaining.extend(breakpad_found);
        if !remaining.is_empty() {
            eprintln!();
            eprintln!("missing debug information files:");
            for id in &remaining {
                eprintln!("  {} ({})", id, id_hint(id),);
            }
        }
    }

    Ok(remaining.is_empty())
}

fn find_ids_for_proguard(
    dirent: &DirEntry,
    proguard_uuids: &HashSet<Uuid>,
) -> Option<Vec<(DebugId, DifType)>> {
    if_chain! {
        if !proguard_uuids.is_empty();
        if dirent.path().extension() == Some(OsStr::new("txt"));
        if let Ok(md) = dirent.metadata();
        if md.len() < MAX_MAPPING_FILE;
        if let Ok(byteview) = ByteView::open(dirent.path());
        let mapping = ProguardMapping::new(&byteview);
        if mapping.is_valid();
        if proguard_uuids.contains(&mapping.uuid());
        then {
            return Some(vec![(mapping.uuid().into(), DifType::Proguard)]);
        }
    }
    None
}

fn find_ids_for_dsym(
    dirent: &DirEntry,
    remaining: &HashSet<DebugId>,
) -> Option<Vec<(DebugId, DifType)>> {
    if_chain! {
        // we regularly match on .class files but the will never be
        // dsyms, so we can quickly skip them here
        if dirent.path().extension() != Some(OsStr::new("class"));
        if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::Dsym));
        then {
            return Some(extract_remaining_ids(&dif.ids(), remaining, DifType::Dsym))
        }
    }
    None
}

fn find_ids_for_elf(
    dirent: &DirEntry,
    remaining: &HashSet<DebugId>,
) -> Option<Vec<(DebugId, DifType)>> {
    if_chain! {
        if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::Elf));
        then {
            return Some(extract_remaining_ids(&dif.ids(), remaining, DifType::Elf))
        }
    }
    None
}

fn find_ids_for_pe(
    dirent: &DirEntry,
    remaining: &HashSet<DebugId>,
) -> Option<Vec<(DebugId, DifType)>> {
    if_chain! {
        if dirent.path().extension() == Some(OsStr::new("exe")) ||
        dirent.path().extension() == Some(OsStr::new("dll"));
        if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::Pe));
        then {
            return Some(extract_remaining_ids(&dif.ids(), remaining, DifType::Pe))
        }
    }
    None
}

fn find_ids_for_pdb(
    dirent: &DirEntry,
    remaining: &HashSet<DebugId>,
) -> Option<Vec<(DebugId, DifType)>> {
    if_chain! {
        if dirent.path().extension() == Some(OsStr::new("pdb"));
        if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::Pdb));
        then {
            return Some(extract_remaining_ids(&dif.ids(), remaining, DifType::Pdb))
        }
    }
    None
}

fn find_ids_for_sourcebundle(
    dirent: &DirEntry,
    remaining: &HashSet<DebugId>,
) -> Option<Vec<(DebugId, DifType)>> {
    if_chain! {
        if dirent.path().extension() == Some(OsStr::new("zip"));
        if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::SourceBundle));
        then {
            return Some(extract_remaining_ids(&dif.ids(), remaining, DifType::SourceBundle))
        }
    }
    None
}

fn find_ids_for_breakpad(
    dirent: &DirEntry,
    remaining: &HashSet<DebugId>,
) -> Option<Vec<(DebugId, DifType)>> {
    if_chain! {
        if dirent.path().extension() == Some(OsStr::new("sym"));
        if let Ok(dif) = DifFile::open_path(dirent.path(), Some(DifType::Breakpad));
        then {
            return Some(extract_remaining_ids(&dif.ids(), remaining, DifType::Breakpad))
        }
    }
    None
}

fn extract_remaining_ids(
    ids: &[DebugId],
    remaining: &HashSet<DebugId>,
    t: DifType,
) -> Vec<(DebugId, DifType)> {
    ids.iter()
        .filter_map(|id| {
            if remaining.contains(id) {
                return Some((id.to_owned(), t));
            }
            None
        })
        .collect()
}

pub fn execute(matches: &ArgMatches<'_>) -> Result<(), Error> {
    let mut paths = HashSet::new();
    let mut types = HashSet::new();
    let mut ids = HashSet::new();

    // which types should we consider?
    if let Some(t) = matches.values_of("types") {
        for ty in t {
            types.insert(ty.parse().unwrap());
        }
    } else {
        types.insert(DifType::Dsym);
        types.insert(DifType::Pdb);
        types.insert(DifType::Pe);
        types.insert(DifType::Proguard);
        types.insert(DifType::SourceBundle);
        types.insert(DifType::Breakpad);
    }

    let with_well_known = !matches.is_present("no_well_known");
    let with_cwd = !matches.is_present("no_cwd");

    // start adding well known locations
    if_chain! {
        if with_well_known;
        if types.contains(&DifType::Dsym);
        if let Some(path) = dirs::home_dir().map(|x| x.join("Library/Developer/Xcode/DerivedData"));
        if path.is_dir();
        then {
            paths.insert(path);
        }
    }

    // current folder if wanted
    if_chain! {
        if with_cwd;
        if let Ok(path) = env::current_dir();
        then {
            paths.insert(path);
        }
    }

    // extra paths
    if let Some(p) = matches.values_of("paths") {
        for path in p {
            paths.insert(PathBuf::from(path));
        }
    }

    // which ids are we looking for?
    if let Some(i) = matches.values_of("ids") {
        for id in i {
            ids.insert(id.parse().unwrap());
        }
    } else {
        return Ok(());
    }

    if !find_ids(&paths, &types, &ids, matches.is_present("json"))? {
        return Err(QuietExit(1).into());
    }

    Ok(())
}
<|endoftext|>


<commit_before>use crate::{
    backend::renderer::{Frame, ImportAll, Renderer, Texture},
    desktop::{space::*, utils::*},
    utils::{Logical, Point, Rectangle},
    wayland::output::Output,
};
use std::{
    any::{Any, TypeId},
    hash::{Hash, Hasher},
};
use wayland_server::protocol::wl_surface::WlSurface;

/// Enum for indicating on with layer a render element schould be draw
#[derive(Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum RenderLayer {
    /// Bellow every other elements
    Bottom,
    /// Above WlrLayer::Background but bellow WlrLayer::Bottom
    AboveBackground,
    /// Right before programs windows are draw
    BeforeWindows,
    /// Right after programs windows are draw
    AfterWindows,
    /// Above WlrLayer::Top but bellow WlrLayer::Overlay
    BeforeOverlay,
    /// Above anything else
    Top,
}

/// Elements rendered by [`Space::render_output`] in addition to windows, layers and popups.
pub type DynamicRenderElements<R> =
    Box<dyn RenderElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>>;

pub(super) type SpaceElem<R> =
    dyn SpaceElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>;

pub(super) struct DynamicRenderElementMap<'a, R: Renderer>(pub(super) &'a [DynamicRenderElements<R>]);

impl<'a, R> DynamicRenderElementMap<'a, R>
where
    R: Renderer + ImportAll + 'static,
    R::TextureId: 'static,
    R::Error: 'static,
    R::Frame: 'static,
{
    pub fn iter_bottom(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::Bottom)
    }

    pub fn iter_above_background(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::AboveBackground)
    }

    pub fn iter_before_windows(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::BeforeWindows)
    }

    pub fn iter_after_windows(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::AfterWindows)
    }

    pub fn iter_before_overlay(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::BeforeOverlay)
    }

    pub fn iter_top(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::Top)
    }

    pub fn iter_layer(&'a self, layer: RenderLayer) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        Box::new(
            self.0
                .iter()
                .filter(move |c| c.layer() == layer)
                .map(|c| c as &SpaceElem<R>),
        )
    }
}

/// Trait for custom elements to be rendered during [`Space::render_output`].
pub trait RenderElement<R, F, E, T>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
    Self: Any + 'static,
{
    /// Returns an id unique to this element for the type of Self.
    fn id(&self) -> usize;
    #[doc(hidden)]
    fn type_of(&self) -> TypeId {
        std::any::Any::type_id(self)
    }
    /// Returns the bounding box of this element including its position in the space.
    fn geometry(&self) -> Rectangle<i32, Logical>;
    /// Returns the damage of the element since it's last update.
    /// It should be relative to the elements coordinates.
    ///
    /// If you receive `Some(_)` for `for_values` you may cache that you
    /// send the damage for this `Space` and `Output` combination once
    /// and return an empty vector for subsequent calls until the contents
    /// of this element actually change again for optimization reasons.
    ///
    /// Returning `vec![Rectangle::from_loc_and_size((0, 0), (i32::MAX, i32::MAX))]` is always
    /// correct, but very inefficient.
    fn accumulated_damage(
        &self,
        for_values: Option<SpaceOutputTuple<'_, '_>>,
    ) -> Vec<Rectangle<i32, Logical>>;
    /// Draws the element using the provided `Frame` and `Renderer`.
    ///
    /// - `scale` provides the current fractional scale value to render as
    /// - `damage` provides the regions you need to re-draw and *may* not
    ///   be equivalent to the damage returned by `accumulated_damage`.
    ///   Redrawing other parts of the element is not valid and may cause rendering artifacts.
    fn draw(
        &self,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error>;

    /// Returns they layer the elements schould be draw on, defaults to Top
    fn layer(&self) -> RenderLayer {
        RenderLayer::Top
    }
}

pub(crate) trait SpaceElement<R, F, E, T>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture,
{
    fn id(&self) -> usize;
    fn type_of(&self) -> TypeId;
    fn location(&self, space_id: usize) -> Point<i32, Logical> {
        self.geometry(space_id).loc
    }
    fn geometry(&self, space_id: usize) -> Rectangle<i32, Logical>;
    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>>;
    #[allow(clippy::too_many_arguments)]
    fn draw(
        &self,
        space_id: usize,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        location: Point<i32, Logical>,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error>;
}

impl<R, F, E, T> SpaceElement<R, F, E, T> for Box<dyn RenderElement<R, F, E, T>>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll + 'static,
    F: Frame<Error = E, TextureId = T> + 'static,
    E: std::error::Error + 'static,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        (&**self as &dyn RenderElement<R, F, E, T>).id()
    }
    fn type_of(&self) -> TypeId {
        (&**self as &dyn RenderElement<R, F, E, T>).type_of()
    }
    fn geometry(&self, _space_id: usize) -> Rectangle<i32, Logical> {
        (&**self as &dyn RenderElement<R, F, E, T>).geometry()
    }
    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> {
        (&**self as &dyn RenderElement<R, F, E, T>).accumulated_damage(for_values.map(SpaceOutputTuple::from))
    }
    fn draw(
        &self,
        _space_id: usize,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        _location: Point<i32, Logical>,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error> {
        (&**self as &dyn RenderElement<R, F, E, T>).draw(renderer, frame, scale, damage, log)
    }
}

/// Generic helper for drawing [`WlSurface`]s and their subsurfaces
/// as custom elements via [`RenderElement`].
///
/// For example useful for cursor or drag-and-drop surfaces.
///
/// Note: This element will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
#[derive(Debug)]
pub struct SurfaceTree {
    /// Surface to be drawn
    pub surface: WlSurface,
    /// Position to draw add
    pub position: Point<i32, Logical>,
}

impl<R, F, E, T> RenderElement<R, F, E, T> for SurfaceTree
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        self.surface.as_ref().id() as usize
    }

    fn geometry(&self) -> Rectangle<i32, Logical> {
        let mut bbox = bbox_from_surface_tree(&self.surface, (0, 0));
        bbox.loc += self.position;
        bbox
    }

    fn accumulated_damage(
        &self,
        for_values: Option<SpaceOutputTuple<'_, '_>>,
    ) -> Vec<Rectangle<i32, Logical>> {
        damage_from_surface_tree(&self.surface, (0, 0), for_values.map(|x| (x.0, x.1)))
    }

    fn draw(
        &self,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error> {
        crate::backend::renderer::utils::draw_surface_tree(
            renderer,
            frame,
            &self.surface,
            scale,
            self.position,
            damage,
            log,
        )
    }
}

/// Newtype for (&Space, &Output) to provide a `Hash` implementation for damage tracking
#[derive(Debug, PartialEq)]
pub struct SpaceOutputTuple<'a, 'b>(pub &'a Space, pub &'b Output);

impl<'a, 'b> Hash for SpaceOutputTuple<'a, 'b> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.id.hash(state);
        (std::sync::Arc::as_ptr(&self.1.inner) as *const () as usize).hash(state);
    }
}

impl<'a, 'b> SpaceOutputTuple<'a, 'b> {
    /// Returns an owned version that produces and equivalent hash
    pub fn owned_hash(&self) -> SpaceOutputHash {
        SpaceOutputHash(
            self.0.id,
            std::sync::Arc::as_ptr(&self.1.inner) as *const () as usize,
        )
    }
}

impl<'a, 'b> From<(&'a Space, &'b Output)> for SpaceOutputTuple<'a, 'b> {
    fn from((space, output): (&'a Space, &'b Output)) -> SpaceOutputTuple<'a, 'b> {
        SpaceOutputTuple(space, output)
    }
}

/// Type to use as an owned hashable value equal to [`SpaceOutputTuple`]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct SpaceOutputHash(usize, usize);
<commit_msg>add comments to DynamicRenderElementMap<commit_after>use crate::{
    backend::renderer::{Frame, ImportAll, Renderer, Texture},
    desktop::{space::*, utils::*},
    utils::{Logical, Point, Rectangle},
    wayland::output::Output,
};
use std::{
    any::{Any, TypeId},
    hash::{Hash, Hasher},
};
use wayland_server::protocol::wl_surface::WlSurface;

/// Enum for indicating on with layer a render element schould be draw
#[derive(Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum RenderLayer {
    /// Bellow every other elements
    Bottom,
    /// Above WlrLayer::Background but bellow WlrLayer::Bottom
    AboveBackground,
    /// Right before programs windows are draw
    BeforeWindows,
    /// Right after programs windows are draw
    AfterWindows,
    /// Above WlrLayer::Top but bellow WlrLayer::Overlay
    BeforeOverlay,
    /// Above anything else
    Top,
}

/// Elements rendered by [`Space::render_output`] in addition to windows, layers and popups.
pub type DynamicRenderElements<R> =
    Box<dyn RenderElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>>;

pub(super) type SpaceElem<R> =
    dyn SpaceElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>;

/// Helper struct for iterating over diffrent layers of `DynamicRenderElements`
pub(super) struct DynamicRenderElementMap<'a, R: Renderer>(pub(super) &'a [DynamicRenderElements<R>]);

impl<'a, R> DynamicRenderElementMap<'a, R>
where
    R: Renderer + ImportAll + 'static,
    R::TextureId: 'static,
    R::Error: 'static,
    R::Frame: 'static,
{
    /// Iterate over `DynamicRenderElements` with layer `RenderLayer::Bottom`
    pub fn iter_bottom(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::Bottom)
    }

    /// Iterate over `DynamicRenderElements with layer `RenderLayer::AboveBackground`
    pub fn iter_above_background(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::AboveBackground)
    }

    /// Iterate over `DynamicRenderElements` with layer `RenderLayer::BeforeWindows`
    pub fn iter_before_windows(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::BeforeWindows)
    }

    /// Iterate over `DynamicRenderElements` with layer `RenderLayer::AfterWindows`
    pub fn iter_after_windows(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::AfterWindows)
    }

    /// Iterate over `DynamicRenderElements` with layer `RenderLayer::BeforeOverlay`
    pub fn iter_before_overlay(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::BeforeOverlay)
    }

    /// Iterate over `DynamicRenderElements` with layer `RenderLayer::Top`
    pub fn iter_top(&'a self) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        self.iter_layer(RenderLayer::Top)
    }

    /// Iterate over `DynamicRenderElements` with provided `layer`
    pub fn iter_layer(&'a self, layer: RenderLayer) -> Box<dyn Iterator<Item = &SpaceElem<R>> + 'a> {
        Box::new(
            self.0
                .iter()
                .filter(move |c| c.layer() == layer)
                .map(|c| c as &SpaceElem<R>),
        )
    }
}

/// Trait for custom elements to be rendered during [`Space::render_output`].
pub trait RenderElement<R, F, E, T>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
    Self: Any + 'static,
{
    /// Returns an id unique to this element for the type of Self.
    fn id(&self) -> usize;
    #[doc(hidden)]
    fn type_of(&self) -> TypeId {
        std::any::Any::type_id(self)
    }
    /// Returns the bounding box of this element including its position in the space.
    fn geometry(&self) -> Rectangle<i32, Logical>;
    /// Returns the damage of the element since it's last update.
    /// It should be relative to the elements coordinates.
    ///
    /// If you receive `Some(_)` for `for_values` you may cache that you
    /// send the damage for this `Space` and `Output` combination once
    /// and return an empty vector for subsequent calls until the contents
    /// of this element actually change again for optimization reasons.
    ///
    /// Returning `vec![Rectangle::from_loc_and_size((0, 0), (i32::MAX, i32::MAX))]` is always
    /// correct, but very inefficient.
    fn accumulated_damage(
        &self,
        for_values: Option<SpaceOutputTuple<'_, '_>>,
    ) -> Vec<Rectangle<i32, Logical>>;
    /// Draws the element using the provided `Frame` and `Renderer`.
    ///
    /// - `scale` provides the current fractional scale value to render as
    /// - `damage` provides the regions you need to re-draw and *may* not
    ///   be equivalent to the damage returned by `accumulated_damage`.
    ///   Redrawing other parts of the element is not valid and may cause rendering artifacts.
    fn draw(
        &self,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error>;

    /// Returns they layer the elements schould be draw on, defaults to Top
    fn layer(&self) -> RenderLayer {
        RenderLayer::Top
    }
}

pub(crate) trait SpaceElement<R, F, E, T>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture,
{
    fn id(&self) -> usize;
    fn type_of(&self) -> TypeId;
    fn location(&self, space_id: usize) -> Point<i32, Logical> {
        self.geometry(space_id).loc
    }
    fn geometry(&self, space_id: usize) -> Rectangle<i32, Logical>;
    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>>;
    #[allow(clippy::too_many_arguments)]
    fn draw(
        &self,
        space_id: usize,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        location: Point<i32, Logical>,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error>;
}

impl<R, F, E, T> SpaceElement<R, F, E, T> for Box<dyn RenderElement<R, F, E, T>>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll + 'static,
    F: Frame<Error = E, TextureId = T> + 'static,
    E: std::error::Error + 'static,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        (&**self as &dyn RenderElement<R, F, E, T>).id()
    }
    fn type_of(&self) -> TypeId {
        (&**self as &dyn RenderElement<R, F, E, T>).type_of()
    }
    fn geometry(&self, _space_id: usize) -> Rectangle<i32, Logical> {
        (&**self as &dyn RenderElement<R, F, E, T>).geometry()
    }
    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> {
        (&**self as &dyn RenderElement<R, F, E, T>).accumulated_damage(for_values.map(SpaceOutputTuple::from))
    }
    fn draw(
        &self,
        _space_id: usize,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        _location: Point<i32, Logical>,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error> {
        (&**self as &dyn RenderElement<R, F, E, T>).draw(renderer, frame, scale, damage, log)
    }
}

/// Generic helper for drawing [`WlSurface`]s and their subsurfaces
/// as custom elements via [`RenderElement`].
///
/// For example useful for cursor or drag-and-drop surfaces.
///
/// Note: This element will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
#[derive(Debug)]
pub struct SurfaceTree {
    /// Surface to be drawn
    pub surface: WlSurface,
    /// Position to draw add
    pub position: Point<i32, Logical>,
}

impl<R, F, E, T> RenderElement<R, F, E, T> for SurfaceTree
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        self.surface.as_ref().id() as usize
    }

    fn geometry(&self) -> Rectangle<i32, Logical> {
        let mut bbox = bbox_from_surface_tree(&self.surface, (0, 0));
        bbox.loc += self.position;
        bbox
    }

    fn accumulated_damage(
        &self,
        for_values: Option<SpaceOutputTuple<'_, '_>>,
    ) -> Vec<Rectangle<i32, Logical>> {
        damage_from_surface_tree(&self.surface, (0, 0), for_values.map(|x| (x.0, x.1)))
    }

    fn draw(
        &self,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error> {
        crate::backend::renderer::utils::draw_surface_tree(
            renderer,
            frame,
            &self.surface,
            scale,
            self.position,
            damage,
            log,
        )
    }
}

/// Newtype for (&Space, &Output) to provide a `Hash` implementation for damage tracking
#[derive(Debug, PartialEq)]
pub struct SpaceOutputTuple<'a, 'b>(pub &'a Space, pub &'b Output);

impl<'a, 'b> Hash for SpaceOutputTuple<'a, 'b> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.id.hash(state);
        (std::sync::Arc::as_ptr(&self.1.inner) as *const () as usize).hash(state);
    }
}

impl<'a, 'b> SpaceOutputTuple<'a, 'b> {
    /// Returns an owned version that produces and equivalent hash
    pub fn owned_hash(&self) -> SpaceOutputHash {
        SpaceOutputHash(
            self.0.id,
            std::sync::Arc::as_ptr(&self.1.inner) as *const () as usize,
        )
    }
}

impl<'a, 'b> From<(&'a Space, &'b Output)> for SpaceOutputTuple<'a, 'b> {
    fn from((space, output): (&'a Space, &'b Output)) -> SpaceOutputTuple<'a, 'b> {
        SpaceOutputTuple(space, output)
    }
}

/// Type to use as an owned hashable value equal to [`SpaceOutputTuple`]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct SpaceOutputHash(usize, usize);
<|endoftext|>