<commit_before>//! The master module provides the Master struct which instructs Workers which
//! portions of the image they should render and collects their results to combine
//! into the final image.

use std::path::PathBuf;
use std::io::prelude::*;
use std::collections::HashMap;
use std::net::ToSocketAddrs;
use std::iter;

use bincode::rustc_serialize::decode;
use image;
use mio::tcp::{TcpStream, Shutdown};
use mio::*;

use film::Image;
use exec::Config;
use exec::distrib::{worker, Instructions};
use sampler::BlockQueue;

pub struct DistributedFrame {
    pub frame: usize,
    // The number of workers who have reported results for this
    // frame so far
    pub num_reporting: usize,
    pub render: Image,
    pub completed: bool,
}

#[derive(Clone, Debug)]
struct WorkerBuffer {
    pub buf: Vec<u8>,
    pub expected_size: usize,
    pub currently_read: usize,
}

impl WorkerBuffer {
    pub fn new() -> WorkerBuffer {
        WorkerBuffer { buf: Vec::new(), expected_size: 8, currently_read: 0 }
    }
}

pub struct Master {
    // Hostnames of the workers to send work too
    workers: Vec<String>,
    connections: Vec<TcpStream>,
    // Temporary buffers to store worker results in as they're
    // read in over TCP
    worker_buffers: Vec<WorkerBuffer>,
    config: Config,
    frames: HashMap<usize, DistributedFrame>,
    selected_frames: Option<(usize, usize)>,
    img_dim: (usize, usize),
    blocks_per_worker: usize,
    blocks_remainder: usize,
}

impl Master {
    /// Create a new master that will contact the worker nodes passed and
    /// send instructions on what parts of the scene to start rendering
    pub fn start_workers(workers: Vec<String>, config: Config, img_dim: (usize, usize),
                         frames: Option<(usize, usize)>) -> (Master, EventLoop<Master>) {
        // Figure out how many blocks we have for this image and assign them to our workers
        let queue = BlockQueue::new((img_dim.0 as u32, img_dim.1 as u32), (8, 8), (0, 0));
        let blocks_per_worker = queue.len() / workers.len();
        let blocks_remainder = queue.len() % workers.len();
        println!("Have {} workers, each worker does {} blocks w/ {} remainder",
                 workers.len(), blocks_per_worker, blocks_remainder);

        let mut event_loop = EventLoop::<Master>::new().unwrap();
        let mut connections = Vec::new();

        // Connect to each worker and send instructions on what to render
        // I guess this should also be queue'd up and the writes actually performed asynchronously?
        // Otherwise we need to loop on write_all while waiting for the connection to open
        for (i, host) in workers.iter().enumerate() {
            let addr = (&host[..], worker::PORT).to_socket_addrs().unwrap().next().unwrap();
            println!("Connecting too {:?}", addr);
            match TcpStream::connect(&addr) {
                Ok(stream) => {
                    println!("Connected and writing");
                    println!("Adding stream to event loop");
                    // Each worker is identified in the event loop by their index in the vec
                    match event_loop.register(&stream, Token(i)) {
                        Err(e) => println!("Error registering stream from {}: {}", host, e),
                        Ok(_) => {},
                    }
                    connections.push(stream);
                },
                Err(e) => println!("Failed to contact worker {}: {:?}", host, e),
            }
        }
        let worker_buffers: Vec<_> = iter::repeat(WorkerBuffer::new()).take(workers.len()).collect();
        let master = Master { workers: workers, connections: connections,
                              worker_buffers: worker_buffers, config: config,
                              frames: HashMap::new(), selected_frames: frames,
                              img_dim: img_dim,
                              blocks_per_worker: blocks_per_worker,
                              blocks_remainder: blocks_remainder };
        (master, event_loop)
    }
    /// Read a result frame from a worker and save it into the list of frames we're collecting from
    /// all workers. Will save out the final render if all workers have reported results for this
    /// frame.
    fn save_results(&mut self, frame: worker::Frame) {
        // Find the frame this worker is referring to and add its results
        let frame_num = frame.frame as usize;
        println!("Worker reporting frame {}", frame_num);
        if let Some(df) = self.frames.get_mut(&frame_num) {
            df.render.add_blocks(frame.block_size, &frame.blocks, &frame.pixels);
            df.num_reporting += 1;
            println!("We have parts of this frame already");
        }
        // TODO: Better way here? We get stuck because self.frames is counted as borrowed
        // from the if above, making this really awkward.
        if self.frames.get_mut(&frame_num).is_none() {
            // TODO: I need to seperate the render target from the actual image as the
            // filter here isn't used in this path and it doesn't make sense to have one
            let render = Image::new(self.img_dim);
            let mut df = DistributedFrame { frame: frame_num, num_reporting: 1, render: render, completed: false };
            df.render.add_blocks(frame.block_size, &frame.blocks, &frame.pixels);
            self.frames.insert(df.frame, df);
            println!("This is a new frame");
        }
        if let Some(df) = self.frames.get_mut(&frame_num) {
            if df.num_reporting == self.workers.len() {
                df.completed = true;
                println!("We have completed frame {}", frame_num);
                let out_file = match self.config.out_path.extension() {
                    Some(_) => self.config.out_path.clone(),
                    None => self.config.out_path.join(PathBuf::from(format!("frame{:05}.png", df.frame))),
                };
                println!("Frame {}: rendered to '{}'\n--------------------", frame_num, out_file.display());
                let img = df.render.get_srgb8();
                let dim = df.render.dimensions();
                match image::save_buffer(&out_file.as_path(), &img[..], dim.0 as u32, dim.1 as u32, image::RGB(8)) {
                    Ok(_) => {},
                    Err(e) => println!("Error saving image, {}", e),
                };
            }
        }
    }
    fn read_worker_buffer(&mut self, worker: usize) -> bool {
        let mut buf = &mut self.worker_buffers[worker];
        // If we haven't read the size of data being sent, read that now
        if buf.currently_read < 8 {
            // First 8 bytes are a u64 specifying the number of bytes being sent
            buf.buf.extend(iter::repeat(0u8).take(8));
            println!("Reading size header...");
            match self.connections[worker].read(&mut buf.buf[buf.currently_read..]) {
                Ok(n) => buf.currently_read += n,
                Err(e) => println!("Error reading results from worker {}: {}", self.workers[worker], e),
            }
            println!("Read {} bytes so far, must read {} in total", buf.currently_read, buf.expected_size);
            if buf.currently_read == buf.expected_size {
                println!("Got size header");
                // How many bytes we expect to get from the worker for a frame
                buf.expected_size = decode(&buf.buf[..]).unwrap();
                println!("Expecting {} bytes", buf.expected_size);
                // Extend the Vec so we've got enough room for the remaning bytes, minus the 8 for the
                // encoded size header
                buf.buf.extend(iter::repeat(0u8).take(buf.expected_size - 8));
            }
        }
        // If we've finished reading the size header we can now start reading the frame data
        if buf.currently_read >= 8 {
            println!("Reading from worker");
            match self.connections[worker].read(&mut buf.buf[buf.currently_read..]) {
                Ok(n) => buf.currently_read += n,
                Err(e) => println!("Error reading results from worker {}: {}", self.workers[worker], e),
            }
            println!("Read {} bytes so far, must read {} in total", buf.currently_read, buf.expected_size);
        }
        buf.currently_read == buf.expected_size
    }
}

impl Handler for Master {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<Master>, token: Token, event: EventSet) {
        let worker = token.as_usize();
        println!("Event from {}: {:?}", worker, event);
        if event.is_error() {
            println!("Error connecting too {}", self.workers[worker]);
            match self.connections[worker].shutdown(Shutdown::Both) {
                Err(e) => println!("Error shutting down worker {}: {}", worker, e),
                Ok(_) => {},
            }
            // Remove the connection from the event loop
            match event_loop.deregister(&self.connections[worker]) {
                Err(e) => println!("Error deregistering worker {}: {}", worker, e),
                Ok(_) => {},
            }
        }
        // A worker is ready to receive instructions from us
        if event.is_writable() {
            let b_start = worker * self.blocks_per_worker;
            let b_count =
                if worker == self.workers.len() - 1 {
                    self.blocks_per_worker + self.blocks_remainder
                } else {
                    self.blocks_per_worker
                };
            let instr = Instructions::new(&self.config.scene_file, self.selected_frames, b_start, b_count);
            println!("Sending instructions {:?} too {}", instr, self.workers[worker]);
            let bytes = instr.to_json().into_bytes();
            // Loop until we successfully write the byes
            match self.connections[worker].write_all(&bytes[..]) {
                Err(e) => println!("Failed to send instructions to {}: {:?}", self.workers[worker], e),
                Ok(_) => println!("Instructions sent"),
            }
            // We no longer need to write anything, so close the write end
            match self.connections[worker].shutdown(Shutdown::Write) {
                Err(e) => panic!(format!("Failed to shutdown write end to worker {}: {}",
                                         self.workers[worker], e)),
                Ok(_) => {},
            }
        }
        // Some results are available from a worker
        if event.is_readable() {
            println!("Readable event from worker {}", worker);
            if self.read_worker_buffer(worker) {
                println!("Got all frame data, now parsing");
                let frame: worker::Frame = decode(&self.worker_buffers[worker].buf[..]).unwrap();
                println!("Saving frame results");
                self.save_results(frame);
                // Clean up our read buffer
                self.worker_buffers[worker].buf.clear();
                self.worker_buffers[worker].expected_size = 8;
                self.worker_buffers[worker].currently_read = 0;
            }
        }
        // If the worker has terminated, shutdown the read end of the connection
        if event.is_hup() {
            println!("Worker {} has hung up", worker);
            match self.connections[worker].shutdown(Shutdown::Both) {
                Err(e) => println!("Error shutting down worker {}: {}", worker, e),
                Ok(_) => {},
            }
            // Remove the connection from the event loop
            match event_loop.deregister(&self.connections[worker]) {
                Err(e) => println!("Error deregistering worker {}: {}", worker, e),
                Ok(_) => {},
            }
        }
        // After getting results from the worker we check if we've completed all our frames
        // and exit if so
        if self.frames.len() == self.config.frame_info.frames
            && self.frames.values().fold(true, |all, v| all && v.completed) {
                println!("All frames have been rendered, master exiting");
                event_loop.shutdown();
        }
    }
}

