<commit_before>extern crate cobalt;

use std::env;
use std::str;
use std::collections::HashMap;
use cobalt::{Client, Config, Connection, ConnectionID, MessageKind, Handler, Server};

struct ServerHandler;
impl Handler<Server> for ServerHandler {

    fn bind(&mut self, _: &mut Server) {
        println!("Server::bind");
    }

    fn tick_connections(
        &mut self, _: &mut Server,
        connections: &mut HashMap<ConnectionID, Connection>
    ) {
        for (_, conn) in connections.iter_mut() {
            conn.send(MessageKind::Reliable, b"Hello World".to_vec());
        }
    }

    fn shutdown(&mut self, _: &mut Server) {
        println!("Server::shutdown");
    }

    fn connection(&mut self, _: &mut Server, _: &mut Connection) {
        println!("Server::connection");
    }

    fn connection_failed(&mut self, _: &mut Server, _: &mut Connection) {
        println!("Server::connection_failed");
    }

    fn connection_packet_lost(
        &mut self, _: &mut Server, _: &mut Connection, p: &[u8]
    ) {
        println!("Server::connection_packet_loss {}", p.len());
    }

    fn connection_congestion_state(&mut self, _: &mut Server, _: &mut Connection, state: bool) {
        println!("Server::connection_congestion_state {}", state);
    }

    fn connection_lost(&mut self, _: &mut Server, _: &mut Connection) {
        println!("Server::connection_lost");
    }

}

struct ClientHandler;
impl Handler<Client> for ClientHandler {

    fn connect(&mut self, _: &mut Client) {
        println!("Client::connect");
    }

    fn tick_connection(&mut self, _: &mut Client, conn: &mut Connection) {
        for msg in conn.received() {
            println!("Received Message: {}", str::from_utf8(&msg).unwrap());
        }
    }

    fn close(&mut self, _: &mut Client) {
        println!("Client::close");
    }

    fn connection(&mut self, _: &mut Client, _: &mut Connection) {
        println!("Client::connection");
    }

    fn connection_failed(&mut self, client: &mut Client, _: &mut Connection) {
        println!("Client::connection_failed");
        client.close().unwrap();
    }

    fn connection_packet_lost(
        &mut self, _: &mut Client, _: &mut Connection, _: &[u8]
    ) {
        println!("Client::connection_packet_loss");
    }

    fn connection_congestion_state(&mut self, _: &mut Client, _: &mut Connection, state: bool) {
        println!("Client::connection_congestion_state {}", state);
    }

    fn connection_lost(&mut self, client: &mut Client, _: &mut Connection) {
        println!("Client::connection_lost");
        client.close().unwrap();
    }

}

fn main() {

    for arg in env::args().skip(1) {
        match &arg[..]  {
            "client" => {
                let config = Config::default();
                let mut handler = ClientHandler;
                let mut client = Client::new(config);
                client.connect(&mut handler, "127.0.0.1:7156").unwrap();
            },
            "server" => {
                let config = Config::default();
                let mut handler = ServerHandler;
                let mut server = Server::new(config);
                server.bind(&mut handler, "127.0.0.1:7156").unwrap();
            },
            _ => {

            }
        }
    }

}

<commit_msg>Update basic example with connection_close() handlers.<commit_after>extern crate cobalt;

use std::env;
use std::str;
use std::collections::HashMap;
use cobalt::{Client, Config, Connection, ConnectionID, MessageKind, Handler, Server};

struct ServerHandler;
impl Handler<Server> for ServerHandler {

    fn bind(&mut self, _: &mut Server) {
        println!("Server::bind");
    }

    fn tick_connections(
        &mut self, _: &mut Server,
        connections: &mut HashMap<ConnectionID, Connection>
    ) {
        for (_, conn) in connections.iter_mut() {
            conn.send(MessageKind::Reliable, b"Hello World".to_vec());
        }
    }

    fn shutdown(&mut self, _: &mut Server) {
        println!("Server::shutdown");
    }

    fn connection(&mut self, _: &mut Server, _: &mut Connection) {
        println!("Server::connection");
    }

    fn connection_failed(&mut self, _: &mut Server, _: &mut Connection) {
        println!("Server::connection_failed");
    }

    fn connection_packet_lost(
        &mut self, _: &mut Server, _: &mut Connection, p: &[u8]
    ) {
        println!("Server::connection_packet_loss {}", p.len());
    }

    fn connection_congestion_state(&mut self, _: &mut Server, _: &mut Connection, state: bool) {
        println!("Server::connection_congestion_state {}", state);
    }

    fn connection_lost(&mut self, _: &mut Server, _: &mut Connection) {
        println!("Server::connection_lost");
    }

    fn connection_closed(&mut self, _: &mut Server, _: &mut Connection, _: bool) {
        println!("Server::connection_closed");
    }

}

struct ClientHandler;
impl Handler<Client> for ClientHandler {

    fn connect(&mut self, _: &mut Client) {
        println!("Client::connect");
    }

    fn tick_connection(&mut self, _: &mut Client, conn: &mut Connection) {
        for msg in conn.received() {
            println!("Received Message: {}", str::from_utf8(&msg).unwrap());
        }
    }

    fn close(&mut self, _: &mut Client) {
        println!("Client::close");
    }

    fn connection(&mut self, _: &mut Client, _: &mut Connection) {
        println!("Client::connection");
    }

    fn connection_failed(&mut self, client: &mut Client, _: &mut Connection) {
        println!("Client::connection_failed");
        client.close().unwrap();
    }

    fn connection_packet_lost(
        &mut self, _: &mut Client, _: &mut Connection, _: &[u8]
    ) {
        println!("Client::connection_packet_loss");
    }

    fn connection_congestion_state(&mut self, _: &mut Client, _: &mut Connection, state: bool) {
        println!("Client::connection_congestion_state {}", state);
    }

    fn connection_lost(&mut self, client: &mut Client, _: &mut Connection) {
        println!("Client::connection_lost");
        client.close().unwrap();
    }

    fn connection_closed(&mut self, _: &mut Client, _: &mut Connection, _: bool) {
        println!("Client::connection_closed");
    }

}

fn main() {

    for arg in env::args().skip(1) {
        match &arg[..]  {
            "client" => {
                let config = Config::default();
                let mut handler = ClientHandler;
                let mut client = Client::new(config);
                client.connect(&mut handler, "127.0.0.1:7156").unwrap();
            },
            "server" => {
                let config = Config::default();
                let mut handler = ServerHandler;
                let mut server = Server::new(config);
                server.bind(&mut handler, "127.0.0.1:7156").unwrap();
            },
            _ => {

            }
        }
    }

}

<|endoftext|>


<commit_before>#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;
#[macro_use]
extern crate torchrs;
#[macro_use]
extern crate clap;

use torchrs::autograd::{Variable, VariableArgs, VarAccess};
use torchrs::optim;
use torchrs::optim::OptimVal;
use torchrs::nn;
use torchrs::nn::{InitModuleStruct, GetFieldStruct, ModIntf, ModDelegate, Module};
use torchrs::nn::functional as F;
use torchrs::utils::data as D;
use torchrs::utils::torchvision::{datasets, transforms};
use torchrs::tensor;

use clap::{Arg, App};
#[derive(Clone, Builder)]
struct NetArgs {
    #[builder(default="64")]
    batch_size: usize,
    #[builder(default="1000")]
    test_batch_size: usize,
    #[builder(default="10")]
    epochs: u32,
    #[builder(default="0.01")]
    lr: f32,
    #[builder(default="0.5")]
    momentum: f32,
    #[builder(default="true")]
    cuda: bool,
    #[builder(default="1")]
    seed: usize,
    #[builder(default="10")]
    log_interval: usize,
}

impl Default for NetArgs {
    fn default() -> Self {
        NetArgsBuilder::default().build().unwrap()
    }
}

fn parse_args() -> NetArgs {
    let mut args = NetArgs::default();
    let matches = App::new("Torch.rs MNIST Example")
        .version("0.1")
        .author("Some Guy")
        .about("recognize handwritten digits")
        .arg(Arg::with_name("batch-size").takes_value(true))
        .arg(Arg::with_name("test-batch-size").takes_value(true))
        .arg(Arg::with_name("epochs").takes_value(true))
        .arg(Arg::with_name("lr").takes_value(true))
        .arg(Arg::with_name("momentum").takes_value(true))
        .arg(Arg::with_name("no-cuda").takes_value(false))
        .arg(Arg::with_name("seed").takes_value(true))
        .arg(Arg::with_name("log-interval").takes_value(true))
        .get_matches();
    let (b_size, tb_size, epochs, lr, momentum, seed, log_int) =
        (value_t!(matches.value_of("batch-size"), usize).ok(),
         value_t!(matches.value_of("test-batch-size"), usize).ok(),
         value_t!(matches.value_of("epochs"), u32).ok(),
         value_t!(matches.value_of("lr"), f32).ok(),
         value_t!(matches.value_of("momentum"), f32).ok(),
         value_t!(matches.value_of("seed"), usize).ok(),
         value_t!(matches.value_of("log-interval"), usize).ok());
    if let Some(b_size) = b_size {
        args.batch_size = b_size
    }
    if let Some(tb_size) = tb_size {
        args.test_batch_size = tb_size
    }
    if let Some(epochs) = epochs {
        args.epochs = epochs
    }
    if let Some(lr) = lr {
        args.lr = lr
    }
    if let Some(momentum) = momentum {
        args.momentum = momentum
    }
    if let Some(seed) = seed {
        args.seed = seed
    }
    if let Some(log_int) = log_int {
        args.log_interval = log_int
    }
    //XXX CUDA?
    args
}