<commit_msg>Don't remove the worker if we fail sending instructions.<commit_after>//! The master module provides the Master struct which instructs Workers which
//! portions of the image they should render and collects their results to combine
//! into the final image.

use std::path::PathBuf;
use std::io::prelude::*;
use std::collections::HashMap;
use std::net::ToSocketAddrs;
use std::iter;

use bincode::rustc_serialize::decode;
use image;
use mio::tcp::{TcpStream, Shutdown};
use mio::*;

use film::Image;
use exec::Config;
use exec::distrib::{worker, Instructions};
use sampler::BlockQueue;

pub struct DistributedFrame {
    pub frame: usize,
    // The number of workers who have reported results for this
    // frame so far
    pub num_reporting: usize,
    pub render: Image,
    pub completed: bool,
}

#[derive(Clone, Debug)]
struct WorkerBuffer {
    pub buf: Vec<u8>,
    pub expected_size: usize,
    pub currently_read: usize,
}

impl WorkerBuffer {
    pub fn new() -> WorkerBuffer {
        WorkerBuffer { buf: Vec::new(), expected_size: 8, currently_read: 0 }
    }
}

pub struct Master {
    // Hostnames of the workers to send work too
    workers: Vec<String>,
    connections: Vec<TcpStream>,
    // Temporary buffers to store worker results in as they're
    // read in over TCP
    worker_buffers: Vec<WorkerBuffer>,
    config: Config,
    frames: HashMap<usize, DistributedFrame>,
    selected_frames: Option<(usize, usize)>,
    img_dim: (usize, usize),
    blocks_per_worker: usize,
    blocks_remainder: usize,
}

impl Master {
    /// Create a new master that will contact the worker nodes passed and
    /// send instructions on what parts of the scene to start rendering
    pub fn start_workers(workers: Vec<String>, config: Config, img_dim: (usize, usize),
                         frames: Option<(usize, usize)>) -> (Master, EventLoop<Master>) {
        // Figure out how many blocks we have for this image and assign them to our workers
        let queue = BlockQueue::new((img_dim.0 as u32, img_dim.1 as u32), (8, 8), (0, 0));
        let blocks_per_worker = queue.len() / workers.len();
        let blocks_remainder = queue.len() % workers.len();
        println!("Have {} workers, each worker does {} blocks w/ {} remainder",
                 workers.len(), blocks_per_worker, blocks_remainder);

        let mut event_loop = EventLoop::<Master>::new().unwrap();
        let mut connections = Vec::new();

        // Connect to each worker and send instructions on what to render
        // I guess this should also be queue'd up and the writes actually performed asynchronously?
        // Otherwise we need to loop on write_all while waiting for the connection to open
        for (i, host) in workers.iter().enumerate() {
            let addr = (&host[..], worker::PORT).to_socket_addrs().unwrap().next().unwrap();
            println!("Connecting too {:?}", addr);
            match TcpStream::connect(&addr) {
                Ok(stream) => {
                    println!("Connected and writing");
                    println!("Adding stream to event loop");
                    // Each worker is identified in the event loop by their index in the vec
                    match event_loop.register(&stream, Token(i)) {
                        Err(e) => println!("Error registering stream from {}: {}", host, e),
                        Ok(_) => {},
                    }
                    connections.push(stream);
                },
                Err(e) => println!("Failed to contact worker {}: {:?}", host, e),
            }
        }
        let worker_buffers: Vec<_> = iter::repeat(WorkerBuffer::new()).take(workers.len()).collect();
        let master = Master { workers: workers, connections: connections,
                              worker_buffers: worker_buffers, config: config,
                              frames: HashMap::new(), selected_frames: frames,
                              img_dim: img_dim,
                              blocks_per_worker: blocks_per_worker,
                              blocks_remainder: blocks_remainder };
        (master, event_loop)
    }
    /// Read a result frame from a worker and save it into the list of frames we're collecting from
    /// all workers. Will save out the final render if all workers have reported results for this
    /// frame.
    fn save_results(&mut self, frame: worker::Frame) {
        // Find the frame this worker is referring to and add its results
        let frame_num = frame.frame as usize;
        println!("Worker reporting frame {}", frame_num);
        if let Some(df) = self.frames.get_mut(&frame_num) {
            df.render.add_blocks(frame.block_size, &frame.blocks, &frame.pixels);
            df.num_reporting += 1;
            println!("We have parts of this frame already");
        }
        // TODO: Better way here? We get stuck because self.frames is counted as borrowed
        // from the if above, making this really awkward.
        if self.frames.get_mut(&frame_num).is_none() {
            // TODO: I need to seperate the render target from the actual image as the
            // filter here isn't used in this path and it doesn't make sense to have one
            let render = Image::new(self.img_dim);
            let mut df = DistributedFrame { frame: frame_num, num_reporting: 1, render: render, completed: false };
            df.render.add_blocks(frame.block_size, &frame.blocks, &frame.pixels);
            self.frames.insert(df.frame, df);
            println!("This is a new frame");
        }
        if let Some(df) = self.frames.get_mut(&frame_num) {
            if df.num_reporting == self.workers.len() {
                df.completed = true;
                println!("We have completed frame {}", frame_num);
                let out_file = match self.config.out_path.extension() {
                    Some(_) => self.config.out_path.clone(),
                    None => self.config.out_path.join(PathBuf::from(format!("frame{:05}.png", df.frame))),
                };
                println!("Frame {}: rendered to '{}'\n--------------------", frame_num, out_file.display());
                let img = df.render.get_srgb8();
                let dim = df.render.dimensions();
                match image::save_buffer(&out_file.as_path(), &img[..], dim.0 as u32, dim.1 as u32, image::RGB(8)) {
                    Ok(_) => {},
                    Err(e) => println!("Error saving image, {}", e),
                };
            }
        }
    }
    fn read_worker_buffer(&mut self, worker: usize) -> bool {
        let mut buf = &mut self.worker_buffers[worker];
        // If we haven't read the size of data being sent, read that now
        if buf.currently_read < 8 {
            // First 8 bytes are a u64 specifying the number of bytes being sent
            buf.buf.extend(iter::repeat(0u8).take(8));
            println!("Reading size header...");
            match self.connections[worker].read(&mut buf.buf[buf.currently_read..]) {
                Ok(n) => buf.currently_read += n,
                Err(e) => println!("Error reading results from worker {}: {}", self.workers[worker], e),
            }
            println!("Read {} bytes so far, must read {} in total", buf.currently_read, buf.expected_size);
            if buf.currently_read == buf.expected_size {
                println!("Got size header");
                // How many bytes we expect to get from the worker for a frame
                buf.expected_size = decode(&buf.buf[..]).unwrap();
                println!("Expecting {} bytes", buf.expected_size);
                // Extend the Vec so we've got enough room for the remaning bytes, minus the 8 for the
                // encoded size header
                buf.buf.extend(iter::repeat(0u8).take(buf.expected_size - 8));
            }
        }
        // If we've finished reading the size header we can now start reading the frame data
        if buf.currently_read >= 8 {
            println!("Reading from worker");
            match self.connections[worker].read(&mut buf.buf[buf.currently_read..]) {
                Ok(n) => buf.currently_read += n,
                Err(e) => println!("Error reading results from worker {}: {}", self.workers[worker], e),
            }
            println!("Read {} bytes so far, must read {} in total", buf.currently_read, buf.expected_size);
        }
        buf.currently_read == buf.expected_size
    }
}

impl Handler for Master {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<Master>, token: Token, event: EventSet) {
        let worker = token.as_usize();
        println!("Event from {}: {:?}", worker, event);
        if event.is_error() {
            println!("Error connecting too {}", self.workers[worker]);
            match self.connections[worker].shutdown(Shutdown::Both) {
                Err(e) => println!("Error shutting down worker {}: {}", worker, e),
                Ok(_) => {},
            }
            // Remove the connection from the event loop
            match event_loop.deregister(&self.connections[worker]) {
                Err(e) => println!("Error deregistering worker {}: {}", worker, e),
                Ok(_) => {},
            }
        }
        // A worker is ready to receive instructions from us
        if event.is_writable() {
            let b_start = worker * self.blocks_per_worker;
            let b_count =
                if worker == self.workers.len() - 1 {
                    self.blocks_per_worker + self.blocks_remainder
                } else {
                    self.blocks_per_worker
                };
            let instr = Instructions::new(&self.config.scene_file, self.selected_frames, b_start, b_count);
            println!("Sending instructions {:?} to {}", instr, self.workers[worker]);
            let bytes = instr.to_json().into_bytes();
            // Loop until we successfully write the byes
            match self.connections[worker].write_all(&bytes[..]) {
                Err(e) => {
                    println!("Failed to send instructions to {}: {:?}", self.workers[worker], e);
                    return;
                },
                Ok(_) => println!("Instructions sent"),
            }
            // We no longer need to write anything, so close the write end
            match self.connections[worker].shutdown(Shutdown::Write) {
                Err(e) => panic!(format!("Failed to shutdown write end to worker {}: {}",
                                         self.workers[worker], e)),
                Ok(_) => {},
            }
        }
        // Some results are available from a worker
        if event.is_readable() {
            println!("Readable event from worker {}", worker);
            if self.read_worker_buffer(worker) {
                println!("Got all frame data, now parsing");
                let frame: worker::Frame = decode(&self.worker_buffers[worker].buf[..]).unwrap();
                println!("Saving frame results");
                self.save_results(frame);
                // Clean up our read buffer
                self.worker_buffers[worker].buf.clear();
                self.worker_buffers[worker].expected_size = 8;
                self.worker_buffers[worker].currently_read = 0;
            }
        }
        // If the worker has terminated, shutdown the read end of the connection
        if event.is_hup() {
            println!("Worker {} has hung up", worker);
            match self.connections[worker].shutdown(Shutdown::Both) {
                Err(e) => println!("Error shutting down worker {}: {}", worker, e),
                Ok(_) => {},
            }
            // Remove the connection from the event loop
            match event_loop.deregister(&self.connections[worker]) {
                Err(e) => println!("Error deregistering worker {}: {}", worker, e),
                Ok(_) => {},
            }
        }
        // After getting results from the worker we check if we've completed all our frames
        // and exit if so
        if self.frames.len() == self.config.frame_info.frames
            && self.frames.values().fold(true, |all, v| all && v.completed) {
                println!("All frames have been rendered, master exiting");
                event_loop.shutdown();
        }
    }
}

<|endoftext|>


<commit_before>use std::ops::Not;
use std::borrow::Cow;

use types::*;
use requests::*;

/// Use this method to edit text and game messages sent by the bot.
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
pub struct EditMessageText<'c, 's> {
    chat_id: ChatRef<'c>,
    message_id: MessageId,
    text: Cow<'s, str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    parse_mode: Option<ParseMode>,
    #[serde(skip_serializing_if = "Not::not")]
    disable_web_page_preview: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    reply_markup: Option<ReplyMarkup>,
}

impl<'c, 's> Request for EditMessageText<'c, 's> {
    type Response = Message;
    type RawResponse = Message;

    fn map(raw: Self::RawResponse) -> Self::Response {
        raw
    }

    fn name() -> &'static str {
        "editMessageText"
    }
}

impl<'c, 's> EditMessageText<'c, 's> {
    pub fn new<C, M, T>(chat: C, message_id: M, text: T) -> Self
        where C: ToChatRef<'c>, M: ToMessageId, T: Into<Cow<'s, str>> {

        EditMessageText {
            chat_id: chat.to_chat_ref(),
            message_id: message_id.to_message_id(),
            text: text.into(),
            parse_mode: None,
            disable_web_page_preview: false,
            reply_markup: None,
        }
    }

    pub fn parse_mode(mut self, parse_mode: ParseMode) -> Self {
        self.parse_mode = Some(parse_mode);
        self
    }

    pub fn disable_web_page_preview(mut self) -> Self { // TODO(knsd): Rename to disable_preview?
        self.disable_web_page_preview = true;
        self
    }

    pub fn reply_markup<R>(mut self, reply_markup: R) -> Self where R: Into<ReplyMarkup> { // TODO(knsd): nice builder?
        self.reply_markup = Some(reply_markup.into());
        self
    }
}

pub trait CanEditMessageText {
    fn edit_text<'c, 's, T>(&self, text: T) -> EditMessageText<'c, 's> where T: Into<Cow<'s, str>>;
}

impl CanEditMessageText for Message {
    fn edit_text<'c, 's, T>(&self, text: T) -> EditMessageText<'c, 's> where T: Into<Cow<'s, str>> {
        EditMessageText::new(&self.chat, self, text)
    }
}
<commit_msg>refactor: implement CanEditMessageText for ToMessageId + ToSourceChat<commit_after>use std::ops::Not;
use std::borrow::Cow;

use types::*;
use requests::*;

/// Use this method to edit text and game messages sent by the bot.
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
pub struct EditMessageText<'c, 's> {
    chat_id: ChatRef<'c>,
    message_id: MessageId,
    text: Cow<'s, str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    parse_mode: Option<ParseMode>,
    #[serde(skip_serializing_if = "Not::not")]
    disable_web_page_preview: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    reply_markup: Option<ReplyMarkup>,
}

impl<'c, 's> Request for EditMessageText<'c, 's> {
    type Response = Message;
    type RawResponse = Message;

    fn map(raw: Self::RawResponse) -> Self::Response {
        raw
    }

    fn name() -> &'static str {
        "editMessageText"
    }
}

impl<'c, 's> EditMessageText<'c, 's> {
    pub fn new<C, M, T>(chat: C, message_id: M, text: T) -> Self
        where C: ToChatRef<'c>, M: ToMessageId, T: Into<Cow<'s, str>> {

        EditMessageText {
            chat_id: chat.to_chat_ref(),
            message_id: message_id.to_message_id(),
            text: text.into(),
            parse_mode: None,
            disable_web_page_preview: false,
            reply_markup: None,
        }
    }

    pub fn parse_mode(mut self, parse_mode: ParseMode) -> Self {
        self.parse_mode = Some(parse_mode);
        self
    }

    pub fn disable_web_page_preview(mut self) -> Self { // TODO(knsd): Rename to disable_preview?
        self.disable_web_page_preview = true;
        self
    }

    pub fn reply_markup<R>(mut self, reply_markup: R) -> Self where R: Into<ReplyMarkup> { // TODO(knsd): nice builder?
        self.reply_markup = Some(reply_markup.into());
        self
    }
}

pub trait CanEditMessageText {
    fn edit_text<'c, 's, T>(&self, text: T) -> EditMessageText<'c, 's> where T: Into<Cow<'s, str>>;
}