#[derive(ModParse)]
struct Net<T: tensor::NumLimits> {
    delegate: nn::Module<T>,
    conv1: nn::Conv2d<T>,
    conv2: nn::Conv2d<T>,
    fc1: nn::Linear<T>,
    fc2: nn::Linear<T>,
}

impl<T: tensor::NumLimits> Net<T> {
    pub fn new() -> Net<T> {
        Net {
                delegate: nn::Module::new(),
                conv1: nn::Conv2d::build(1, 10, (5, 5)).done(),
                conv2: nn::Conv2d::build(10, 20, (5, 5)).done(),
                fc1: nn::Linear::build(320, 50).done(),
                fc2: nn::Linear::build(50, 10).done(),
            }
            .init_module()
    }
}
impl_mod_delegate!(Net);

// The forward operations could take on one of two implementations.
// The first supporting a near verbatim version of the python
// implementation, and the second supporting a slightly more
// idiomatic to Rust method chaining.

// a) as a near verbatim implementation of the python version
impl<T: tensor::NumLimits> ModIntf<T> for Net<T> {
    fn forward(&mut self, args: &mut Variable<T>) -> Variable<T> {
        let pool_val = F::MaxPool2dArgs::default();
        let mut dropout_val = F::DropoutArgs::default();
        dropout_val.training = self.delegate.training;
        let mut x = F::relu(F::max_pool2d(self.conv1.f(args), (2, 2), &pool_val));
        x = F::relu(F::max_pool2d(F::dropout2d(self.conv2.f(x), &dropout_val),
                                  (2, 2),
                                  &pool_val));
        x = x.view([-1, 320]);
        x = F::relu(self.fc1.f(x));
        x = F::dropout(x, &dropout_val);
        x = self.fc2.f(x);
        F::log_softmax(x)
    }
}

fn train(model: &mut Net<f32>,
         args: &NetArgs,
         train_loader: &D::BatchLoader<f32, i64>,
         epoch: u32,
         optimizer: &mut optim::OptIntf<f32>) {
    model.train();
    for (batch_idx, (ref data, ref target)) in train_loader.iter().enumerate() {
        let (mut data, target) = if args.cuda {
            (Variable::new(data.cuda(None).clone()), Variable::new(target.cuda(None).clone()))
        } else {
            (Variable::new(data.clone()), Variable::new(target.clone()))
        };
        optimizer.zero_grad(model);
        let output = model.f(data.clone());
        let mut loss = F::nll_loss(output, target, &F::NLLLossArgs::default());
        loss.backward();
        optimizer.step(model);
        if batch_idx % args.log_interval == 0 {
            println!("Train Epoch: {} [{}/{} ({:.0}%)]\tLoss: {:.6}",
                     epoch,
                     batch_idx * data.data().len(),
                     train_loader.dataset.len(),
                     100. * (batch_idx as f32) / train_loader.len() as f32,
                     loss.data()[0]);
        }
    }
}

fn test(model: &mut Net<f32>, args: &NetArgs, test_loader: &D::BatchLoader<f32, i64>) {
    model.eval();
    let mut test_loss = 0.;
    let mut correct = 0;
    for (ref data, ref target) in test_loader.iter() {
        let varargs = VariableArgs {
            volatile: true,
            ..Default::default()
        };
        let (mut data, mut target) = if args.cuda {
            (Variable::new_args(data.cuda(None).clone(), &varargs),
             Variable::new(target.cuda(None).clone()))
        } else {
            (Variable::new_args(data.clone(), &varargs), Variable::new(target.clone()))
        };
        let mut output = model.f(data);
        test_loss += F::nll_loss(output.clone(), target.clone(), &F::NLLLossArgs::default());
        let pred = output.data().max_reduce(1).1;
        correct += pred.eq_tensor(&*target.data()).cpu().sum() as u32;
    }
    test_loss /= test_loader.len() as f32;
    println!("\nTest set: Average loss: {:.4}, Accuracy: {}/{} ({:.0}%)\n",
             test_loss,
             correct,
             test_loader.dataset.len(),
             100. * (correct as f32) / (test_loader.dataset.len() as f32))

}

fn main() {
    // no data loaders yet so demonstrate with Vec placeholder

    let train_loader: D::BatchLoader<f32, i64> =
        D::DataLoader::new(datasets::MNIST::<f32>::build("../data").done(None),
                           D::DataLoaderArgs::default());

    let test_loader: D::BatchLoader<f32, i64> =
        D::DataLoader::new(datasets::MNIST::<f32>::build("../data").done(None),
                           D::DataLoaderArgs::default());
    let args = parse_args();
    let mut model = Net::new();
    let mut optimizer = optim::SGD::new(map_opt!{"lr" => args.lr, "momentum" => args.momentum});
    for epoch in 1..args.epochs + 1 {
        train(&mut model, &args, &train_loader, epoch, &mut optimizer);
        test(&mut model, &args, &test_loader);
    }
}
<commit_msg>compile fix<commit_after>#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;
#[macro_use]
extern crate torchrs;
#[macro_use]
extern crate clap;

use torchrs::autograd::{Variable, VariableArgs, VarAccess};
use torchrs::optim;
use torchrs::optim::OptimVal;
use torchrs::nn;
use torchrs::nn::{InitModuleStruct, GetFieldStruct, ModIntf, ModDelegate, Module};
use torchrs::nn::functional as F;
use torchrs::utils::data as D;
use torchrs::utils::torchvision::{datasets, transforms};
use torchrs::tensor;

use clap::{Arg, App};
#[derive(Clone, Builder)]
struct NetArgs {
    #[builder(default="64")]
    batch_size: usize,
    #[builder(default="1000")]
    test_batch_size: usize,
    #[builder(default="10")]
    epochs: u32,
    #[builder(default="0.01")]
    lr: f32,
    #[builder(default="0.5")]
    momentum: f32,
    #[builder(default="true")]
    cuda: bool,
    #[builder(default="1")]
    seed: usize,
    #[builder(default="10")]
    log_interval: usize,
}

impl Default for NetArgs {
    fn default() -> Self {
        NetArgsBuilder::default().build().unwrap()
    }
}

fn parse_args() -> NetArgs {
    let mut args = NetArgs::default();
    let matches = App::new("Torch.rs MNIST Example")
        .version("0.1")
        .author("Some Guy")
        .about("recognize handwritten digits")
        .arg(Arg::with_name("batch-size").takes_value(true))
        .arg(Arg::with_name("test-batch-size").takes_value(true))
        .arg(Arg::with_name("epochs").takes_value(true))
        .arg(Arg::with_name("lr").takes_value(true))
        .arg(Arg::with_name("momentum").takes_value(true))
        .arg(Arg::with_name("no-cuda").takes_value(false))
        .arg(Arg::with_name("seed").takes_value(true))
        .arg(Arg::with_name("log-interval").takes_value(true))
        .get_matches();
    let (b_size, tb_size, epochs, lr, momentum, seed, log_int) =
        (value_t!(matches.value_of("batch-size"), usize).ok(),
         value_t!(matches.value_of("test-batch-size"), usize).ok(),
         value_t!(matches.value_of("epochs"), u32).ok(),
         value_t!(matches.value_of("lr"), f32).ok(),
         value_t!(matches.value_of("momentum"), f32).ok(),
         value_t!(matches.value_of("seed"), usize).ok(),
         value_t!(matches.value_of("log-interval"), usize).ok());
    if let Some(b_size) = b_size {
        args.batch_size = b_size
    }
    if let Some(tb_size) = tb_size {
        args.test_batch_size = tb_size
    }
    if let Some(epochs) = epochs {
        args.epochs = epochs
    }
    if let Some(lr) = lr {
        args.lr = lr
    }
    if let Some(momentum) = momentum {
        args.momentum = momentum
    }
    if let Some(seed) = seed {
        args.seed = seed
    }
    if let Some(log_int) = log_int {
        args.log_interval = log_int
    }
    //XXX CUDA?
    args
}

#[derive(ModParse)]
struct Net<T: tensor::NumLimits> {
    delegate: nn::Module<T>,
    conv1: nn::Conv2d<T>,
    conv2: nn::Conv2d<T>,
    fc1: nn::Linear<T>,
    fc2: nn::Linear<T>,
}

impl<T: tensor::NumLimits> Net<T> {
    pub fn new() -> Net<T> {
        Net {
                delegate: nn::Module::new(),
                conv1: nn::Conv2d::build(1, 10, (5, 5)).done(),
                conv2: nn::Conv2d::build(10, 20, (5, 5)).done(),
                fc1: nn::Linear::build(320, 50).done(),
                fc2: nn::Linear::build(50, 10).done(),
            }
            .init_module()
    }
}
impl_mod_delegate!(Net);