impl<M> CanEditMessageText for M where M: ToMessageId + ToSourceChat {
    fn edit_text<'c, 's, T>(&self, text: T) -> EditMessageText<'c, 's> where T: Into<Cow<'s, str>> {
        EditMessageText::new(self.to_source_chat(), self.to_message_id(), text)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#[test]
fn simple_raw_data_struct() {
    let data : ::private::AlignedData<[u8; 16]> = ::private::AlignedData {
        _dummy: 0,
        data : [0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
                0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]
    };

    let reader = unsafe { ::private::layout::PointerReader::get_root_unchecked(
        ::std::mem::transmute(data.data.as_ptr())).get_struct(::std::ptr::null()).unwrap() };

    assert_eq!(0xefcdab8967452301u64, reader.get_data_field::<u64>(0));
    assert_eq!(0, reader.get_data_field::<u64>(1));
    assert_eq!(0x67452301u32, reader.get_data_field::<u32>(0));
    assert_eq!(0xefcdab89u32, reader.get_data_field::<u32>(1));
    assert_eq!(0, reader.get_data_field::<u32>(2));
    assert_eq!(0x2301u16, reader.get_data_field::<u16>(0));
    // TODO the rest of uints.

    // Bits.
    assert_eq!(reader.get_bool_field(0), true);
    assert_eq!(reader.get_bool_field(1), false);
    assert_eq!(reader.get_bool_field(2), false);
    assert_eq!(reader.get_bool_field(3), false);
    assert_eq!(reader.get_bool_field(4), false);
    assert_eq!(reader.get_bool_field(5), false);
    assert_eq!(reader.get_bool_field(6), false);
    assert_eq!(reader.get_bool_field(7), false);

    assert_eq!(reader.get_bool_field(8),  true);
    assert_eq!(reader.get_bool_field(9),  true);
    assert_eq!(reader.get_bool_field(10), false);
    assert_eq!(reader.get_bool_field(11), false);
    assert_eq!(reader.get_bool_field(12), false);
    assert_eq!(reader.get_bool_field(13), true);
    assert_eq!(reader.get_bool_field(14), false);
    assert_eq!(reader.get_bool_field(15), false);

    assert_eq!(reader.get_bool_field(63), true);
    assert_eq!(reader.get_bool_field(64), false);
}

#[test]
fn bool_list() {
    use private::layout::PrimitiveElement;
    use traits::FromPointerReader;

    // [true, false, true, false,
    //  true, true, true, false,
    //  false, true]

    let data : ::private::AlignedData<[u8; 16]> = ::private::AlignedData {
        _dummy: 0,
        data : [0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00,
                0x75, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
    };

    let reader = unsafe {
        ::private::layout::PointerReader::get_root_unchecked(
            ::std::mem::transmute(data.data.as_ptr()))
            .get_list(::private::layout::ElementSize::Bit, ::std::ptr::null()).unwrap() };

    assert_eq!(reader.len(), 10);
    assert_eq!(bool::get(&reader, 0), true);
    assert_eq!(bool::get(&reader, 1), false);
    assert_eq!(bool::get(&reader, 2), true);
    assert_eq!(bool::get(&reader, 3), false);
    assert_eq!(bool::get(&reader, 4), true);
    assert_eq!(bool::get(&reader, 5), true);
    assert_eq!(bool::get(&reader, 6), true);
    assert_eq!(bool::get(&reader, 7), false);
    assert_eq!(bool::get(&reader, 8), false);
    assert_eq!(bool::get(&reader, 9), true);

    let reader = unsafe {
        ::primitive_list::Reader::<bool>::get_from_pointer(
            &::private::layout::PointerReader::get_root_unchecked(
                ::std::mem::transmute(data.data.as_ptr()))).unwrap() };

    assert_eq!(reader.len(), 10);
    assert_eq!(reader.get(0), true);
    assert_eq!(reader.get(1), false);
    assert_eq!(reader.get(2), true);
    assert_eq!(reader.get(3), false);
    //...
}
<commit_msg>nicer<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#[test]
fn simple_raw_data_struct() {
    let data : ::private::AlignedData<[u8; 16]> = ::private::AlignedData {
        _dummy: 0,
        data : [0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
                0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]
    };

    let reader = unsafe { ::private::layout::PointerReader::get_root_unchecked(
        ::std::mem::transmute(data.data.as_ptr())).get_struct(::std::ptr::null()).unwrap() };

    assert_eq!(0xefcdab8967452301u64, reader.get_data_field::<u64>(0));
    assert_eq!(0, reader.get_data_field::<u64>(1));
    assert_eq!(0x67452301u32, reader.get_data_field::<u32>(0));
    assert_eq!(0xefcdab89u32, reader.get_data_field::<u32>(1));
    assert_eq!(0, reader.get_data_field::<u32>(2));
    assert_eq!(0x2301u16, reader.get_data_field::<u16>(0));
    // TODO the rest of uints.

    // Bits.
    assert_eq!(reader.get_bool_field(0), true);
    assert_eq!(reader.get_bool_field(1), false);
    assert_eq!(reader.get_bool_field(2), false);
    assert_eq!(reader.get_bool_field(3), false);
    assert_eq!(reader.get_bool_field(4), false);
    assert_eq!(reader.get_bool_field(5), false);
    assert_eq!(reader.get_bool_field(6), false);
    assert_eq!(reader.get_bool_field(7), false);

    assert_eq!(reader.get_bool_field(8),  true);
    assert_eq!(reader.get_bool_field(9),  true);
    assert_eq!(reader.get_bool_field(10), false);
    assert_eq!(reader.get_bool_field(11), false);
    assert_eq!(reader.get_bool_field(12), false);
    assert_eq!(reader.get_bool_field(13), true);
    assert_eq!(reader.get_bool_field(14), false);
    assert_eq!(reader.get_bool_field(15), false);

    assert_eq!(reader.get_bool_field(63), true);
    assert_eq!(reader.get_bool_field(64), false);
}

#[test]
fn bool_list() {
    use private::layout::PrimitiveElement;
    use traits::FromPointerReader;

    // [true, false, true, false,
    //  true, true, true, false,
    //  false, true]

    let data : ::private::AlignedData<[u8; 16]> = ::private::AlignedData {
        _dummy: 0,
        data : [0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00,
                0x75, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
    };

    let pointer_reader = unsafe {
        ::private::layout::PointerReader::get_root_unchecked(
            ::std::mem::transmute(data.data.as_ptr()))
    };

    let reader = pointer_reader.get_list(::private::layout::ElementSize::Bit, ::std::ptr::null()).unwrap();

    assert_eq!(reader.len(), 10);
    assert_eq!(bool::get(&reader, 0), true);
    assert_eq!(bool::get(&reader, 1), false);
    assert_eq!(bool::get(&reader, 2), true);
    assert_eq!(bool::get(&reader, 3), false);
    assert_eq!(bool::get(&reader, 4), true);
    assert_eq!(bool::get(&reader, 5), true);
    assert_eq!(bool::get(&reader, 6), true);
    assert_eq!(bool::get(&reader, 7), false);
    assert_eq!(bool::get(&reader, 8), false);
    assert_eq!(bool::get(&reader, 9), true);

    let reader = ::primitive_list::Reader::<bool>::get_from_pointer(&pointer_reader).unwrap();

    assert_eq!(reader.len(), 10);
    assert_eq!(reader.get(0), true);
    assert_eq!(reader.get(1), false);
    assert_eq!(reader.get(2), true);
    assert_eq!(reader.get(3), false);
    //...
}
<|endoftext|>


<commit_before>//! [GET /_matrix/client/r0/sync](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-sync)

use std::{collections::HashMap, time::Duration};

use js_int::UInt;
use ruma_api::{ruma_api, Outgoing};
use ruma_events::{
    collections::{
        all::{RoomEvent, StateEvent},
        only::Event as NonRoomEvent,
    },
    presence::PresenceEvent,
    stripped::AnyStrippedStateEvent,
    to_device::AnyToDeviceEvent,
    EventResult,
};
use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};

use crate::{
    r0::{filter::FilterDefinition, keys::KeyAlgorithm},
    serde::is_default,
};

ruma_api! {
    metadata {
        description: "Get all new events from all rooms since the last sync or a given point of time.",
        method: GET,
        name: "sync",
        path: "/_matrix/client/r0/sync",
        rate_limited: false,
        requires_authentication: true,
    }

    request {
        /// A filter represented either as its full JSON definition or the ID of a saved filter.
        #[serde(skip_serializing_if = "Option::is_none")]
        #[ruma_api(query)]
        pub filter: Option<Filter>,
        /// A point in time to continue a sync from.
        ///
        /// Should be a token from the `next_batch` field of a previous `/sync`
        /// request.
        #[serde(skip_serializing_if = "Option::is_none")]
        #[ruma_api(query)]
        pub since: Option<String>,
        /// Controls whether to include the full state for all rooms the user is a member of.
        #[serde(default, skip_serializing_if = "is_default")]
        #[ruma_api(query)]
        pub full_state: bool,
        /// Controls whether the client is automatically marked as online by polling this API.
        #[serde(default, skip_serializing_if = "is_default")]
        #[ruma_api(query)]
        pub set_presence: SetPresence,
        /// The maximum time to poll in milliseconds before returning this request.
        #[serde(with = "crate::serde::duration::opt_ms", skip_serializing_if = "Option::is_none")]
        #[ruma_api(query)]
        pub timeout: Option<Duration>,
    }

    response {
        /// The batch token to supply in the `since` param of the next `/sync` request.
        pub next_batch: String,
        /// Updates to rooms.
        #[wrap_incoming]
        pub rooms: Rooms,
        /// Updates to the presence status of other users.
        #[wrap_incoming]
        pub presence: Presence,
        /// Messages sent dirrectly between devices.
        #[serde(default, skip_serializing_if = "ToDevice::is_empty")]
        #[wrap_incoming]
        pub to_device: ToDevice,
        /// Information on E2E device updates.
        ///
        /// Only present on an incremental sync.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub device_lists: Option<DeviceLists>,
        /// For each key algorithm, the number of unclaimed one-time keys
        /// currently held on the server for a device.
        #[serde(skip_serializing_if = "HashMap::is_empty")]
        pub device_one_time_keys_count: HashMap<KeyAlgorithm, UInt>,
    }

    error: crate::Error
}

/// Whether to set presence or not during sync.
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum SetPresence {
    /// Do not set the presence of the user calling this API.
    Offline,
    /// Mark client as online explicitly. Assumed by default.
    Online,
    /// Mark client as being idle.
    Unavailable,
}

impl Default for SetPresence {
    fn default() -> Self {
        Self::Online
    }
}

/// A filter represented either as its full JSON definition or the ID of a saved filter.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[allow(clippy::large_enum_variant)]
#[serde(untagged)]
pub enum Filter {
    // The filter definition needs to be (de)serialized twice because it is a URL-encoded JSON
    // string. Since #[ruma_api(query)] only does the latter and this is a very uncommon
    // setup, we implement it through custom serde logic for this specific enum variant rather than
    // adding another ruma_api attribute.
    //
    // On the deserialization side, because this is an enum with #[serde(untagged)], serde will
    // try the variants in order (https://serde.rs/enum-representations.html). That means because
    // FilterDefinition is the first variant, JSON decoding is attempted first which is almost
    // functionally equivalent to looking at whether the first symbol is a '{' as the spec says.
    // (there are probably some corner cases like leading whitespace)
    #[serde(with = "filter_def_serde")]
    /// A complete filter definition serialized to JSON.
    FilterDefinition(FilterDefinition),
    /// The ID of a filter saved on the server.
    FilterId(String),
}

/// Serialization and deserialization logic for filter definitions.
mod filter_def_serde {
    use serde::{de::Error as _, ser::Error as _, Deserialize, Deserializer, Serializer};

    use crate::r0::filter::FilterDefinition;

    /// Serialization logic for filter definitions.
    pub fn serialize<S>(filter_def: &FilterDefinition, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let string = serde_json::to_string(filter_def).map_err(S::Error::custom)?;
        serializer.serialize_str(&string)
    }

    /// Deserialization logic for filter definitions.
    pub fn deserialize<'de, D>(deserializer: D) -> Result<FilterDefinition, D::Error>
    where
        D: Deserializer<'de>,
    {
        let filter_str = <&str>::deserialize(deserializer)?;

        serde_json::from_str(filter_str).map_err(D::Error::custom)
    }
}

/// Updates to rooms.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct Rooms {
    /// The rooms that the user has left or been banned from.
    #[wrap_incoming(LeftRoom)]
    pub leave: HashMap<RoomId, LeftRoom>,
    /// The rooms that the user has joined.
    #[wrap_incoming(JoinedRoom)]
    pub join: HashMap<RoomId, JoinedRoom>,
    /// The rooms that the user has been invited to.
    #[wrap_incoming(InvitedRoom)]
    pub invite: HashMap<RoomId, InvitedRoom>,
}

/// Historical updates to left rooms.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct LeftRoom {
    /// The timeline of messages and state changes in the room up to the point when the user
    /// left.
    #[wrap_incoming]
    pub timeline: Timeline,
    /// The state updates for the room up to the start of the timeline.
    #[wrap_incoming]
    pub state: State,
    /// The private data that this user has attached to this room.
    #[wrap_incoming]
    pub account_data: AccountData,
}

/// Updates to joined rooms.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct JoinedRoom {
    /// Information about the room which clients may need to correctly render it
    /// to users.
    pub summary: RoomSummary,
    /// Counts of unread notifications for this room.
    pub unread_notifications: UnreadNotificationsCount,
    /// The timeline of messages and state changes in the room.
    #[wrap_incoming]
    pub timeline: Timeline,
    /// Updates to the state, between the time indicated by the `since` parameter, and the start
    /// of the `timeline` (or all state up to the start of the `timeline`, if `since` is not
    /// given, or `full_state` is true).
    #[wrap_incoming]
    pub state: State,
    /// The private data that this user has attached to this room.
    #[wrap_incoming]
    pub account_data: AccountData,
    /// The ephemeral events in the room that aren't recorded in the timeline or state of the
    /// room. e.g. typing.
    #[wrap_incoming]
    pub ephemeral: Ephemeral,
}

/// unread notifications count
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct UnreadNotificationsCount {
    /// The number of unread notifications for this room with the highlight flag set.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub highlight_count: Option<UInt>,
    /// The total number of unread notifications for this room.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub notification_count: Option<UInt>,
}

/// Events in the room.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct Timeline {
    /// True if the number of events returned was limited by the `limit` on the filter.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub limited: Option<bool>,
    /// A token that can be supplied to to the `from` parameter of the
    /// `/rooms/{roomId}/messages` endpoint.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub prev_batch: Option<String>,
    /// A list of events.
    #[wrap_incoming(RoomEvent with EventResult)]
    pub events: Vec<RoomEvent>,
}

/// State events in the room.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct State {
    /// A list of state events.
    #[wrap_incoming(StateEvent with EventResult)]
    pub events: Vec<StateEvent>,
}

/// The private data that this user has attached to this room.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct AccountData {
    /// A list of events.
    #[wrap_incoming(NonRoomEvent with EventResult)]
    pub events: Vec<NonRoomEvent>,
}

/// Ephemeral events not recorded in the timeline or state of the room.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct Ephemeral {
    /// A list of events.
    #[wrap_incoming(NonRoomEvent with EventResult)]
    pub events: Vec<NonRoomEvent>,
}

/// Information about room for rendering to clients.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RoomSummary {
    /// Users which can be used to generate a room name if the room does not have
    /// one. Required if room name or canonical aliases are not set or empty.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub heroes: Vec<String>,
    /// Number of users whose membership status is `join`.
    /// Required if field has changed since last sync; otherwise, it may be
    /// omitted.
    pub joined_member_count: Option<UInt>,
    /// Number of users whose membership status is `invite`.
    /// Required if field has changed since last sync; otherwise, it may be
    /// omitted.
    pub invited_member_count: Option<UInt>,
}

/// Updates to the rooms that the user has been invited to.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct InvitedRoom {
    /// The state of a room that the user has been invited to.
    #[wrap_incoming]
    pub invite_state: InviteState,
}

/// The state of a room that the user has been invited to.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct InviteState {
    /// A list of state events.
    #[wrap_incoming(AnyStrippedStateEvent with EventResult)]
    pub events: Vec<AnyStrippedStateEvent>,
}

/// Updates to the presence status of other users.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct Presence {
    /// A list of events.
    #[wrap_incoming(PresenceEvent with EventResult)]
    pub events: Vec<PresenceEvent>,
}

/// Messages sent dirrectly between devices.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct ToDevice {
    /// A list of to-device events.
    #[wrap_incoming(AnyToDeviceEvent with EventResult)]
    pub events: Vec<AnyToDeviceEvent>,
}

impl ToDevice {
    fn is_empty(&self) -> bool {
        self.events.is_empty()
    }
}

impl Default for IncomingToDevice {
    fn default() -> Self {
        Self { events: Vec::new() }
    }
}

/// Information on E2E device udpates.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DeviceLists {
    /// List of users who have updated their device identity keys or who now
    /// share an encrypted room with the client since the previous sync
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub changed: Vec<String>,
    /// List of users who no longer share encrypted rooms since the previous sync
    /// response.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub left: Vec<String>,
}
<commit_msg>Add a test for sync_events::Request serialization<commit_after>//! [GET /_matrix/client/r0/sync](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-sync)

use std::{collections::HashMap, time::Duration};

use js_int::UInt;
use ruma_api::{ruma_api, Outgoing};
use ruma_events::{
    collections::{
        all::{RoomEvent, StateEvent},
        only::Event as NonRoomEvent,
    },
    presence::PresenceEvent,
    stripped::AnyStrippedStateEvent,
    to_device::AnyToDeviceEvent,
    EventResult,
};
use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};

use crate::{
    r0::{filter::FilterDefinition, keys::KeyAlgorithm},
    serde::is_default,
};

ruma_api! {
    metadata {
        description: "Get all new events from all rooms since the last sync or a given point of time.",
        method: GET,
        name: "sync",
        path: "/_matrix/client/r0/sync",
        rate_limited: false,
        requires_authentication: true,
    }

    request {
        /// A filter represented either as its full JSON definition or the ID of a saved filter.
        #[serde(skip_serializing_if = "Option::is_none")]
        #[ruma_api(query)]
        pub filter: Option<Filter>,
        /// A point in time to continue a sync from.
        ///
        /// Should be a token from the `next_batch` field of a previous `/sync`
        /// request.
        #[serde(skip_serializing_if = "Option::is_none")]
        #[ruma_api(query)]
        pub since: Option<String>,
        /// Controls whether to include the full state for all rooms the user is a member of.
        #[serde(default, skip_serializing_if = "is_default")]
        #[ruma_api(query)]
        pub full_state: bool,
        /// Controls whether the client is automatically marked as online by polling this API.
        #[serde(default, skip_serializing_if = "is_default")]
        #[ruma_api(query)]
        pub set_presence: SetPresence,
        /// The maximum time to poll in milliseconds before returning this request.
        #[serde(with = "crate::serde::duration::opt_ms", skip_serializing_if = "Option::is_none")]
        #[ruma_api(query)]
        pub timeout: Option<Duration>,
    }

    response {
        /// The batch token to supply in the `since` param of the next `/sync` request.
        pub next_batch: String,
        /// Updates to rooms.
        #[wrap_incoming]
        pub rooms: Rooms,
        /// Updates to the presence status of other users.
        #[wrap_incoming]
        pub presence: Presence,
        /// Messages sent dirrectly between devices.
        #[serde(default, skip_serializing_if = "ToDevice::is_empty")]
        #[wrap_incoming]
        pub to_device: ToDevice,
        /// Information on E2E device updates.
        ///
        /// Only present on an incremental sync.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub device_lists: Option<DeviceLists>,
        /// For each key algorithm, the number of unclaimed one-time keys
        /// currently held on the server for a device.
        #[serde(skip_serializing_if = "HashMap::is_empty")]
        pub device_one_time_keys_count: HashMap<KeyAlgorithm, UInt>,
    }

    error: crate::Error
}

/// Whether to set presence or not during sync.
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum SetPresence {
    /// Do not set the presence of the user calling this API.
    Offline,
    /// Mark client as online explicitly. Assumed by default.
    Online,
    /// Mark client as being idle.
    Unavailable,
}

impl Default for SetPresence {
    fn default() -> Self {
        Self::Online
    }
}

/// A filter represented either as its full JSON definition or the ID of a saved filter.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[allow(clippy::large_enum_variant)]
#[serde(untagged)]
pub enum Filter {
    // The filter definition needs to be (de)serialized twice because it is a URL-encoded JSON
    // string. Since #[ruma_api(query)] only does the latter and this is a very uncommon
    // setup, we implement it through custom serde logic for this specific enum variant rather than
    // adding another ruma_api attribute.
    //
    // On the deserialization side, because this is an enum with #[serde(untagged)], serde will
    // try the variants in order (https://serde.rs/enum-representations.html). That means because
    // FilterDefinition is the first variant, JSON decoding is attempted first which is almost
    // functionally equivalent to looking at whether the first symbol is a '{' as the spec says.
    // (there are probably some corner cases like leading whitespace)
    #[serde(with = "filter_def_serde")]
    /// A complete filter definition serialized to JSON.
    FilterDefinition(FilterDefinition),
    /// The ID of a filter saved on the server.
    FilterId(String),
}

/// Serialization and deserialization logic for filter definitions.
mod filter_def_serde {
    use serde::{de::Error as _, ser::Error as _, Deserialize, Deserializer, Serializer};

    use crate::r0::filter::FilterDefinition;

    /// Serialization logic for filter definitions.
    pub fn serialize<S>(filter_def: &FilterDefinition, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let string = serde_json::to_string(filter_def).map_err(S::Error::custom)?;
        serializer.serialize_str(&string)
    }

    /// Deserialization logic for filter definitions.
    pub fn deserialize<'de, D>(deserializer: D) -> Result<FilterDefinition, D::Error>
    where
        D: Deserializer<'de>,
    {
        let filter_str = <&str>::deserialize(deserializer)?;

        serde_json::from_str(filter_str).map_err(D::Error::custom)
    }
}

/// Updates to rooms.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct Rooms {
    /// The rooms that the user has left or been banned from.
    #[wrap_incoming(LeftRoom)]
    pub leave: HashMap<RoomId, LeftRoom>,
    /// The rooms that the user has joined.
    #[wrap_incoming(JoinedRoom)]
    pub join: HashMap<RoomId, JoinedRoom>,
    /// The rooms that the user has been invited to.
    #[wrap_incoming(InvitedRoom)]
    pub invite: HashMap<RoomId, InvitedRoom>,
}

/// Historical updates to left rooms.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct LeftRoom {
    /// The timeline of messages and state changes in the room up to the point when the user
    /// left.
    #[wrap_incoming]
    pub timeline: Timeline,
    /// The state updates for the room up to the start of the timeline.
    #[wrap_incoming]
    pub state: State,
    /// The private data that this user has attached to this room.
    #[wrap_incoming]
    pub account_data: AccountData,
}