// The forward operations could take on one of two implementations.
// The first supporting a near verbatim version of the python
// implementation, and the second supporting a slightly more
// idiomatic to Rust method chaining.

// a) as a near verbatim implementation of the python version
impl<T: tensor::NumLimits> ModIntf<T> for Net<T> {
    fn forward(&mut self, args: &mut Variable<T>) -> Variable<T> {
        let pool_val = F::MaxPool2dArgs::default();
        let mut dropout_val = F::DropoutArgs::default();
        dropout_val.training = self.delegate.training;
        let mut x = F::relu(F::max_pool2d(self.conv1.f(args.clone()), (2, 2), &pool_val));
        x = F::relu(F::max_pool2d(F::dropout2d(self.conv2.f(x), &dropout_val),
                                  (2, 2),
                                  &pool_val));
        x = x.view([-1, 320]);
        x = F::relu(self.fc1.f(x));
        x = F::dropout(x, &dropout_val);
        x = self.fc2.f(x);
        F::log_softmax(x)
    }
}

fn train(model: &mut Net<f32>,
         args: &NetArgs,
         train_loader: &D::BatchLoader<f32, i64>,
         epoch: u32,
         optimizer: &mut optim::OptIntf<f32>) {
    model.train();
    for (batch_idx, (ref data, ref target)) in train_loader.iter().enumerate() {
        let (mut data, target) = if args.cuda {
            (Variable::new(data.cuda(None).clone()), Variable::new(target.cuda(None).clone()))
        } else {
            (Variable::new(data.clone()), Variable::new(target.clone()))
        };
        optimizer.zero_grad(model);
        let output = model.f(data.clone());
        let mut loss = F::nll_loss(output, target, &F::NLLLossArgs::default());
        loss.backward();
        optimizer.step(model);
        if batch_idx % args.log_interval == 0 {
            println!("Train Epoch: {} [{}/{} ({:.0}%)]\tLoss: {:.6}",
                     epoch,
                     batch_idx * data.data().len(),
                     train_loader.dataset.len(),
                     100. * (batch_idx as f32) / train_loader.len() as f32,
                     loss.data()[0]);
        }
    }
}

fn test(model: &mut Net<f32>, args: &NetArgs, test_loader: &D::BatchLoader<f32, i64>) {
    model.eval();
    let mut test_loss = 0.;
    let mut correct = 0;
    for (ref data, ref target) in test_loader.iter() {
        let varargs = VariableArgs {
            volatile: true,
            ..Default::default()
        };
        let (mut data, mut target) = if args.cuda {
            (Variable::new_args(data.cuda(None).clone(), &varargs),
             Variable::new(target.cuda(None).clone()))
        } else {
            (Variable::new_args(data.clone(), &varargs), Variable::new(target.clone()))
        };
        let mut output = model.f(data);
        test_loss += F::nll_loss(output.clone(), target.clone(), &F::NLLLossArgs::default());
        let pred = output.data().max_reduce(1).1;
        correct += pred.eq_tensor(&*target.data()).cpu().sum() as u32;
    }
    test_loss /= test_loader.len() as f32;
    println!("\nTest set: Average loss: {:.4}, Accuracy: {}/{} ({:.0}%)\n",
             test_loss,
             correct,
             test_loader.dataset.len(),
             100. * (correct as f32) / (test_loader.dataset.len() as f32))

}