/// Updates to joined rooms.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct JoinedRoom {
    /// Information about the room which clients may need to correctly render it
    /// to users.
    pub summary: RoomSummary,
    /// Counts of unread notifications for this room.
    pub unread_notifications: UnreadNotificationsCount,
    /// The timeline of messages and state changes in the room.
    #[wrap_incoming]
    pub timeline: Timeline,
    /// Updates to the state, between the time indicated by the `since` parameter, and the start
    /// of the `timeline` (or all state up to the start of the `timeline`, if `since` is not
    /// given, or `full_state` is true).
    #[wrap_incoming]
    pub state: State,
    /// The private data that this user has attached to this room.
    #[wrap_incoming]
    pub account_data: AccountData,
    /// The ephemeral events in the room that aren't recorded in the timeline or state of the
    /// room. e.g. typing.
    #[wrap_incoming]
    pub ephemeral: Ephemeral,
}

/// unread notifications count
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct UnreadNotificationsCount {
    /// The number of unread notifications for this room with the highlight flag set.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub highlight_count: Option<UInt>,
    /// The total number of unread notifications for this room.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub notification_count: Option<UInt>,
}

/// Events in the room.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct Timeline {
    /// True if the number of events returned was limited by the `limit` on the filter.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub limited: Option<bool>,
    /// A token that can be supplied to to the `from` parameter of the
    /// `/rooms/{roomId}/messages` endpoint.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub prev_batch: Option<String>,
    /// A list of events.
    #[wrap_incoming(RoomEvent with EventResult)]
    pub events: Vec<RoomEvent>,
}

/// State events in the room.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct State {
    /// A list of state events.
    #[wrap_incoming(StateEvent with EventResult)]
    pub events: Vec<StateEvent>,
}

/// The private data that this user has attached to this room.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct AccountData {
    /// A list of events.
    #[wrap_incoming(NonRoomEvent with EventResult)]
    pub events: Vec<NonRoomEvent>,
}

/// Ephemeral events not recorded in the timeline or state of the room.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct Ephemeral {
    /// A list of events.
    #[wrap_incoming(NonRoomEvent with EventResult)]
    pub events: Vec<NonRoomEvent>,
}

/// Information about room for rendering to clients.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RoomSummary {
    /// Users which can be used to generate a room name if the room does not have
    /// one. Required if room name or canonical aliases are not set or empty.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub heroes: Vec<String>,
    /// Number of users whose membership status is `join`.
    /// Required if field has changed since last sync; otherwise, it may be
    /// omitted.
    pub joined_member_count: Option<UInt>,
    /// Number of users whose membership status is `invite`.
    /// Required if field has changed since last sync; otherwise, it may be
    /// omitted.
    pub invited_member_count: Option<UInt>,
}

/// Updates to the rooms that the user has been invited to.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct InvitedRoom {
    /// The state of a room that the user has been invited to.
    #[wrap_incoming]
    pub invite_state: InviteState,
}

/// The state of a room that the user has been invited to.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct InviteState {
    /// A list of state events.
    #[wrap_incoming(AnyStrippedStateEvent with EventResult)]
    pub events: Vec<AnyStrippedStateEvent>,
}

/// Updates to the presence status of other users.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct Presence {
    /// A list of events.
    #[wrap_incoming(PresenceEvent with EventResult)]
    pub events: Vec<PresenceEvent>,
}

/// Messages sent dirrectly between devices.
#[derive(Clone, Debug, Serialize, Outgoing)]
pub struct ToDevice {
    /// A list of to-device events.
    #[wrap_incoming(AnyToDeviceEvent with EventResult)]
    pub events: Vec<AnyToDeviceEvent>,
}

impl ToDevice {
    fn is_empty(&self) -> bool {
        self.events.is_empty()
    }
}

impl Default for IncomingToDevice {
    fn default() -> Self {
        Self { events: Vec::new() }
    }
}

/// Information on E2E device udpates.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DeviceLists {
    /// List of users who have updated their device identity keys or who now
    /// share an encrypted room with the client since the previous sync
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub changed: Vec<String>,
    /// List of users who no longer share encrypted rooms since the previous sync
    /// response.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub left: Vec<String>,
}

#[cfg(test)]
mod tests {
    use std::{convert::TryInto, time::Duration};

    use super::{Filter, Request, SetPresence};

    #[test]
    fn serialize_sync_request() {
        let req: http::Request<Vec<u8>> = Request {
            filter: Some(Filter::FilterId("66696p746572".into())),
            since: Some("s72594_4483_1934".into()),
            full_state: true,
            set_presence: SetPresence::Offline,
            timeout: Some(Duration::from_millis(30000)),
        }
        .try_into()
        .unwrap();

        let uri = req.uri();
        let query = uri.query().unwrap();

        assert_eq!(uri.path(), "/_matrix/client/r0/sync");
        assert!(query.contains("filter=66696p746572"));
        assert!(query.contains("since=s72594_4483_1934"));
        assert!(query.contains("full_state=true"));
        assert!(query.contains("set_presence=offline"));
        assert!(query.contains("timeout=30000"))
    }
}
<|endoftext|>


<commit_before>use super::types::{OrigFileName, Details};
use parser::{Parser, ParseError};

// Parses a wuala file conflict encoded in the file name in the form:
//
//    `<base_name> (conflicting version <version> from <host>).<extension>`
//
// e.g:
//
//    `x_original (conflicting version 5 from blub).txt`
//
// would return:
//
//    `Some("x_original.txt", "Version 5 from blub")`
//
pub fn parse(file_name: &str) -> Option<(OrigFileName, Details)>
{
   parse_internal(file_name).ok()
}

fn parse_internal(file_name: &str) -> Result<(OrigFileName, Details), ParseError>
{
   let mut parser = Parser::new(file_name);
   let mut base_name = parser.take_while(|c| c != '(');

   // drops the whitespace before the '('
   base_name.pop();

   try!(parser.skip("(conflicting version "));
   let version = try!(parser.take_uint());

   try!(parser.skip(" from ")
              .or(parser.skip(" from"))
              .or(Ok(())));

   let host = parser.take_while(|c| c != ')');
   try!(parser.skip(")"));

   if ! parser.eof() {
      let extension = parser.take_till_eof();
      base_name.push_str(extension.as_slice());
   }

   let details = format!("Version {} from {}", version, host);
   Ok((base_name, details))
}

#[test]
fn tests()
{
   test_str("original (conflicting version 1 from machine)", "original", "Version 1 from machine");
   test_str("x_original (conflicting version 5 from blub).txt", "x_original.txt", "Version 5 from blub");
   test_str("x_original (conflicting version 5 from ).txt", "x_original.txt", "Version 5 from ");
   test_str("x_original (conflicting version 5 from).txt", "x_original.txt", "Version 5 from ");
   test_str("x_original (conflicting version 5).txt", "x_original.txt", "Version 5 from ");
}

#[cfg(test)]
fn test_str(file_name: &str, orig_name: &str, details: &str)
{
   println!("test: {}", file_name);
   match parse_internal(file_name) {
      Ok((name, det)) => {
         assert_eq!(orig_name.to_string(), name);
         assert_eq!(details.to_string()  , det);
      }

      Err(err) => assert!(false, err)
   }
}
<commit_msg>Extend wuala tests<commit_after>use super::types::{OrigFileName, Details};
use parser::{Parser, ParseError};

// Parses a wuala file conflict encoded in the file name in the form:
//
//    `<base_name> (conflicting version <version> from <host>).<extension>`
//
// e.g:
//
//    `x_original (conflicting version 5 from blub).txt`
//
// would return:
//
//    `Some("x_original.txt", "Version 5 from blub")`
//
pub fn parse(file_name: &str) -> Option<(OrigFileName, Details)>
{
   parse_internal(file_name).ok()
}

fn parse_internal(file_name: &str) -> Result<(OrigFileName, Details), ParseError>
{
   let mut parser = Parser::new(file_name);
   let mut base_name = parser.take_while(|c| c != '(');

   // drops the whitespace before the '('
   base_name.pop();

   try!(parser.skip("(conflicting version "));
   let version = try!(parser.take_uint());

   try!(parser.skip(" from ")
              .or(parser.skip(" from"))
              .or(Ok(())));

   let host = parser.take_while(|c| c != ')');
   try!(parser.skip(")"));

   if ! parser.eof() {
      let extension = parser.take_till_eof();
      base_name.push_str(extension.as_slice());
   }

   let details = format!("Version {} from {}", version, host);
   Ok((base_name, details))
}

#[test]
fn tests()
{
   test_str("original (conflicting version 1 from machine)",
            Ok(("original".to_string(), "Version 1 from machine".to_string())));

   test_str("x_original (conflicting version 5 from blub).txt",
            Ok(("x_original.txt".to_string(), "Version 5 from blub".to_string())));

   test_str("x_original (conflicting version 5 from ).txt",
            Ok(("x_original.txt".to_string(), "Version 5 from ".to_string())));

   test_str("x_original (conflicting version 5 from).txt",
            Ok(("x_original.txt".to_string(), "Version 5 from ".to_string())));

   test_str("x_original (conflicting version 5).txt",
            Ok(("x_original.txt".to_string(), "Version 5 from ".to_string())));

   test_str("z_original", Err("Couldn't skip str '(conflicting version '!".to_string()));
}

#[cfg(test)]
fn test_str(file_name: &str, result: Result<(OrigFileName, Details), ParseError>)
{
   println!("test: {}", file_name);
   assert_eq!(parse_internal(file_name), result);
}
<|endoftext|>


<commit_before>use std::fmt;