fn main() {
    // no data loaders yet so demonstrate with Vec placeholder

    let train_loader: D::BatchLoader<f32, i64> =
        D::DataLoader::new(datasets::MNIST::<f32>::build("../data").done(None),
                           D::DataLoaderArgs::default());

    let test_loader: D::BatchLoader<f32, i64> =
        D::DataLoader::new(datasets::MNIST::<f32>::build("../data").done(None),
                           D::DataLoaderArgs::default());
    let args = parse_args();
    let mut model = Net::new();
    let mut optimizer = optim::SGD::new(map_opt!{"lr" => args.lr, "momentum" => args.momentum});
    for epoch in 1..args.epochs + 1 {
        train(&mut model, &args, &train_loader, epoch, &mut optimizer);
        test(&mut model, &args, &test_loader);
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate mount;

use iron::{Iron, Request, Response, IronResult};
use iron::status;

use mount::Mount;

fn send_hello(req: &mut Request) -> IronResult<Response> {
    println!("Running send_hello handler, URL path: {:?}", req.url.path);
    Ok(Response::with((status::Ok, "Hello!")))
}

fn intercept(req: &mut Request) -> IronResult<Response> {
    println!("Running intercept handler, URL path: {:?}", req.url.path);
    Ok(Response::with((status::Ok, "Blocked!")))
}

fn main() {
    let mut mount = Mount::new();
    mount.mount("/blocked/", intercept).mount("/", send_hello);

    Iron::new(mount).http("localhost:3000").unwrap();
}

<commit_msg>use iron 0.4 apis in examples<commit_after>extern crate iron;
extern crate mount;

use iron::{Iron, Request, Response, IronResult};
use iron::status;

use mount::Mount;

fn send_hello(req: &mut Request) -> IronResult<Response> {
    println!("Running send_hello handler, URL path: {:?}", req.url.path());
    Ok(Response::with((status::Ok, "Hello!")))
}

fn intercept(req: &mut Request) -> IronResult<Response> {
    println!("Running intercept handler, URL path: {:?}", req.url.path());
    Ok(Response::with((status::Ok, "Blocked!")))
}

fn main() {
    let mut mount = Mount::new();
    mount.mount("/blocked/", intercept).mount("/", send_hello);

    Iron::new(mount).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>//! Internal FFI and marshalling things.

use std::mem;

use cairo;
use cairo::prelude::SurfaceExt;
use cairo_sys::cairo_surface_t;
use glib::translate::{from_glib_borrow, ToGlibPtr};
use glib_sys::*;
use libc::c_char;

use drawing_ctx::RsvgDrawingCtx;
use filter_context::{FilterContext, RsvgFilter, RsvgFilterContext};
use length::RsvgLength;
use node::{NodeType, RsvgCNodeImpl, RsvgNode};
use state::{ComputedValues, RsvgComputedValues};

use super::Filter;

// Required by the C code until all filters are ported to Rust.
// Keep this in sync with
// ../../librsvg/librsvg/filters/common.h:_RsvgFilterPrimitive
#[repr(C)]
pub struct RsvgFilterPrimitive {
    pub x: RsvgLength,
    pub y: RsvgLength,
    pub width: RsvgLength,
    pub height: RsvgLength,
    pub x_specified: gboolean,
    pub y_specified: gboolean,
    pub width_specified: gboolean,
    pub height_specified: gboolean,
    in_: *mut GString,
    result: *mut GString,

    render: Option<
        unsafe extern "C" fn(
            *mut RsvgNode,
            RsvgComputedValues,
            *mut RsvgFilterPrimitive,
            *mut RsvgFilterContext,
        ),
    >,
}

/// The type of the render function below.
pub(super) type RenderFunctionType = fn(&RsvgNode, &mut FilterContext);

/// Downcasts the given `node` to the type `T` and calls `Filter::render()` on it.
pub(super) fn render<T: Filter>(node: &RsvgNode, ctx: &mut FilterContext) {
    node.with_impl(|filter: &T| filter.render(node, ctx));
}

/// Creates a new surface applied the filter. This function will create a context for itself, set up
/// the coordinate systems execute all its little primitives and then clean up its own mess.
#[no_mangle]
pub unsafe extern "C" fn rsvg_filter_render(
    filter_node: *mut RsvgNode,
    source: *mut cairo_surface_t,
    context: *mut RsvgDrawingCtx,
    channelmap: *const c_char,
) -> *mut cairo_surface_t {
    assert!(!filter_node.is_null());
    assert!(!source.is_null());
    assert!(!context.is_null());
    assert!(!channelmap.is_null());

    let source: cairo::Surface = from_glib_borrow(source);
    assert_eq!(source.get_type(), cairo::SurfaceType::Image);
    let source = cairo::ImageSurface::from(source).unwrap();

    let filter_node = &*filter_node;
    assert_eq!(filter_node.get_type(), NodeType::Filter);

    let values = &filter_node.get_computed_values() as &ComputedValues;

    let mut channelmap_arr = [0; 4];
    for i in 0..4 {
        channelmap_arr[i] = i32::from(*channelmap.offset(i as isize) - '0' as i8);
    }

    let mut filter_ctx = FilterContext::new(
        filter_node.get_c_impl() as *mut RsvgFilter,
        filter_node,
        source,
        context,
        channelmap_arr,
    );

    filter_node
        .children()
        .filter(|c| {
            c.get_type() > NodeType::FilterPrimitiveFirst
                && c.get_type() < NodeType::FilterPrimitiveLast
        })
        .filter(|c| !c.is_in_error())
        .for_each(|mut c| match c.get_type() {
            NodeType::FilterPrimitiveOffset => {
                let render =
                    *(&c.get_c_impl() as *const *const RsvgCNodeImpl as *const RenderFunctionType);
                render(&c, &mut filter_ctx);
            }
            _ => {
                let filter = &mut *(c.get_c_impl() as *mut RsvgFilterPrimitive);
                (filter.render.unwrap())(
                    &mut c,
                    values as RsvgComputedValues,
                    filter,
                    &mut filter_ctx,
                );
            }
        });

    // HACK because to_glib_full() is unimplemented!() on ImageSurface.
    let result = filter_ctx.into_result();
    let ptr = result.to_glib_none().0;
    mem::forget(result);
    ptr
}
<commit_msg>Pass the filter primitive's computed values to its ::render() method, not the filter context's<commit_after>//! Internal FFI and marshalling things.

use std::mem;

use cairo;
use cairo::prelude::SurfaceExt;
use cairo_sys::cairo_surface_t;
use glib::translate::{from_glib_borrow, ToGlibPtr};
use glib_sys::*;
use libc::c_char;

use drawing_ctx::RsvgDrawingCtx;
use filter_context::{FilterContext, RsvgFilter, RsvgFilterContext};
use length::RsvgLength;
use node::{NodeType, RsvgCNodeImpl, RsvgNode};
use state::{ComputedValues, RsvgComputedValues};

use super::Filter;

// Required by the C code until all filters are ported to Rust.
// Keep this in sync with
// ../../librsvg/librsvg/filters/common.h:_RsvgFilterPrimitive
#[repr(C)]
pub struct RsvgFilterPrimitive {
    pub x: RsvgLength,
    pub y: RsvgLength,
    pub width: RsvgLength,
    pub height: RsvgLength,
    pub x_specified: gboolean,
    pub y_specified: gboolean,
    pub width_specified: gboolean,
    pub height_specified: gboolean,
    in_: *mut GString,
    result: *mut GString,

    render: Option<
        unsafe extern "C" fn(
            *mut RsvgNode,
            RsvgComputedValues,
            *mut RsvgFilterPrimitive,
            *mut RsvgFilterContext,
        ),
    >,
}

/// The type of the render function below.
pub(super) type RenderFunctionType = fn(&RsvgNode, &mut FilterContext);

/// Downcasts the given `node` to the type `T` and calls `Filter::render()` on it.
pub(super) fn render<T: Filter>(node: &RsvgNode, ctx: &mut FilterContext) {
    node.with_impl(|filter: &T| filter.render(node, ctx));
}

/// Creates a new surface applied the filter. This function will create a context for itself, set up
/// the coordinate systems execute all its little primitives and then clean up its own mess.
#[no_mangle]
pub unsafe extern "C" fn rsvg_filter_render(
    filter_node: *mut RsvgNode,
    source: *mut cairo_surface_t,
    context: *mut RsvgDrawingCtx,
    channelmap: *const c_char,
) -> *mut cairo_surface_t {
    assert!(!filter_node.is_null());
    assert!(!source.is_null());
    assert!(!context.is_null());
    assert!(!channelmap.is_null());

    let source: cairo::Surface = from_glib_borrow(source);
    assert_eq!(source.get_type(), cairo::SurfaceType::Image);
    let source = cairo::ImageSurface::from(source).unwrap();

    let filter_node = &*filter_node;
    assert_eq!(filter_node.get_type(), NodeType::Filter);

    let values = &filter_node.get_computed_values() as &ComputedValues;

    let mut channelmap_arr = [0; 4];
    for i in 0..4 {
        channelmap_arr[i] = i32::from(*channelmap.offset(i as isize) - '0' as i8);
    }

    let mut filter_ctx = FilterContext::new(
        filter_node.get_c_impl() as *mut RsvgFilter,
        filter_node,
        source,
        context,
        channelmap_arr,
    );

    filter_node
        .children()
        .filter(|c| {
            c.get_type() > NodeType::FilterPrimitiveFirst
                && c.get_type() < NodeType::FilterPrimitiveLast
        })
        .filter(|c| !c.is_in_error())
        .for_each(|mut c| match c.get_type() {
            NodeType::FilterPrimitiveOffset => {
                let render =
                    *(&c.get_c_impl() as *const *const RsvgCNodeImpl as *const RenderFunctionType);
                render(&c, &mut filter_ctx);
            }
            _ => {
                let filter = &mut *(c.get_c_impl() as *mut RsvgFilterPrimitive);
                (filter.render.unwrap())(
                    &mut c,
                    &c.get_computed_values() as &ComputedValues as RsvgComputedValues,
                    filter,
                    &mut filter_ctx,
                );
            }
        });

    // HACK because to_glib_full() is unimplemented!() on ImageSurface.
    let result = filter_ctx.into_result();
    let ptr = result.to_glib_none().0;
    mem::forget(result);
    ptr
}
<|endoftext|>


<commit_before><commit_msg>fix(metrics): swap uid for cid<commit_after><|endoftext|>


<commit_before>extern crate mach;
extern crate glium;

use std::rc::Rc;
use std::mem;
use std::collections::HashMap;

use self::glium::backend::glutin_backend::GlutinFacade;

use support::{SceneEnv, Instance, InstanceFactory, FrameMetadata, PolygonModel};
use support::polygons;

pub struct ExamplesRenderer {
    program: glium::Program,
    cube: Rc<PolygonModel>,
    instances: HashMap<mach::ID, Instance>,
    factory: InstanceFactory,
}

impl ExamplesRenderer {
    pub fn new(display: &GlutinFacade) -> Result<ExamplesRenderer, String> {
        let program = try!(
            glium::Program::from_source(
                display,
                include_str!("shaders/foreground.vert.glsl"),
                include_str!("shaders/foreground.frag.glsl"),
                None,
            ).map_err(|err| format!("{}", err))
        );

        Ok(ExamplesRenderer {
            instances: HashMap::new(),
            cube: Rc::new(polygons::initialize_cube(display)),
            program: program,
            factory: InstanceFactory::new(),
        })
    }

    pub fn render<S: glium::Surface>(&mut self, surface: &mut S, world: &mach::World, frame_metadata: &FrameMetadata, env: &SceneEnv) -> Result<(), String> {
        surface.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);

        let mut old_instances = HashMap::new();

        mem::swap(&mut old_instances, &mut self.instances);

        for body in world.rigid_bodies_iter() {
            if let Some(instance) = old_instances.remove(&body.id()) {
                self.render_and_save(surface, instance, body.transform(), env);
            } else {
                let instance = self.generate_new_instance(body.id(), body.shape());

                self.render_and_save(surface, instance, body.transform(), env);
            }
        }

        try!(self.render_contacts(surface, &frame_metadata.contacts, env));
        return Ok(());
    }

    fn render_contacts<S: glium::Surface>(&mut self, surface: &mut S, contacts: &Vec<mach::maths::Vect>, env: &SceneEnv) -> Result<(), String> {
        let mut model_matrix: [[f32; 4]; 4] = [
            [0.1, 0.0, 0.0, 0.0],
            [0.0, 0.1, 0.0, 0.0],
            [0.0, 0.0, 0.1, 0.0],
            [0.0, 0.0, 0.0, 1.0],
        ];

        for contact in contacts.iter() {
            model_matrix[3][0] = contact.x;
            model_matrix[3][1] = contact.y;
            model_matrix[3][2] = contact.z;

            surface.draw(
                (&self.cube.vertices, &self.cube.normals),
                &self.cube.indices,
                &self.program,
                &uniform! {
                    projection_matrix: *env.camera.projection_matrix(),
                    view_matrix: env.camera.view_matrix(),
                    model_matrix: model_matrix,
                    light_direction: [1.0, 2.0, 1.0f32],
                    surface_color: [1.0, 1.0, 0.0, 1.0f32],
                },
                &glium::DrawParameters {
                    depth: glium::Depth {
                        test: glium::draw_parameters::DepthTest::Overwrite,
                        write: false,
                        .. Default::default()
                    },
                    .. Default::default()
                },
            ).unwrap();
        }

        return Ok(());
    }

    fn render_and_save<S: glium::Surface>(&mut self, surface: &mut S, instance: Instance, transform: &mach::maths::Transform, env: &SceneEnv) {
        let quat = transform.rotation().normalize();
        let r11 = 1.0 - 2.0*quat.j*quat.j - 2.0*quat.k*quat.k;
        let r12 = 2.0*quat.i*quat.j - 2.0*quat.r*quat.k;
        let r13 = 2.0*quat.i*quat.k + 2.0*quat.r*quat.j;
        let r21 = 2.0*quat.i*quat.j + 2.0*quat.r*quat.k;
        let r22 = 1.0 - 2.0*quat.i*quat.i - 2.0*quat.k*quat.k;
        let r23 = 2.0*quat.j*quat.k - 2.0*quat.r*quat.i;
        let r31 = 2.0*quat.i*quat.k - 2.0*quat.r*quat.j;
        let r32 = 2.0*quat.j*quat.k + 2.0*quat.r*quat.i;
        let r33 = 1.0 - 2.0*quat.i*quat.i - 2.0*quat.j*quat.j;

        let m11 = instance.scale.0 * r11;
        let m12 = instance.scale.0 * r12;
        let m13 = instance.scale.0 * r13;
        let m14 = instance.scale.0 * transform.translation().x as f32;
        let m21 = instance.scale.1 * r21;
        let m22 = instance.scale.1 * r22;
        let m23 = instance.scale.1 * r23;
        let m24 = instance.scale.1 * transform.translation().y as f32;
        let m31 = instance.scale.2 * r31;
        let m32 = instance.scale.2 * r32;
        let m33 = instance.scale.2 * r33;
        let m34 = instance.scale.2 * transform.translation().z as f32;

        let model_matrix: [[f32; 4]; 4] = [
            [m11, m21, m31, 0.0],
            [m12, m22, m32, 0.0],
            [m13, m23, m33, 0.0],
            [m14, m24, m34, 1.0],
        ];

        surface.draw(
            (&instance.polygon_model.vertices, &instance.polygon_model.normals),
            &instance.polygon_model.indices,
            &self.program,
            &uniform! {
                projection_matrix: *env.camera.projection_matrix(),
                view_matrix: env.camera.view_matrix(),
                model_matrix: model_matrix,
                light_direction: [1.0, 2.0, 1.0f32],
                surface_color: instance.color.clone(),
            },
            &glium::DrawParameters {
                depth: glium::Depth {
                    test: glium::draw_parameters::DepthTest::IfLess,
                    write: true,
                    .. Default::default()
                },
                .. Default::default()
            },
        ).unwrap();

        self.instances.insert(instance.id, instance);
    }

    fn generate_new_instance(&mut self, id: mach::ID, shape: &mach::Shape) -> Instance {
        match shape.spec() {
            mach::ShapeSpec::Cuboid(x, y, z) => {
                self.factory.generate(id, (x as f32, y as f32, z as f32), self.cube.clone())
            },

            _ => unimplemented!(),
        }
    }
}
<commit_msg>fixed failing compilation with high_precision enabled<commit_after>extern crate mach;
extern crate glium;

use std::rc::Rc;
use std::mem;
use std::collections::HashMap;

use self::glium::backend::glutin_backend::GlutinFacade;

use support::{SceneEnv, Instance, InstanceFactory, FrameMetadata, PolygonModel};
use support::polygons;

pub struct ExamplesRenderer {
    program: glium::Program,
    cube: Rc<PolygonModel>,
    instances: HashMap<mach::ID, Instance>,
    factory: InstanceFactory,
}

impl ExamplesRenderer {
    pub fn new(display: &GlutinFacade) -> Result<ExamplesRenderer, String> {
        let program = try!(
            glium::Program::from_source(
                display,
                include_str!("shaders/foreground.vert.glsl"),
                include_str!("shaders/foreground.frag.glsl"),
                None,
            ).map_err(|err| format!("{}", err))
        );

        Ok(ExamplesRenderer {
            instances: HashMap::new(),
            cube: Rc::new(polygons::initialize_cube(display)),
            program: program,
            factory: InstanceFactory::new(),
        })
    }

    pub fn render<S: glium::Surface>(&mut self, surface: &mut S, world: &mach::World, frame_metadata: &FrameMetadata, env: &SceneEnv) -> Result<(), String> {
        surface.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);

        let mut old_instances = HashMap::new();

        mem::swap(&mut old_instances, &mut self.instances);

        for body in world.rigid_bodies_iter() {
            if let Some(instance) = old_instances.remove(&body.id()) {
                self.render_and_save(surface, instance, body.transform(), env);
            } else {
                let instance = self.generate_new_instance(body.id(), body.shape());

                self.render_and_save(surface, instance, body.transform(), env);
            }
        }

        try!(self.render_contacts(surface, &frame_metadata.contacts, env));
        return Ok(());
    }

    fn render_contacts<S: glium::Surface>(&mut self, surface: &mut S, contacts: &Vec<mach::maths::Vect>, env: &SceneEnv) -> Result<(), String> {
        let mut model_matrix: [[f32; 4]; 4] = [
            [0.1, 0.0, 0.0, 0.0],
            [0.0, 0.1, 0.0, 0.0],
            [0.0, 0.0, 0.1, 0.0],
            [0.0, 0.0, 0.0, 1.0],
        ];

        for contact in contacts.iter() {
            model_matrix[3][0] = contact.x as f32;
            model_matrix[3][1] = contact.y as f32;
            model_matrix[3][2] = contact.z as f32;

            surface.draw(
                (&self.cube.vertices, &self.cube.normals),
                &self.cube.indices,
                &self.program,
                &uniform! {
                    projection_matrix: *env.camera.projection_matrix(),
                    view_matrix: env.camera.view_matrix(),
                    model_matrix: model_matrix,
                    light_direction: [1.0, 2.0, 1.0f32],
                    surface_color: [1.0, 1.0, 0.0, 1.0f32],
                },
                &glium::DrawParameters {
                    depth: glium::Depth {
                        test: glium::draw_parameters::DepthTest::Overwrite,
                        write: false,
                        .. Default::default()
                    },
                    .. Default::default()
                },
            ).unwrap();
        }

        return Ok(());
    }

    fn render_and_save<S: glium::Surface>(&mut self, surface: &mut S, instance: Instance, transform: &mach::maths::Transform, env: &SceneEnv) {
        let quat = transform.rotation().normalize();
        let r11 = 1.0 - 2.0*quat.j*quat.j - 2.0*quat.k*quat.k;
        let r12 = 2.0*quat.i*quat.j - 2.0*quat.r*quat.k;
        let r13 = 2.0*quat.i*quat.k + 2.0*quat.r*quat.j;
        let r21 = 2.0*quat.i*quat.j + 2.0*quat.r*quat.k;
        let r22 = 1.0 - 2.0*quat.i*quat.i - 2.0*quat.k*quat.k;
        let r23 = 2.0*quat.j*quat.k - 2.0*quat.r*quat.i;
        let r31 = 2.0*quat.i*quat.k - 2.0*quat.r*quat.j;
        let r32 = 2.0*quat.j*quat.k + 2.0*quat.r*quat.i;
        let r33 = 1.0 - 2.0*quat.i*quat.i - 2.0*quat.j*quat.j;

        let m11 = instance.scale.0 * r11 as f32;
        let m12 = instance.scale.0 * r12 as f32;
        let m13 = instance.scale.0 * r13 as f32;
        let m14 = instance.scale.0 * transform.translation().x as f32;
        let m21 = instance.scale.1 * r21 as f32;
        let m22 = instance.scale.1 * r22 as f32;
        let m23 = instance.scale.1 * r23 as f32;
        let m24 = instance.scale.1 * transform.translation().y as f32;
        let m31 = instance.scale.2 * r31 as f32;
        let m32 = instance.scale.2 * r32 as f32;
        let m33 = instance.scale.2 * r33 as f32;
        let m34 = instance.scale.2 * transform.translation().z as f32;

        let model_matrix: [[f32; 4]; 4] = [
            [m11, m21, m31, 0.0],
            [m12, m22, m32, 0.0],
            [m13, m23, m33, 0.0],
            [m14, m24, m34, 1.0],
        ];

        surface.draw(
            (&instance.polygon_model.vertices, &instance.polygon_model.normals),
            &instance.polygon_model.indices,
            &self.program,
            &uniform! {
                projection_matrix: *env.camera.projection_matrix(),
                view_matrix: env.camera.view_matrix(),
                model_matrix: model_matrix,
                light_direction: [1.0, 2.0, 1.0f32],
                surface_color: instance.color.clone(),
            },
            &glium::DrawParameters {
                depth: glium::Depth {
                    test: glium::draw_parameters::DepthTest::IfLess,
                    write: true,
                    .. Default::default()
                },
                .. Default::default()
            },
        ).unwrap();

        self.instances.insert(instance.id, instance);
    }

    fn generate_new_instance(&mut self, id: mach::ID, shape: &mach::Shape) -> Instance {
        match shape.spec() {
            mach::ShapeSpec::Cuboid(x, y, z) => {
                self.factory.generate(id, (x as f32, y as f32, z as f32), self.cube.clone())
            },

            _ => unimplemented!(),
        }
    }
}
<|endoftext|>


<commit_before>use crate::{
    backend::render::render_space,
    state::Fireplace,
};
use anyhow::Result;
use smithay::{
    backend::{
        input::{InputBackend, InputEvent},
        winit,
    },
    reexports::{
        calloop::{timer::Timer, EventLoop},
        wayland_server::protocol::wl_output::Subpixel,
    },
    wayland::output::{Mode, PhysicalProperties},
};
use std::{
    sync::atomic::{AtomicUsize, Ordering},
    time::Duration,
};

static WINIT_COUNTER: AtomicUsize = AtomicUsize::new(0);

pub fn init_winit(event_loop: &mut EventLoop<Fireplace>, state: &mut Fireplace) -> Result<()> {
    let (renderer, input) = match winit::init(None) {
        Ok(ret) => ret,
        Err(err) => {
            slog_scope::crit!("Failed to initialize winit backend: {}", err);
            return Err(err.into());
        }
    };

    let id = WINIT_COUNTER.fetch_add(1, Ordering::SeqCst);
    let name = format!("WINIT-{}", id);

    let size = renderer.window_size();
    let props = PhysicalProperties {
        size: (0, 0).into(),
        subpixel: Subpixel::Unknown,
        make: String::from("WINIT"),
        model: format!("{}", id),
    };
    let mode = Mode {
        size: size.physical_size,
        refresh: 60_000,
    };
    state
        .workspaces
        .borrow_mut()
        .add_output(name.clone(), props, mode);

    let timer = Timer::new()?;
    let timer_handle = timer.handle();
    let token = event_loop
        .handle()
        .insert_source(
            timer,
            move |(mut input, mut renderer): (
                winit::WinitInputBackend,
                winit::WinitGraphicsBackend,
            ),
                  handle,
                  state| {
                match input.dispatch_new_events(|event| state.process_winit_event(&name, event)) {
                    Ok(()) => {
                        let mut workspaces = state.workspaces.borrow_mut();
                        let scale = workspaces.output_by_name(&name).unwrap().scale();
                        let space = workspaces.space_by_output_name(&name).unwrap();
                        let popups = state.popups.borrow();
                        if let Err(err) = renderer
                            .render(|renderer, frame| render_space(&**space, scale, &**popups, id as u64, renderer, frame))
                            .and_then(|x| x.map_err(Into::into))
                        {
                            slog_scope::error!("Failed to render frame: {}", err);
                        };
                        space.send_frames(state.start_time.elapsed().as_millis() as u32);
                        handle.add_timeout(Duration::from_millis(16), (input, renderer));
                    }
                    Err(winit::WinitInputError::WindowClosed) => {
                        state.workspaces.borrow_mut().remove_output_by_name(&name);
                        slog_scope::debug!("Removed {}", name);
                    }
                }
            },
        )
        .map_err(|_| anyhow::anyhow!("Failed to init eventloop timer for winit"))?;
    timer_handle.add_timeout(Duration::ZERO, (input, renderer));
    state.tokens.push(token);

    Ok(())
}

impl Fireplace {
    pub fn process_winit_event<B>(&mut self, name: &str, event: InputEvent<B>)
    where
        B: InputBackend<SpecialEvent = smithay::backend::winit::WinitEvent>,
    {
        use smithay::backend::winit::WinitEvent;

        match event {
            InputEvent::Special(WinitEvent::Resized { size, .. }) => {
                let mut workspaces = self.workspaces.borrow_mut();
                if let Some(output) = workspaces.output_by_name(&name) {
                    output.set_mode(smithay::wayland::output::Mode {
                        size,
                        refresh: 60_000,
                    });
                }

                if let Some(space) = workspaces.space_by_output_name(&name) {
                    space.rearrange(&size.to_logical(1));
                };
            }
            x => self.process_input_event(x),
        }
    }
}
<commit_msg>winit: Add hardware-accelerated client support<commit_after>use crate::{
    backend::render::render_space,
    state::Fireplace,
};
use anyhow::Result;
use smithay::{
    backend::{
        input::{InputBackend, InputEvent},
        renderer::{ImportDma, ImportEgl},
        winit,
    },
    reexports::{
        calloop::{timer::Timer, EventLoop},
        wayland_server::protocol::wl_output::Subpixel,
    },
    wayland::{
        dmabuf::init_dmabuf_global,
        output::{Mode, PhysicalProperties},
    },
};
use std::{
    cell::RefCell,
    rc::Rc,
    sync::atomic::{AtomicUsize, Ordering},
    time::Duration,
};

static WINIT_COUNTER: AtomicUsize = AtomicUsize::new(0);

pub fn init_winit(event_loop: &mut EventLoop<Fireplace>, state: &mut Fireplace) -> Result<()> {
    let (renderer, input) = match winit::init(None) {
        Ok(ret) => ret,
        Err(err) => {
            slog_scope::crit!("Failed to initialize winit backend: {}", err);
            return Err(err.into());
        }
    };
    let renderer = Rc::new(RefCell::new(renderer));

    if renderer
        .borrow_mut()
        .renderer()
        .bind_wl_display(&state.display.borrow())
        .is_ok()
    {
        slog_scope::info!("EGL hardware-acceleration enabled");
        let dmabuf_formats = renderer
            .borrow_mut()
            .renderer()
            .dmabuf_formats()
            .cloned()
            .collect::<Vec<_>>();
        let renderer = renderer.clone();
        init_dmabuf_global(
            &mut *state.display.borrow_mut(),
            dmabuf_formats,
            move |buffer, _| renderer.borrow_mut().renderer().import_dmabuf(buffer).is_ok(),
            slog_scope::logger(),
        );
    };

    let id = WINIT_COUNTER.fetch_add(1, Ordering::SeqCst);
    let name = format!("WINIT-{}", id);

    let size = renderer.borrow().window_size();
    let props = PhysicalProperties {
        size: (0, 0).into(),
        subpixel: Subpixel::Unknown,
        make: String::from("WINIT"),
        model: format!("{}", id),
    };
    let mode = Mode {
        size: size.physical_size,
        refresh: 60_000,
    };
    state
        .workspaces
        .borrow_mut()
        .add_output(name.clone(), props, mode);

    let timer = Timer::new()?;
    let timer_handle = timer.handle();
    let token = event_loop
        .handle()
        .insert_source(
            timer,
            move |(mut input, renderer): (
                winit::WinitInputBackend,
                Rc<RefCell<winit::WinitGraphicsBackend>>,
            ),
            handle,
            state| {
                match input.dispatch_new_events(|event| state.process_winit_event(&name, event)) {
                    Ok(()) => {
                        let mut workspaces = state.workspaces.borrow_mut();
                        let scale = workspaces.output_by_name(&name).unwrap().scale();
                        let space = workspaces.space_by_output_name(&name).unwrap();
                        let popups = state.popups.borrow();
                        if let Err(err) = renderer
                            .borrow_mut()
                            .render(|renderer, frame| render_space(&**space, scale, &**popups, id as u64, renderer, frame))
                            .and_then(|x| x.map_err(Into::into))
                        {
                            slog_scope::error!("Failed to render frame: {}", err);
                        };
                        space.send_frames(state.start_time.elapsed().as_millis() as u32);
                        handle.add_timeout(Duration::from_millis(16), (input, renderer));
                    }
                    Err(winit::WinitInputError::WindowClosed) => {
                        state.workspaces.borrow_mut().remove_output_by_name(&name);
                        slog_scope::debug!("Removed {}", name);
                    }
                }
            },
        )
        .map_err(|_| anyhow::anyhow!("Failed to init eventloop timer for winit"))?;
    timer_handle.add_timeout(Duration::ZERO, (input, renderer));
    state.tokens.push(token);

    Ok(())
}

impl Fireplace {
    pub fn process_winit_event<B>(&mut self, name: &str, event: InputEvent<B>)
    where
        B: InputBackend<SpecialEvent = smithay::backend::winit::WinitEvent>,
    {
        use smithay::backend::winit::WinitEvent;

        match event {
            InputEvent::Special(WinitEvent::Resized { size, scale_factor }) => {
                let mut workspaces = self.workspaces.borrow_mut();
                if let Some(output) = workspaces.output_by_name(&name) {
                    output.set_mode(smithay::wayland::output::Mode {
                        size,
                        refresh: 60_000,
                    });
                }

                let _scale = scale_factor;
                if let Some(space) = workspaces.space_by_output_name(&name) {
                    space.rearrange(&size.to_logical(1));
                };
            }
            x => self.process_input_event(x),
        }
    }
}
<|endoftext|>


<commit_before>//! Intel's Restricted Transactional Memory (RTM).
//!
//! This CPU feature is available on Intel Broadwell or later CPUs (and some Haswell).
//!
//! The reference is [Intel 64 and IA-32 Architectures Software Developer's
//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref].
//!
//! [Wikipedia][wikipedia_rtm] provides a quick overview of the assembly instructions, and
//! Intel's [programming considerations][intel_consid] details what sorts of instructions within a
//! transaction are likely to cause an abort.
//!
//! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
//! [wikipedia_rtm]: https://en.wikipedia.org/wiki/Transactional_Synchronization_Extensions#Restricted_Transactional_Memory
//! [intel_consid]: https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-intel-transactional-synchronization-extensions-intel-tsx-programming-considerations

#[cfg(test)]
use stdsimd_test::assert_instr;

extern "C" {
    #[link_name = "llvm.x86.xbegin"]
    fn x86_xbegin() -> i32;
    #[link_name = "llvm.x86.xend"]
    fn x86_xend() -> ();
    #[link_name = "llvm.x86.xabort"]
    fn x86_xabort(imm8: i8) -> ();
    #[link_name = "llvm.x86.xtest"]
    fn x86_xtest() -> i32;
}

/// Transaction successfully started.
pub const _XBEGIN_STARTED: u32 = !0;

/// Transaction explicitly aborted with xabort. The parameter passed to xabort is available with
/// `_xabort_code(status)`.
pub const _XABORT_EXPLICIT: u32 = 1 << 0;

/// Transaction retry is possible.
pub const _XABORT_RETRY: u32 = 1 << 1;

/// Transaction abort due to a memory conflict with another thread.
pub const _XABORT_CONFLICT: u32 = 1 << 2;

/// Transaction abort due to the transaction using too much memory.
pub const _XABORT_CAPACITY: u32 = 1 << 3;

/// Transaction abort due to a debug trap.
pub const _XABORT_DEBUG: u32 = 1 << 4;

/// Transaction abort in a inner nested transaction.
pub const _XABORT_NESTED: u32 = 1 << 5;

/// Specifies the start of a restricted transactional memory (RTM) code region and returns a value
/// indicating status.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xbegin).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xbegin))]
pub unsafe fn _xbegin() -> u32 {
    x86_xbegin() as _
}

/// Specifies the end of a restricted transactional memory (RTM) code region.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xend).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xend))]
pub unsafe fn _xend() {
    x86_xend()
}

/// Forces a restricted transactional memory (RTM) region to abort.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xabort).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xabort))]
pub unsafe fn _xabort(imm8: u32) {
    macro_rules! call {
        ($imm8:expr) => {
            x86_xabort($imm8)
        };
    }
    constify_imm8!(imm8, call)
}

/// Queries whether the processor is executing in a transactional region identified by restricted
/// transactional memory (RTM) or hardware lock elision (HLE).
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xtest).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xtest))]
pub unsafe fn _xtest() -> u8 {
    x86_xtest() as _
}

/// Retrieves the parameter passed to [`_xabort`] when [`_xbegin`]'s status has the
/// `_XABORT_EXPLICIT` flag set.
#[inline]
pub const fn _xabort_code(status: u32) -> u32 {
    (status >> 24) & 0xFF
}

#[cfg(test)]
mod tests {
    use stdsimd_test::simd_test;

    use crate::core_arch::x86::*;

    #[simd_test(enable = "rtm")]
    unsafe fn test_xbegin_xend() {
        let mut x = 0;
        for _ in 0..10 {
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                x += 1;
                rtm::_xend();
                assert_eq!(x, 1);
                break
            }
            assert_eq!(x, 0);
        }
    }

    #[simd_test(enable = "rtm")]
    unsafe fn test_xabort() {
        const ABORT_CODE: u32 = 42;
        // aborting outside a transactional region does nothing
        _xabort(ABORT_CODE);

        for _ in 0..10 {
            let mut x = 0;
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                x += 1;
                rtm::_xabort(ABORT_CODE);
            } else if code & _XABORT_EXPLICIT != 0 {
                let test_abort_code = rtm::_xabort_code(code);
                assert_eq!(test_abort_code, ABORT_CODE);
            }
            assert_eq!(x, 0);
        }
    }

    #[simd_test(enable = "rtm")]
    unsafe fn test_xtest() {
        assert_eq!(_xtest(), 0);

        for _ in 0..10 {
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                let in_tx = _xtest();
                rtm::_xend();

                // putting the assert inside the transaction would abort the transaction on fail
                // without any output/panic/etc
                assert_eq!(in_tx, 1);
                break
            }
        }
    }
}<commit_msg>use const flags from adx feature<commit_after>//! Intel's Restricted Transactional Memory (RTM).
//!
//! This CPU feature is available on Intel Broadwell or later CPUs (and some Haswell).
//!
//! The reference is [Intel 64 and IA-32 Architectures Software Developer's
//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref].
//!
//! [Wikipedia][wikipedia_rtm] provides a quick overview of the assembly instructions, and
//! Intel's [programming considerations][intel_consid] details what sorts of instructions within a
//! transaction are likely to cause an abort.
//!
//! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
//! [wikipedia_rtm]: https://en.wikipedia.org/wiki/Transactional_Synchronization_Extensions#Restricted_Transactional_Memory
//! [intel_consid]: https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-intel-transactional-synchronization-extensions-intel-tsx-programming-considerations