use cranelift_codegen::{
    entity::SecondaryMap,
    ir::{entities::AnyEntity, function::DisplayFunctionAnnotations},
    write::{FuncWriter, PlainWriter},
};

use rustc_session::config::OutputType;

use crate::prelude::*;

/// This module provides the [CommentWriter] which makes it possible
/// to add comments to the written cranelift ir.
///
/// # Example
///
/// ```clif
/// test compile
/// target x86_64
///
/// function u0:0(i64, i64, i64) system_v {
/// ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
/// ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
/// ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
///
/// ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
/// ; msg   loc.idx    param    pass mode            ssa flags  ty
/// ; ret    _0      = v0       ByRef                NOT_SSA    (u8, u8)
/// ; arg    _1      = v1       ByRef                NOT_SSA    IsNotEmpty
/// ; arg    _2.0    = v2       ByVal(types::I64)    NOT_SSA    &&[u16]
///
///     ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
///     ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
///     ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
///     sig0 = (i64, i64, i64) system_v
///     sig1 = (i64, i64, i64) system_v
///     fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
///
/// block0(v0: i64, v1: i64, v2: i64):
///     v3 = stack_addr.i64 ss0
///     v4 = stack_addr.i64 ss1
///     store v2, v4
///     v5 = stack_addr.i64 ss2
///     jump block1
///
/// block1:
///     nop
/// ; _3 = &mut _1
/// ; _4 = _2
///     v6 = load.i64 v4
///     store v6, v5
/// ;
/// ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
///     v7 = load.i64 v5
///     call fn0(v0, v3, v7)
///     jump block2
///
/// block2:
///     nop
/// ;
/// ; return
///     return
/// }
/// ```

#[derive(Debug)]
pub(crate) struct CommentWriter {
    global_comments: Vec<String>,
    entity_comments: FxHashMap<AnyEntity, String>,
}

impl CommentWriter {
    pub(crate) fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
        let global_comments = if cfg!(debug_assertions) {
            vec![
                format!("symbol {}", tcx.symbol_name(instance).name.as_str()),
                format!("instance {:?}", instance),
                format!(
                    "sig {:?}",
                    tcx.normalize_erasing_late_bound_regions(
                        ParamEnv::reveal_all(),
                        &crate::abi::fn_sig_for_fn_abi(tcx, instance)
                    )
                ),
                String::new(),
            ]
        } else {
            vec![]
        };

        CommentWriter {
            global_comments,
            entity_comments: FxHashMap::default(),
        }
    }
}

#[cfg(debug_assertions)]
impl CommentWriter {
    pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
        self.global_comments.push(comment.into());
    }

    pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
        &mut self,
        entity: E,
        comment: S,
    ) {
        use std::collections::hash_map::Entry;
        match self.entity_comments.entry(entity.into()) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().push('\n');
                occ.get_mut().push_str(comment.as_ref());
            }
            Entry::Vacant(vac) => {
                vac.insert(comment.into());
            }
        }
    }
}

impl FuncWriter for &'_ CommentWriter {
    fn write_preamble(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        reg_info: Option<&isa::RegInfo>,
    ) -> Result<bool, fmt::Error> {
        for comment in &self.global_comments {
            if !comment.is_empty() {
                writeln!(w, "; {}", comment)?;
            } else {
                writeln!(w, "")?;
            }
        }
        if !self.global_comments.is_empty() {
            writeln!(w, "")?;
        }

        self.super_preamble(w, func, reg_info)
    }

    fn write_entity_definition(
        &mut self,
        w: &mut dyn fmt::Write,
        _func: &Function,
        entity: AnyEntity,
        value: &dyn fmt::Display,
    ) -> fmt::Result {
        write!(w, "    {} = {}", entity, value)?;

        if let Some(comment) = self.entity_comments.get(&entity) {
            writeln!(w, " ; {}", comment.replace('\n', "\n; "))
        } else {
            writeln!(w, "")
        }
    }

    fn write_block_header(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        isa: Option<&dyn isa::TargetIsa>,
        block: Block,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_block_header(w, func, isa, block, indent)
    }

    fn write_instruction(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        aliases: &SecondaryMap<Value, Vec<Value>>,
        isa: Option<&dyn isa::TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?;
        if let Some(comment) = self.entity_comments.get(&inst.into()) {
            writeln!(w, "; {}", comment.replace('\n', "\n; "))?;
        }
        Ok(())
    }
}

#[cfg(debug_assertions)]
impl<B: Backend + 'static> FunctionCx<'_, '_, B> {
    pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
        self.clif_comments.add_global_comment(comment);
    }

    pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
        &mut self,
        entity: E,
        comment: S,
    ) {
       self.clif_comments.add_comment(entity, comment);
    }
}

pub(crate) fn write_clif_file<'tcx>(
    tcx: TyCtxt<'tcx>,
    postfix: &str,
    instance: Instance<'tcx>,
    func: &cranelift_codegen::ir::Function,
    mut clif_comments: &CommentWriter,
    value_ranges: Option<&cranelift_codegen::ValueLabelsRanges>,
) {
    if !(cfg!(debug_assertions) || tcx.sess.opts.output_types.contains_key(&OutputType::LlvmAssembly)) {
        return;
    }

    use std::io::Write;

    let symbol_name = tcx.symbol_name(instance).name.as_str();
    let clif_file_name = format!(
        "{}/{}__{}.{}.clif",
        concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/clif"),
        tcx.crate_name(LOCAL_CRATE),
        symbol_name,
        postfix,
    );

    let mut clif = String::new();
    cranelift_codegen::write::decorate_function(
        &mut clif_comments,
        &mut clif,
        &func,
        &DisplayFunctionAnnotations {
            isa: Some(&*crate::build_isa(
                tcx.sess, true, /* PIC doesn't matter here */
            )),
            value_ranges,
        },
    )
    .unwrap();

    match ::std::fs::File::create(clif_file_name) {
        Ok(mut file) => {
            let target_triple = crate::target_triple(tcx.sess);
            writeln!(file, "test compile").unwrap();
            writeln!(file, "set is_pic").unwrap();
            writeln!(file, "target {}", target_triple).unwrap();
            writeln!(file, "").unwrap();
            file.write(clif.as_bytes()).unwrap();
        }
        Err(e) => {
            tcx.sess.warn(&format!("err opening clif file: {:?}", e));
        }
    }
}

impl<B: Backend + 'static> fmt::Debug for FunctionCx<'_, '_, B> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "{:?}", self.instance.substs)?;
        writeln!(f, "{:?}", self.local_map)?;

        let mut clif = String::new();
        ::cranelift_codegen::write::decorate_function(
            &mut &self.clif_comments,
            &mut clif,
            &self.bcx.func,
            &DisplayFunctionAnnotations::default(),
        )
        .unwrap();
        writeln!(f, "\n{}", clif)
    }
}
<commit_msg>Update src/pretty_clif.rs<commit_after>use std::fmt;

use cranelift_codegen::{
    entity::SecondaryMap,
    ir::{entities::AnyEntity, function::DisplayFunctionAnnotations},
    write::{FuncWriter, PlainWriter},
};

use rustc_session::config::OutputType;

use crate::prelude::*;

/// This module provides the [CommentWriter] which makes it possible
/// to add comments to the written cranelift ir.
///
/// # Example
///
/// ```clif
/// test compile
/// target x86_64
///
/// function u0:0(i64, i64, i64) system_v {
/// ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
/// ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
/// ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
///
/// ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
/// ; msg   loc.idx    param    pass mode            ssa flags  ty
/// ; ret    _0      = v0       ByRef                NOT_SSA    (u8, u8)
/// ; arg    _1      = v1       ByRef                NOT_SSA    IsNotEmpty
/// ; arg    _2.0    = v2       ByVal(types::I64)    NOT_SSA    &&[u16]
///
///     ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
///     ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
///     ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
///     sig0 = (i64, i64, i64) system_v
///     sig1 = (i64, i64, i64) system_v
///     fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
///
/// block0(v0: i64, v1: i64, v2: i64):
///     v3 = stack_addr.i64 ss0
///     v4 = stack_addr.i64 ss1
///     store v2, v4
///     v5 = stack_addr.i64 ss2
///     jump block1
///
/// block1:
///     nop
/// ; _3 = &mut _1
/// ; _4 = _2
///     v6 = load.i64 v4
///     store v6, v5
/// ;
/// ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
///     v7 = load.i64 v5
///     call fn0(v0, v3, v7)
///     jump block2
///
/// block2:
///     nop
/// ;
/// ; return
///     return
/// }
/// ```

#[derive(Debug)]
pub(crate) struct CommentWriter {
    global_comments: Vec<String>,
    entity_comments: FxHashMap<AnyEntity, String>,
}

impl CommentWriter {
    pub(crate) fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
        let global_comments = if cfg!(debug_assertions) {
            vec![
                format!("symbol {}", tcx.symbol_name(instance).name.as_str()),
                format!("instance {:?}", instance),
                format!(
                    "sig {:?}",
                    tcx.normalize_erasing_late_bound_regions(
                        ParamEnv::reveal_all(),
                        &crate::abi::fn_sig_for_fn_abi(tcx, instance)
                    )
                ),
                String::new(),
            ]
        } else {
            vec![]
        };

        CommentWriter {
            global_comments,
            entity_comments: FxHashMap::default(),
        }
    }
}

#[cfg(debug_assertions)]
impl CommentWriter {
    pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
        self.global_comments.push(comment.into());
    }

    pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
        &mut self,
        entity: E,
        comment: S,
    ) {
        use std::collections::hash_map::Entry;
        match self.entity_comments.entry(entity.into()) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().push('\n');
                occ.get_mut().push_str(comment.as_ref());
            }
            Entry::Vacant(vac) => {
                vac.insert(comment.into());
            }
        }
    }
}