#[cfg(test)]
use stdsimd_test::assert_instr;

extern "C" {
    #[link_name = "llvm.x86.xbegin"]
    fn x86_xbegin() -> i32;
    #[link_name = "llvm.x86.xend"]
    fn x86_xend() -> ();
    #[link_name = "llvm.x86.xabort"]
    fn x86_xabort(imm8: i8) -> ();
    #[link_name = "llvm.x86.xtest"]
    fn x86_xtest() -> i32;
}

/// Transaction successfully started.
pub const _XBEGIN_STARTED: u32 = !0;

/// Transaction explicitly aborted with xabort. The parameter passed to xabort is available with
/// `_xabort_code(status)`.
pub const _XABORT_EXPLICIT: u32 = 1 << 0;

/// Transaction retry is possible.
pub const _XABORT_RETRY: u32 = 1 << 1;

/// Transaction abort due to a memory conflict with another thread.
pub const _XABORT_CONFLICT: u32 = 1 << 2;

/// Transaction abort due to the transaction using too much memory.
pub const _XABORT_CAPACITY: u32 = 1 << 3;

/// Transaction abort due to a debug trap.
pub const _XABORT_DEBUG: u32 = 1 << 4;

/// Transaction abort in a inner nested transaction.
pub const _XABORT_NESTED: u32 = 1 << 5;