impl FuncWriter for &'_ CommentWriter {
    fn write_preamble(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        reg_info: Option<&isa::RegInfo>,
    ) -> Result<bool, fmt::Error> {
        for comment in &self.global_comments {
            if !comment.is_empty() {
                writeln!(w, "; {}", comment)?;
            } else {
                writeln!(w, "")?;
            }
        }
        if !self.global_comments.is_empty() {
            writeln!(w, "")?;
        }

        self.super_preamble(w, func, reg_info)
    }

    fn write_entity_definition(
        &mut self,
        w: &mut dyn fmt::Write,
        _func: &Function,
        entity: AnyEntity,
        value: &dyn fmt::Display,
    ) -> fmt::Result {
        write!(w, "    {} = {}", entity, value)?;

        if let Some(comment) = self.entity_comments.get(&entity) {
            writeln!(w, " ; {}", comment.replace('\n', "\n; "))
        } else {
            writeln!(w, "")
        }
    }

    fn write_block_header(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        isa: Option<&dyn isa::TargetIsa>,
        block: Block,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_block_header(w, func, isa, block, indent)
    }

    fn write_instruction(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        aliases: &SecondaryMap<Value, Vec<Value>>,
        isa: Option<&dyn isa::TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?;
        if let Some(comment) = self.entity_comments.get(&inst.into()) {
            writeln!(w, "; {}", comment.replace('\n', "\n; "))?;
        }
        Ok(())
    }
}

#[cfg(debug_assertions)]
impl<B: Backend + 'static> FunctionCx<'_, '_, B> {
    pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
        self.clif_comments.add_global_comment(comment);
    }

    pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
        &mut self,
        entity: E,
        comment: S,
    ) {
       self.clif_comments.add_comment(entity, comment);
    }
}

pub(crate) fn write_clif_file<'tcx>(
    tcx: TyCtxt<'tcx>,
    postfix: &str,
    instance: Instance<'tcx>,
    func: &cranelift_codegen::ir::Function,
    mut clif_comments: &CommentWriter,
    value_ranges: Option<&cranelift_codegen::ValueLabelsRanges>,
) {
    if !cfg!(debug_assertions) && !tcx.sess.opts.output_types.contains_key(&OutputType::LlvmAssembly) {
        return;
    }

    use std::io::Write;

    let symbol_name = tcx.symbol_name(instance).name.as_str();
    let clif_file_name = format!(
        "{}/{}__{}.{}.clif",
        concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/clif"),
        tcx.crate_name(LOCAL_CRATE),
        symbol_name,
        postfix,
    );

    let mut clif = String::new();
    cranelift_codegen::write::decorate_function(
        &mut clif_comments,
        &mut clif,
        &func,
        &DisplayFunctionAnnotations {
            isa: Some(&*crate::build_isa(
                tcx.sess, true, /* PIC doesn't matter here */
            )),
            value_ranges,
        },
    )
    .unwrap();

    match ::std::fs::File::create(clif_file_name) {
        Ok(mut file) => {
            let target_triple = crate::target_triple(tcx.sess);
            writeln!(file, "test compile").unwrap();
            writeln!(file, "set is_pic").unwrap();
            writeln!(file, "target {}", target_triple).unwrap();
            writeln!(file, "").unwrap();
            file.write(clif.as_bytes()).unwrap();
        }
        Err(e) => {
            tcx.sess.warn(&format!("err opening clif file: {:?}", e));
        }
    }
}

impl<B: Backend + 'static> fmt::Debug for FunctionCx<'_, '_, B> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "{:?}", self.instance.substs)?;
        writeln!(f, "{:?}", self.local_map)?;

        let mut clif = String::new();
        ::cranelift_codegen::write::decorate_function(
            &mut &self.clif_comments,
            &mut clif,
            &self.bcx.func,
            &DisplayFunctionAnnotations::default(),
        )
        .unwrap();
        writeln!(f, "\n{}", clif)
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::fs;
use std::path;
use std::process;

use protobuf;

use config;
use error;

pub fn add_file(paths: &config::Paths,
                relative_to: &path::Path,
                file: &path::Path)
                -> error::Result<()> {
    let rel_file = file.strip_prefix(relative_to)
                       .unwrap_or(file.file_name().map(path::Path::new).unwrap_or(file));
    let target = paths.preferred_data("proto").join(rel_file);

    if let Some(parent) = target.parent() {
        trace!("Creating directory {:?}", parent);
        try!(fs::create_dir_all(parent));
    }

    try!(fs::copy(file, &target));
    info!("Added proto file as {:?}", target);
    Ok(())
}

pub fn compile_descriptor_set(paths: &config::Paths)
                              -> error::Result<protobuf::descriptor::FileDescriptorSet> {

    let proto_includes = try!(paths.find_data("proto"));
    let proto_files = try!(paths.find_data("proto/*.proto"));
    let cache = paths.preferred_cache("descriptor-cache.pb");

    debug!("Proto includes: {:?}", proto_includes);
    debug!("Proto files: {:?}", proto_files);
    debug!("Proto cache location: {:?}", cache);

    if try!(is_cache_stale(&cache, &proto_files)) {
        trace!("Proto descriptor cache is stale; recomputing");

        if let Some(parent) = cache.parent() {
            trace!("Creating directory {:?}", parent);
            try!(fs::create_dir_all(parent));
        }

        let include_args = proto_includes.into_iter()
                                         .map(|p| format!("-I{}", p.to_string_lossy()))
                                         .collect::<Vec<_>>();

        let status = try!(process::Command::new("protoc")
                              .arg("-o")
                              .arg(&cache)
                              .args(&include_args)
                              .args(&proto_files)
                              .status());
        if !status.success() {
            panic!("protoc descriptor compilation failed");
        }

        trace!("Proto descriptor cache regenerated");
    }

    let mut cache_file = try!(fs::File::open(&cache));
    let descriptor_set = try!(protobuf::parse_from_reader(&mut cache_file));

    trace!("Successfully parsed descriptor set from cache");

    Ok(descriptor_set)
}

fn is_cache_stale<P>(cache: &path::Path, proto_files: &[P]) -> error::Result<bool>
    where P: AsRef<path::Path>
{
    use std::os::unix::fs::MetadataExt;

    if cache.exists() {
        let cache_metadata = try!(fs::metadata(&cache));
        let cache_mtime = cache_metadata.mtime();
        let mut max_proto_mtime = 0;

        for proto_file in proto_files.iter() {
            let proto_metadata = try!(fs::metadata(&proto_file));
            let proto_mtime = proto_metadata.mtime();
            max_proto_mtime = cmp::max(max_proto_mtime, proto_mtime);
        }

        Ok(cache_mtime < max_proto_mtime)
    } else {
        Ok(true)
    }
}
<commit_msg>Search for proto files recursively<commit_after>use std::cmp;
use std::fs;
use std::path;
use std::process;

use protobuf;

use config;
use error;

pub fn add_file(paths: &config::Paths,
                relative_to: &path::Path,
                file: &path::Path)
                -> error::Result<()> {
    let rel_file = file.strip_prefix(relative_to)
                       .unwrap_or(file.file_name().map(path::Path::new).unwrap_or(file));
    let target = paths.preferred_data("proto").join(rel_file);

    if let Some(parent) = target.parent() {
        trace!("Creating directory {:?}", parent);
        try!(fs::create_dir_all(parent));
    }

    try!(fs::copy(file, &target));
    info!("Added proto file as {:?}", target);
    Ok(())
}

pub fn compile_descriptor_set(paths: &config::Paths)
                              -> error::Result<protobuf::descriptor::FileDescriptorSet> {

    let proto_includes = try!(paths.find_data("proto"));
    let proto_files = try!(paths.find_data("proto/**/*.proto"));
    let cache = paths.preferred_cache("descriptor-cache.pb");

    debug!("Proto includes: {:?}", proto_includes);
    debug!("Proto files: {:?}", proto_files);
    debug!("Proto cache location: {:?}", cache);

    if try!(is_cache_stale(&cache, &proto_files)) {
        trace!("Proto descriptor cache is stale; recomputing");

        if let Some(parent) = cache.parent() {
            trace!("Creating directory {:?}", parent);
            try!(fs::create_dir_all(parent));
        }

        let include_args = proto_includes.into_iter()
                                         .map(|p| format!("-I{}", p.to_string_lossy()))
                                         .collect::<Vec<_>>();

        let status = try!(process::Command::new("protoc")
                              .arg("-o")
                              .arg(&cache)
                              .args(&include_args)
                              .args(&proto_files)
                              .status());
        if !status.success() {
            panic!("protoc descriptor compilation failed");
        }

        trace!("Proto descriptor cache regenerated");
    }

    let mut cache_file = try!(fs::File::open(&cache));
    let descriptor_set = try!(protobuf::parse_from_reader(&mut cache_file));

    trace!("Successfully parsed descriptor set from cache");

    Ok(descriptor_set)
}

fn is_cache_stale<P>(cache: &path::Path, proto_files: &[P]) -> error::Result<bool>
    where P: AsRef<path::Path>
{
    use std::os::unix::fs::MetadataExt;

    if cache.exists() {
        let cache_metadata = try!(fs::metadata(&cache));
        let cache_mtime = cache_metadata.mtime();
        let mut max_proto_mtime = 0;

        for proto_file in proto_files.iter() {
            let proto_metadata = try!(fs::metadata(&proto_file));
            let proto_mtime = proto_metadata.mtime();
            max_proto_mtime = cmp::max(max_proto_mtime, proto_mtime);
        }

        Ok(cache_mtime < max_proto_mtime)
    } else {
        Ok(true)
    }
}
<|endoftext|>