/// Specifies the start of a restricted transactional memory (RTM) code region and returns a value
/// indicating status.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xbegin).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xbegin))]
pub unsafe fn _xbegin() -> u32 {
    x86_xbegin() as _
}

/// Specifies the end of a restricted transactional memory (RTM) code region.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xend).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xend))]
pub unsafe fn _xend() {
    x86_xend()
}

/// Forces a restricted transactional memory (RTM) region to abort.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xabort).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xabort, imm8 = 0x0))]
#[rustc_args_required_const(0)]
pub unsafe fn _xabort(imm8: u32) {
    macro_rules! call {
        ($imm8:expr) => {
            x86_xabort($imm8)
        };
    }
    constify_imm8!(imm8, call)
}

/// Queries whether the processor is executing in a transactional region identified by restricted
/// transactional memory (RTM) or hardware lock elision (HLE).
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xtest).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xtest))]
pub unsafe fn _xtest() -> u8 {
    x86_xtest() as _
}

/// Retrieves the parameter passed to [`_xabort`] when [`_xbegin`]'s status has the
/// `_XABORT_EXPLICIT` flag set.
#[inline]
pub const fn _xabort_code(status: u32) -> u32 {
    (status >> 24) & 0xFF
}

#[cfg(test)]
mod tests {
    use stdsimd_test::simd_test;

    use crate::core_arch::x86::*;

    #[simd_test(enable = "rtm")]
    unsafe fn test_xbegin_xend() {
        let mut x = 0;
        for _ in 0..10 {
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                x += 1;
                rtm::_xend();
                assert_eq!(x, 1);
                break
            }
            assert_eq!(x, 0);
        }
    }

    #[simd_test(enable = "rtm")]
    unsafe fn test_xabort() {
        const ABORT_CODE: u32 = 42;
        // aborting outside a transactional region does nothing
        _xabort(ABORT_CODE);

        for _ in 0..10 {
            let mut x = 0;
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                x += 1;
                rtm::_xabort(ABORT_CODE);
            } else if code & _XABORT_EXPLICIT != 0 {
                let test_abort_code = rtm::_xabort_code(code);
                assert_eq!(test_abort_code, ABORT_CODE);
            }
            assert_eq!(x, 0);
        }
    }

    #[simd_test(enable = "rtm")]
    unsafe fn test_xtest() {
        assert_eq!(_xtest(), 0);

        for _ in 0..10 {
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                let in_tx = _xtest();
                rtm::_xend();

                // putting the assert inside the transaction would abort the transaction on fail
                // without any output/panic/etc
                assert_eq!(in_tx, 1);
                break
            }
        }
    }
}<|endoftext|>


<commit_before>//! `ra_hir_expand` deals with macro expansion.
//!
//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax
//! tree originates not from the text of some `FileId`, but from some macro
//! expansion.

pub mod db;
pub mod ast_id_map;
pub mod either;
pub mod name;
pub mod hygiene;
pub mod diagnostics;

use std::hash::{Hash, Hasher};
use std::sync::Arc;

use ra_db::{salsa, CrateId, FileId};
use ra_syntax::{
    ast::{self, AstNode},
    SyntaxNode, TextRange, TextUnit,
};

use crate::ast_id_map::FileAstId;

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interner).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HirFileId(HirFileIdRepr);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum HirFileIdRepr {
    FileId(FileId),
    MacroFile(MacroFile),
}

impl From<FileId> for HirFileId {
    fn from(id: FileId) -> Self {
        HirFileId(HirFileIdRepr::FileId(id))
    }
}

impl From<MacroFile> for HirFileId {
    fn from(id: MacroFile) -> Self {
        HirFileId(HirFileIdRepr::MacroFile(id))
    }
}

impl HirFileId {
    /// For macro-expansion files, returns the file original source file the
    /// expansion originated from.
    pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId {
        match self.0 {
            HirFileIdRepr::FileId(file_id) => file_id,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc = db.lookup_intern_macro(macro_file.macro_call_id);
                loc.ast_id.file_id().original_file(db)
            }
        }
    }

    /// Return expansion information if it is a macro-expansion file
    pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
        match self.0 {
            HirFileIdRepr::FileId(_) => None,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);

                let arg_start = loc.ast_id.to_node(db).token_tree()?.syntax().text_range().start();
                let def_start =
                    loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start();

                let macro_def = db.macro_def(loc.def)?;
                let shift = macro_def.0.shift();
                let exp_map = db.parse_macro(macro_file)?.1;
                let macro_arg = db.macro_arg(macro_file.macro_call_id)?;

                let arg_start = (loc.ast_id.file_id, arg_start);
                let def_start = (loc.def.ast_id.file_id, def_start);

                Some(ExpansionInfo { arg_start, def_start, macro_arg, macro_def, exp_map, shift })
            }
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroFile {
    macro_call_id: MacroCallId,
    macro_file_kind: MacroFileKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacroFileKind {
    Items,
    Expr,
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroCallId(salsa::InternId);
impl salsa::InternKey for MacroCallId {
    fn from_intern_id(v: salsa::InternId) -> Self {
        MacroCallId(v)
    }
    fn as_intern_id(&self) -> salsa::InternId {
        self.0
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId {
    pub krate: CrateId,
    pub ast_id: AstId<ast::MacroCall>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
    pub def: MacroDefId,
    pub ast_id: AstId<ast::MacroCall>,
}

impl MacroCallId {
    pub fn as_file(self, kind: MacroFileKind) -> HirFileId {
        let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
        macro_file.into()
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// ExpansionInfo mainly describes how to map text range between src and expanded macro
pub struct ExpansionInfo {
    pub(crate) arg_start: (HirFileId, TextUnit),
    pub(crate) def_start: (HirFileId, TextUnit),
    pub(crate) shift: u32,

    pub(crate) macro_def: Arc<(mbe::MacroRules, mbe::TokenMap)>,
    pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
    pub(crate) exp_map: Arc<mbe::RevTokenMap>,
}

impl ExpansionInfo {
    pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> {
        fn look_in_rev_map(exp_map: &mbe::RevTokenMap, from: TextRange) -> Option<tt::TokenId> {
            exp_map.ranges.iter().find(|&it| it.0.is_subrange(&from)).map(|it| it.1)
        }

        let token_id = look_in_rev_map(&self.exp_map, from)?;
        let (token_map, file_offset, token_id) = if token_id.0 >= self.shift {
            (&self.macro_arg.1, self.arg_start, tt::TokenId(token_id.0 - self.shift).into())
        } else {
            (&self.macro_def.1, self.def_start, token_id)
        };

        let range = token_map.relative_range_of(token_id)?;
        Some((file_offset.0, TextRange::offset_len(range.start() + file_offset.1, range.len())))
    }
}

/// `AstId` points to an AST node in any file.
///
/// It is stable across reparses, and can be used as salsa key/value.
// FIXME: isn't this just a `Source<FileAstId<N>>` ?
#[derive(Debug)]
pub struct AstId<N: AstNode> {
    file_id: HirFileId,
    file_ast_id: FileAstId<N>,
}

impl<N: AstNode> Clone for AstId<N> {
    fn clone(&self) -> AstId<N> {
        *self
    }
}
impl<N: AstNode> Copy for AstId<N> {}

impl<N: AstNode> PartialEq for AstId<N> {
    fn eq(&self, other: &Self) -> bool {
        (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
    }
}
impl<N: AstNode> Eq for AstId<N> {}
impl<N: AstNode> Hash for AstId<N> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        (self.file_id, self.file_ast_id).hash(hasher);
    }
}

impl<N: AstNode> AstId<N> {
    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
        AstId { file_id, file_ast_id }
    }

    pub fn file_id(&self) -> HirFileId {
        self.file_id
    }

    pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
        let root = db.parse_or_expand(self.file_id).unwrap();
        db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root)
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Source<T> {
    pub file_id: HirFileId,
    pub ast: T,
}

impl<T> Source<T> {
    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
        Source { file_id: self.file_id, ast: f(self.ast) }
    }
    pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
        db.parse_or_expand(self.file_id).expect("source created from invalid file")
    }
}
<commit_msg>Minor cleanup<commit_after>//! `ra_hir_expand` deals with macro expansion.
//!
//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax
//! tree originates not from the text of some `FileId`, but from some macro
//! expansion.

pub mod db;
pub mod ast_id_map;
pub mod either;
pub mod name;
pub mod hygiene;
pub mod diagnostics;

use std::hash::{Hash, Hasher};
use std::sync::Arc;

use ra_db::{salsa, CrateId, FileId};
use ra_syntax::{
    ast::{self, AstNode},
    SyntaxNode, TextRange, TextUnit,
};

use crate::ast_id_map::FileAstId;

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interner).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HirFileId(HirFileIdRepr);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum HirFileIdRepr {
    FileId(FileId),
    MacroFile(MacroFile),
}

impl From<FileId> for HirFileId {
    fn from(id: FileId) -> Self {
        HirFileId(HirFileIdRepr::FileId(id))
    }
}

impl From<MacroFile> for HirFileId {
    fn from(id: MacroFile) -> Self {
        HirFileId(HirFileIdRepr::MacroFile(id))
    }
}

impl HirFileId {
    /// For macro-expansion files, returns the file original source file the
    /// expansion originated from.
    pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId {
        match self.0 {
            HirFileIdRepr::FileId(file_id) => file_id,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc = db.lookup_intern_macro(macro_file.macro_call_id);
                loc.ast_id.file_id().original_file(db)
            }
        }
    }

    /// Return expansion information if it is a macro-expansion file
    pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
        match self.0 {
            HirFileIdRepr::FileId(_) => None,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);

                let arg_start = loc.ast_id.to_node(db).token_tree()?.syntax().text_range().start();
                let def_start =
                    loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start();

                let macro_def = db.macro_def(loc.def)?;
                let shift = macro_def.0.shift();
                let exp_map = db.parse_macro(macro_file)?.1;
                let macro_arg = db.macro_arg(macro_file.macro_call_id)?;

                let arg_start = (loc.ast_id.file_id, arg_start);
                let def_start = (loc.def.ast_id.file_id, def_start);

                Some(ExpansionInfo { arg_start, def_start, macro_arg, macro_def, exp_map, shift })
            }
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroFile {
    macro_call_id: MacroCallId,
    macro_file_kind: MacroFileKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacroFileKind {
    Items,
    Expr,
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroCallId(salsa::InternId);
impl salsa::InternKey for MacroCallId {
    fn from_intern_id(v: salsa::InternId) -> Self {
        MacroCallId(v)
    }
    fn as_intern_id(&self) -> salsa::InternId {
        self.0
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId {
    pub krate: CrateId,
    pub ast_id: AstId<ast::MacroCall>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
    pub def: MacroDefId,
    pub ast_id: AstId<ast::MacroCall>,
}

impl MacroCallId {
    pub fn as_file(self, kind: MacroFileKind) -> HirFileId {
        let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
        macro_file.into()
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// ExpansionInfo mainly describes how to map text range between src and expanded macro
pub struct ExpansionInfo {
    pub(crate) arg_start: (HirFileId, TextUnit),
    pub(crate) def_start: (HirFileId, TextUnit),
    pub(crate) shift: u32,

    pub(crate) macro_def: Arc<(mbe::MacroRules, mbe::TokenMap)>,
    pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
    pub(crate) exp_map: Arc<mbe::RevTokenMap>,
}

impl ExpansionInfo {
    pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> {
        let token_id = look_in_rev_map(&self.exp_map, from)?;

        let (token_map, (file_id, start_offset), token_id) = if token_id.0 >= self.shift {
            (&self.macro_arg.1, self.arg_start, tt::TokenId(token_id.0 - self.shift).into())
        } else {
            (&self.macro_def.1, self.def_start, token_id)
        };

        let range = token_map.relative_range_of(token_id)?;

        return Some((file_id, range + start_offset));

        fn look_in_rev_map(exp_map: &mbe::RevTokenMap, from: TextRange) -> Option<tt::TokenId> {
            exp_map.ranges.iter().find(|&it| it.0.is_subrange(&from)).map(|it| it.1)
        }
    }
}

/// `AstId` points to an AST node in any file.
///
/// It is stable across reparses, and can be used as salsa key/value.
// FIXME: isn't this just a `Source<FileAstId<N>>` ?
#[derive(Debug)]
pub struct AstId<N: AstNode> {
    file_id: HirFileId,
    file_ast_id: FileAstId<N>,
}

impl<N: AstNode> Clone for AstId<N> {
    fn clone(&self) -> AstId<N> {
        *self
    }
}
impl<N: AstNode> Copy for AstId<N> {}

impl<N: AstNode> PartialEq for AstId<N> {
    fn eq(&self, other: &Self) -> bool {
        (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
    }
}
impl<N: AstNode> Eq for AstId<N> {}
impl<N: AstNode> Hash for AstId<N> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        (self.file_id, self.file_ast_id).hash(hasher);
    }
}

impl<N: AstNode> AstId<N> {
    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
        AstId { file_id, file_ast_id }
    }

    pub fn file_id(&self) -> HirFileId {
        self.file_id
    }

    pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
        let root = db.parse_or_expand(self.file_id).unwrap();
        db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root)
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Source<T> {
    pub file_id: HirFileId,
    pub ast: T,
}

impl<T> Source<T> {
    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
        Source { file_id: self.file_id, ast: f(self.ast) }
    }
    pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
        db.parse_or_expand(self.file_id).expect("source created from invalid file")
    }
}
<|endoftext|>