<commit_before>// use std::old_io::{TcpListener, TcpStream};
// use std::old_io::{Acceptor, Listener, IoResult, MemReader};
use std::thread::sleep_ms;
use std::io::{Read, Write, Result, BufRead, BufReader, BufWriter};
use std::fs::File;

use std::net::{TcpListener, TcpStream};
use std::mem::size_of;

use std::sync::mpsc::{Sender, Receiver, channel};

use std::thread;
use std::sync::Arc;
use std::mem;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use communication::{Pushable, BinaryCommunicator, ProcessCommunicator};
use drain::DrainExt;

// TODO : Much of this only relates to BinaryWriter/BinaryReader based communication, not networking.
// TODO : Could be moved somewhere less networking-specific.

#[derive(Copy, Clone)]
pub struct MessageHeader {
    pub graph:      u64,   // graph identifier
    pub channel:    u64,   // index of channel
    pub source:     u64,   // index of worker sending message
    pub target:     u64,   // index of worker receiving message
    pub length:     u64,   // number of bytes in message
}

impl MessageHeader {
    // returns a header when there is enough supporting data
    fn try_read(bytes: &mut &[u8]) -> Option<MessageHeader> {
        if bytes.len() > size_of::<MessageHeader>() {
            // capture original in case we need to rewind
            let original = *bytes;

            // unclear what order struct initializers run in, so ...
            let graph = bytes.read_u64::<LittleEndian>().unwrap();
            let channel = bytes.read_u64::<LittleEndian>().unwrap();
            let source = bytes.read_u64::<LittleEndian>().unwrap();
            let target = bytes.read_u64::<LittleEndian>().unwrap();
            let length = bytes.read_u64::<LittleEndian>().unwrap();

            let header = MessageHeader {
                graph: graph,
                channel: channel,
                source: source,
                target: target,
                length: length,
            };

            if bytes.len() >= header.length as usize {
                Some(header)
            }
            else {
                // rewind the reader
                *bytes = original;
                None
            }
        }
        else { None }
    }

    fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
        try!(writer.write_u64::<LittleEndian>(self.graph));
        try!(writer.write_u64::<LittleEndian>(self.channel));
        try!(writer.write_u64::<LittleEndian>(self.source));
        try!(writer.write_u64::<LittleEndian>(self.target));
        try!(writer.write_u64::<LittleEndian>(self.length));
        Ok(())
    }
}

// structure in charge of receiving data from a Reader, for example the network
struct BinaryReceiver<R: Read> {
    reader:     R,          // the generic reader
    buffer:     Vec<u8>,    // current working buffer
    double:     Vec<u8>,    // second working buffer
    staging:    Vec<u8>,    // 1 << 20 of buffer to read into
    targets:    Switchboard<(Sender<Vec<u8>>, Receiver<Vec<u8>>)>,
}

impl<R: Read> BinaryReceiver<R> {
    fn new(reader: R, channels: Receiver<((u64, u64, u64), (Sender<Vec<u8>>, Receiver<Vec<u8>>))>) -> BinaryReceiver<R> {
        BinaryReceiver {

            reader:     reader,
            buffer:     Vec::new(),
            double:     Vec::new(),
            staging:    vec![0u8; 1 << 20],
            targets:    Switchboard::new(channels),
        }
    }

    fn recv_loop(&mut self) {
        loop {

            // attempt to read some more bytes into our buffer
            // TODO : We read in to self.staging because extending a Vec<u8> is hard without
            // TODO : using set_len, which is unsafe.
            let read = self.reader.read(&mut self.staging[..]).unwrap_or(0);
            // self.buffer.write_all(&self.staging[..read]).unwrap(); // <-- shouldn't fail
            //
            // {
            //     // get a view of available bytes
            //     let mut slice = &self.buffer[..];
            //
            //     while let Some(header) = MessageHeader::try_read(&mut slice) {
            //
            //         let h_len = header.length as usize;  // length in bytes
            //         let target = self.targets.ensure(header.target, header.graph, header.channel);
            //         let mut buffer = target.1.try_recv().unwrap_or(Vec::new());
            //
            //         buffer.clear();
            //         buffer.write_all(&slice[..h_len]).unwrap();
            //         slice = &slice[h_len..];
            //
            //         target.0.send(buffer).unwrap();
            //     }
            //
            //     // TODO: way inefficient... =/ Fix! :D
            //     // if slice.len() < self.buffer.len() {
            //         self.double.clear();
            //         self.double.write_all(slice).unwrap();
            //     // }
            // }
            //
            // // if self.double.len() > 0 {
            //     mem::swap(&mut self.buffer, &mut self.double);
            //     // self.double.clear();
            // // }
        }
    }
}

// structure in charge of sending data to a Writer, for example the network
struct BinarySender<W: Write> {
    id:         u64,    // destination process
    writer:     W,
    sources:    Receiver<(MessageHeader, Vec<u8>)>,
    returns:    Switchboard<Sender<Vec<u8>>>,
}

impl<W: Write> BinarySender<W> {
    fn new(id: u64,
           writer: W,
           sources: Receiver<(MessageHeader, Vec<u8>)>,
           channels: Receiver<((u64, u64, u64), Sender<Vec<u8>>)>) -> BinarySender<W> {
        BinarySender {
            id:         id,
            writer:     writer,
            sources:    sources,
            returns: Switchboard::new(channels),
        }
    }

    fn send_loop(&mut self) {
        let mut stash = Vec::new();

        let trash = vec![0u8; 1 << 20];

        loop {
            self.writer.write_all(&trash[..]);
        }

        // block until data to recv
        while let Ok((header, buffer)) = self.sources.recv() {

            stash.push((header, buffer));

            // collect any additional outstanding data to send
            while let Ok((header, buffer)) = self.sources.try_recv() {
                stash.push((header, buffer));
            }

            // println!("send loop to process {}:\tstarting", self.id);
            for (mut header, mut buffer) in stash.drain_temp() {
                header.length = buffer.len() as u64;    // <-- is this really our job? O.o
                header.write_to(&mut self.writer).unwrap();
                self.writer.write_all(&buffer[..]).unwrap();
                buffer.clear();

                // self.returns.ensure(header.source, header.graph, header.channel).send(buffer).unwrap();
            }

            self.writer.flush().unwrap();    // <-- because writer is buffered
        }
    }
}

struct Switchboard<T:Send> {
    source: Receiver<((u64, u64, u64), T)>,
    buffer: Vec<Vec<Vec<Option<T>>>>,
}

impl<T:Send> Switchboard<T> {
    pub fn new(source: Receiver<((u64, u64, u64), T)>) -> Switchboard<T> {
        Switchboard {
            source: source,
            buffer: Vec::new(),
        }
    }

    pub fn ensure(&mut self, a: u64, b: u64, c: u64) -> &mut T {
        let a = a as usize;
        let b = b as usize;
        let c = c as usize;

        while self.buffer.len() <= a { self.buffer.push(Vec::new()); }
        while self.buffer[a].len() <= b { self.buffer[a].push(Vec::new()); }
        while self.buffer[a][b].len() <= c { self.buffer[a][b].push(None); }

        while let None = self.buffer[a][b][c] {
            let ((x, y, z), s) = self.source.recv().unwrap();

            let x = x as usize;
            let y = y as usize;
            let z = z as usize;

            while self.buffer.len() <= x { self.buffer.push(Vec::new()); }
            while self.buffer[x].len() <= y { self.buffer[x].push(Vec::new()); }
            while self.buffer[x][y].len() <= z { self.buffer[x][y].push(None); }
            self.buffer[x][y][z] = Some(s);
        }

        self.buffer[a][b][c].as_mut().unwrap()
    }
}

pub fn initialize_networking_from_file(filename: &str, my_index: u64, workers: u64) -> Result<Vec<BinaryCommunicator>> {

    let reader = BufReader::new(try!(File::open(filename)));
    let mut addresses = Vec::new();

    for line in reader.lines() {
        addresses.push(try!(line));
    }

    // println!("addresses.len() : {} vs workers : {}", addresses.len(), workers);
    // assert!(addresses.len() as u64 == workers);
    initialize_networking(addresses, my_index, workers)
}

pub fn initialize_networking(addresses: Vec<String>, my_index: u64, workers: u64) -> Result<Vec<BinaryCommunicator>> {

    let processes = addresses.len() as u64;
    let hosts1 = Arc::new(addresses);
    let hosts2 = hosts1.clone();

    let start_task = thread::spawn(move || start_connections(hosts1, my_index));
    let await_task = thread::spawn(move || await_connections(hosts2, my_index));

    let mut results = try!(start_task.join().unwrap());

    results.push(None);
    let mut to_extend = try!(await_task.join().unwrap());
    results.extend(to_extend.drain_temp());

    println!("worker {}:\tinitialization complete", my_index);

    let mut writers = Vec::new();   // handles to the BinarySenders (to present new channels)
    let mut readers = Vec::new();   // handles to the BinaryReceivers (to present new channels)
    let mut senders = Vec::new();   // destinations for serialized data (to send serialized data)

    // for each process, if a stream exists (i.e. not local) ...
    for index in (0..results.len()) {
        if let Some(stream) = results[index].take() {

            let (writer_channels_s, writer_channels_r) = channel();
            let (reader_channels_s, reader_channels_r) = channel();
            let (sender_channels_s, sender_channels_r) = channel();

            writers.push(writer_channels_s);    //
            readers.push(reader_channels_s);    //
            senders.push(sender_channels_s);    //

            let mut sender = BinarySender::new(index as u64, BufWriter::with_capacity(1 << 20, stream.try_clone().unwrap()), sender_channels_r, writer_channels_r);
            let mut recver = BinaryReceiver::new(stream.try_clone().unwrap(), reader_channels_r);

            // start senders and receivers associated with this stream
            thread::Builder::new().name(format!("send thread {}", index))
                                  .spawn(move || sender.send_loop())
                                  .unwrap();
            thread::Builder::new().name(format!("recv thread {}", index))
                                  .spawn(move || recver.recv_loop())
                                  .unwrap();

        }
    }

    let proc_comms = ProcessCommunicator::new_vector(workers);

    let mut results = Vec::new();
    for (index, proc_comm) in proc_comms.into_iter().enumerate() {
        results.push(BinaryCommunicator {
            inner:          proc_comm,
            index:          my_index * workers + index as u64,
            peers:          workers * processes,
            graph:          0,          // TODO : Fix this
            allocated:      0,
            writers:        writers.clone(),
            readers:        readers.clone(),
            senders:        senders.clone(),
        });
    }

    return Ok(results);
}

// result contains connections [0, my_index - 1].
fn start_connections(addresses: Arc<Vec<String>>, my_index: u64) -> Result<Vec<Option<TcpStream>>> {
    let mut results: Vec<_> = (0..my_index).map(|_| None).collect();
    for index in (0..my_index) {
        let mut connected = false;
        while !connected {
            match TcpStream::connect(&addresses[index as usize][..]) {
                Ok(mut stream) => {
                    try!(stream.write_u64::<LittleEndian>(my_index));
                    results[index as usize] = Some(stream);
                    println!("worker {}:\tconnection to worker {}", my_index, index);
                    connected = true;
                },
                Err(error) => {
                    println!("worker {}:\terror connecting to worker {}: {}; retrying", my_index, index, error);
                    sleep_ms(1000);
                },
            }
        }
    }

    return Ok(results);
}

// result contains connections [my_index + 1, addresses.len() - 1].
fn await_connections(addresses: Arc<Vec<String>>, my_index: u64) -> Result<Vec<Option<TcpStream>>> {
    let mut results: Vec<_> = (0..(addresses.len() - my_index as usize - 1)).map(|_| None).collect();
    let listener = try!(TcpListener::bind(&addresses[my_index as usize][..]));

    for _ in (my_index as usize + 1 .. addresses.len()) {
        let mut stream = try!(listener.accept()).0;
        let identifier = try!(stream.read_u64::<LittleEndian>()) as usize;
        results[identifier - my_index as usize - 1] = Some(stream);
        println!("worker {}:\tconnection from worker {}", my_index, identifier);
    }

    return Ok(results);
}
<commit_msg>throughput test; do not use<commit_after>// use std::old_io::{TcpListener, TcpStream};
// use std::old_io::{Acceptor, Listener, IoResult, MemReader};
use std::thread::sleep_ms;
use std::io::{Read, Write, Result, BufRead, BufReader, BufWriter};
use std::fs::File;

use std::net::{TcpListener, TcpStream};
use std::mem::size_of;

use std::sync::mpsc::{Sender, Receiver, channel};

use std::thread;
use std::sync::Arc;
use std::mem;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use communication::{Pushable, BinaryCommunicator, ProcessCommunicator};
use drain::DrainExt;

// TODO : Much of this only relates to BinaryWriter/BinaryReader based communication, not networking.
// TODO : Could be moved somewhere less networking-specific.

#[derive(Copy, Clone)]
pub struct MessageHeader {
    pub graph:      u64,   // graph identifier
    pub channel:    u64,   // index of channel
    pub source:     u64,   // index of worker sending message
    pub target:     u64,   // index of worker receiving message
    pub length:     u64,   // number of bytes in message
}

impl MessageHeader {
    // returns a header when there is enough supporting data
    fn try_read(bytes: &mut &[u8]) -> Option<MessageHeader> {
        if bytes.len() > size_of::<MessageHeader>() {
            // capture original in case we need to rewind
            let original = *bytes;

            // unclear what order struct initializers run in, so ...
            let graph = bytes.read_u64::<LittleEndian>().unwrap();
            let channel = bytes.read_u64::<LittleEndian>().unwrap();
            let source = bytes.read_u64::<LittleEndian>().unwrap();
            let target = bytes.read_u64::<LittleEndian>().unwrap();
            let length = bytes.read_u64::<LittleEndian>().unwrap();

            let header = MessageHeader {
                graph: graph,
                channel: channel,
                source: source,
                target: target,
                length: length,
            };

            if bytes.len() >= header.length as usize {
                Some(header)
            }
            else {
                // rewind the reader
                *bytes = original;
                None
            }
        }
        else { None }
    }

    fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
        try!(writer.write_u64::<LittleEndian>(self.graph));
        try!(writer.write_u64::<LittleEndian>(self.channel));
        try!(writer.write_u64::<LittleEndian>(self.source));
        try!(writer.write_u64::<LittleEndian>(self.target));
        try!(writer.write_u64::<LittleEndian>(self.length));
        Ok(())
    }
}

// structure in charge of receiving data from a Reader, for example the network
struct BinaryReceiver<R: Read> {
    reader:     R,          // the generic reader
    buffer:     Vec<u8>,    // current working buffer
    double:     Vec<u8>,    // second working buffer
    staging:    Vec<u8>,    // 1 << 20 of buffer to read into
    targets:    Switchboard<(Sender<Vec<u8>>, Receiver<Vec<u8>>)>,
}

impl<R: Read> BinaryReceiver<R> {
    fn new(reader: R, channels: Receiver<((u64, u64, u64), (Sender<Vec<u8>>, Receiver<Vec<u8>>))>) -> BinaryReceiver<R> {
        BinaryReceiver {

            reader:     reader,
            buffer:     Vec::new(),
            double:     Vec::new(),
            staging:    vec![0u8; 1 << 20],
            targets:    Switchboard::new(channels),
        }
    }

    fn recv_loop(&mut self) {
        loop {

            // attempt to read some more bytes into our buffer
            // TODO : We read in to self.staging because extending a Vec<u8> is hard without
            // TODO : using set_len, which is unsafe.
            let read = self.reader.read(&mut self.staging[..]).unwrap_or(0);
            // self.buffer.write_all(&self.staging[..read]).unwrap(); // <-- shouldn't fail
            //
            // {
            //     // get a view of available bytes
            //     let mut slice = &self.buffer[..];
            //
            //     while let Some(header) = MessageHeader::try_read(&mut slice) {
            //
            //         let h_len = header.length as usize;  // length in bytes
            //         let target = self.targets.ensure(header.target, header.graph, header.channel);
            //         let mut buffer = target.1.try_recv().unwrap_or(Vec::new());
            //
            //         buffer.clear();
            //         buffer.write_all(&slice[..h_len]).unwrap();
            //         slice = &slice[h_len..];
            //
            //         target.0.send(buffer).unwrap();
            //     }
            //
            //     // TODO: way inefficient... =/ Fix! :D
            //     // if slice.len() < self.buffer.len() {
            //         self.double.clear();
            //         self.double.write_all(slice).unwrap();
            //     // }
            // }
            //
            // // if self.double.len() > 0 {
            //     mem::swap(&mut self.buffer, &mut self.double);
            //     // self.double.clear();
            // // }
        }
    }
}

// structure in charge of sending data to a Writer, for example the network
struct BinarySender<W: Write> {
    id:         u64,    // destination process
    writer:     W,
    sources:    Receiver<(MessageHeader, Vec<u8>)>,
    returns:    Switchboard<Sender<Vec<u8>>>,
}

impl<W: Write> BinarySender<W> {
    fn new(id: u64,
           writer: W,
           sources: Receiver<(MessageHeader, Vec<u8>)>,
           channels: Receiver<((u64, u64, u64), Sender<Vec<u8>>)>) -> BinarySender<W> {
        BinarySender {
            id:         id,
            writer:     writer,
            sources:    sources,
            returns: Switchboard::new(channels),
        }
    }

    fn send_loop(&mut self) {
        let mut stash = Vec::new();

        let trash1 = vec![0u8; 40];
        let trash2 = vec![0u8; 1 << 20];

        loop {
            self.writer.write_all(&trash1[..]);
            self.writer.write_all(&trash2[..]);
        }

        // block until data to recv
        while let Ok((header, buffer)) = self.sources.recv() {

            stash.push((header, buffer));

            // collect any additional outstanding data to send
            while let Ok((header, buffer)) = self.sources.try_recv() {
                stash.push((header, buffer));
            }

            // println!("send loop to process {}:\tstarting", self.id);
            for (mut header, mut buffer) in stash.drain_temp() {
                header.length = buffer.len() as u64;    // <-- is this really our job? O.o
                header.write_to(&mut self.writer).unwrap();
                self.writer.write_all(&buffer[..]).unwrap();
                buffer.clear();

                // self.returns.ensure(header.source, header.graph, header.channel).send(buffer).unwrap();
            }

            self.writer.flush().unwrap();    // <-- because writer is buffered
        }
    }
}

struct Switchboard<T:Send> {
    source: Receiver<((u64, u64, u64), T)>,
    buffer: Vec<Vec<Vec<Option<T>>>>,
}

impl<T:Send> Switchboard<T> {
    pub fn new(source: Receiver<((u64, u64, u64), T)>) -> Switchboard<T> {
        Switchboard {
            source: source,
            buffer: Vec::new(),
        }
    }

    pub fn ensure(&mut self, a: u64, b: u64, c: u64) -> &mut T {
        let a = a as usize;
        let b = b as usize;
        let c = c as usize;

        while self.buffer.len() <= a { self.buffer.push(Vec::new()); }
        while self.buffer[a].len() <= b { self.buffer[a].push(Vec::new()); }
        while self.buffer[a][b].len() <= c { self.buffer[a][b].push(None); }

        while let None = self.buffer[a][b][c] {
            let ((x, y, z), s) = self.source.recv().unwrap();

            let x = x as usize;
            let y = y as usize;
            let z = z as usize;

            while self.buffer.len() <= x { self.buffer.push(Vec::new()); }
            while self.buffer[x].len() <= y { self.buffer[x].push(Vec::new()); }
            while self.buffer[x][y].len() <= z { self.buffer[x][y].push(None); }
            self.buffer[x][y][z] = Some(s);
        }

        self.buffer[a][b][c].as_mut().unwrap()
    }
}

pub fn initialize_networking_from_file(filename: &str, my_index: u64, workers: u64) -> Result<Vec<BinaryCommunicator>> {

    let reader = BufReader::new(try!(File::open(filename)));
    let mut addresses = Vec::new();

    for line in reader.lines() {
        addresses.push(try!(line));
    }

    // println!("addresses.len() : {} vs workers : {}", addresses.len(), workers);
    // assert!(addresses.len() as u64 == workers);
    initialize_networking(addresses, my_index, workers)
}

pub fn initialize_networking(addresses: Vec<String>, my_index: u64, workers: u64) -> Result<Vec<BinaryCommunicator>> {

    let processes = addresses.len() as u64;
    let hosts1 = Arc::new(addresses);
    let hosts2 = hosts1.clone();

    let start_task = thread::spawn(move || start_connections(hosts1, my_index));
    let await_task = thread::spawn(move || await_connections(hosts2, my_index));

    let mut results = try!(start_task.join().unwrap());

    results.push(None);
    let mut to_extend = try!(await_task.join().unwrap());
    results.extend(to_extend.drain_temp());

    println!("worker {}:\tinitialization complete", my_index);

    let mut writers = Vec::new();   // handles to the BinarySenders (to present new channels)
    let mut readers = Vec::new();   // handles to the BinaryReceivers (to present new channels)
    let mut senders = Vec::new();   // destinations for serialized data (to send serialized data)

    // for each process, if a stream exists (i.e. not local) ...
    for index in (0..results.len()) {
        if let Some(stream) = results[index].take() {

            let (writer_channels_s, writer_channels_r) = channel();
            let (reader_channels_s, reader_channels_r) = channel();
            let (sender_channels_s, sender_channels_r) = channel();

            writers.push(writer_channels_s);    //
            readers.push(reader_channels_s);    //
            senders.push(sender_channels_s);    //

            let mut sender = BinarySender::new(index as u64, BufWriter::with_capacity(1 << 20, stream.try_clone().unwrap()), sender_channels_r, writer_channels_r);
            let mut recver = BinaryReceiver::new(stream.try_clone().unwrap(), reader_channels_r);

            // start senders and receivers associated with this stream
            thread::Builder::new().name(format!("send thread {}", index))
                                  .spawn(move || sender.send_loop())
                                  .unwrap();
            thread::Builder::new().name(format!("recv thread {}", index))
                                  .spawn(move || recver.recv_loop())
                                  .unwrap();

        }
    }

    let proc_comms = ProcessCommunicator::new_vector(workers);

    let mut results = Vec::new();
    for (index, proc_comm) in proc_comms.into_iter().enumerate() {
        results.push(BinaryCommunicator {
            inner:          proc_comm,
            index:          my_index * workers + index as u64,
            peers:          workers * processes,
            graph:          0,          // TODO : Fix this
            allocated:      0,
            writers:        writers.clone(),
            readers:        readers.clone(),
            senders:        senders.clone(),
        });
    }

    return Ok(results);
}

// result contains connections [0, my_index - 1].
fn start_connections(addresses: Arc<Vec<String>>, my_index: u64) -> Result<Vec<Option<TcpStream>>> {
    let mut results: Vec<_> = (0..my_index).map(|_| None).collect();
    for index in (0..my_index) {
        let mut connected = false;
        while !connected {
            match TcpStream::connect(&addresses[index as usize][..]) {
                Ok(mut stream) => {
                    try!(stream.write_u64::<LittleEndian>(my_index));
                    results[index as usize] = Some(stream);
                    println!("worker {}:\tconnection to worker {}", my_index, index);
                    connected = true;
                },
                Err(error) => {
                    println!("worker {}:\terror connecting to worker {}: {}; retrying", my_index, index, error);
                    sleep_ms(1000);
                },
            }
        }
    }

    return Ok(results);
}

// result contains connections [my_index + 1, addresses.len() - 1].
fn await_connections(addresses: Arc<Vec<String>>, my_index: u64) -> Result<Vec<Option<TcpStream>>> {
    let mut results: Vec<_> = (0..(addresses.len() - my_index as usize - 1)).map(|_| None).collect();
    let listener = try!(TcpListener::bind(&addresses[my_index as usize][..]));

    for _ in (my_index as usize + 1 .. addresses.len()) {
        let mut stream = try!(listener.accept()).0;
        let identifier = try!(stream.read_u64::<LittleEndian>()) as usize;
        results[identifier - my_index as usize - 1] = Some(stream);
        println!("worker {}:\tconnection from worker {}", my_index, identifier);
    }

    return Ok(results);
}
<|endoftext|>


<commit_before>use std::fmt::Debug;

use async_trait::async_trait;
use bytes::Bytes;
use http::{Request, Response};
use opentelemetry::{
    propagation::{Extractor, Injector},
    trace::TraceError,
};

pub struct HeaderInjector<'a>(pub &'a mut http::HeaderMap);

impl<'a> Injector for HeaderInjector<'a> {
    /// Set a key and value in the HeaderMap.  Does nothing if the key or value are not valid inputs.
    fn set(&mut self, key: &str, value: String) {
        if let Ok(name) = http::header::HeaderName::from_bytes(key.as_bytes()) {
            if let Ok(val) = http::header::HeaderValue::from_str(&value) {
                self.0.insert(name, val);
            }
        }
    }
}

pub struct HeaderExtractor<'a>(pub &'a http::HeaderMap);

impl<'a> Extractor for HeaderExtractor<'a> {
    /// Get a value for a key from the HeaderMap.  If the value is not valid ASCII, returns None.
    fn get(&self, key: &str) -> Option<&str> {
        self.0.get(key).and_then(|value| value.to_str().ok())
    }

    /// Collect all the keys from the HeaderMap.
    fn keys(&self) -> Vec<&str> {
        self.0
            .keys()
            .map(|value| value.as_str())
            .collect::<Vec<_>>()
    }
}

pub type HttpError = Box<dyn std::error::Error + Send + Sync + 'static>;

/// A minimal interface necessary for export spans over HTTP.
///
/// Users sometime choose HTTP clients that relay on a certain async runtime. This trait allows
/// users to bring their choice of HTTP client.
#[async_trait]
pub trait HttpClient: Debug + Send + Sync {
    /// Send the specified HTTP request
    ///
    /// Returns the HTTP response including the status code and body.
    ///
    /// Returns an error if it can't connect to the server or the request could not be completed,
    /// e.g. because of a timeout, infinite redirects, or a loss of connection.
    async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError>;
}

#[cfg(feature = "reqwest")]
mod reqwest {
    use super::{async_trait, Bytes, HttpClient, HttpError, Request, Response};
    use std::convert::TryInto;

    #[async_trait]
    impl HttpClient for reqwest::Client {
        async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError> {
            let request = request.try_into()?;
            let response = self.execute(request).await?;
            Ok(Response::builder()
                .status(response.status())
                .body(response.bytes().await?)?)
        }
    }

    #[async_trait]
    impl HttpClient for reqwest::blocking::Client {
        async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError> {
            let request = request.try_into()?;
            let response = self.execute(request)?;
            Ok(Response::builder()
                .status(response.status())
                .body(response.bytes()?)?)
        }
    }
}

#[cfg(feature = "surf")]
mod surf {
    use super::{async_trait, Bytes, HttpClient, HttpError, Request, Response};

    #[async_trait]
    impl HttpClient for surf::Client {
        async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError> {
            let (parts, body) = request.into_parts();
            let method = parts.method.as_str().parse()?;
            let uri = parts.uri.to_string().parse()?;

            let mut request_builder = surf::Request::builder(method, uri).body(body);
            let mut prev_name = None;
            for (new_name, value) in parts.headers.into_iter() {
                let name = new_name.or(prev_name).expect("the first time new_name should be set and from then on we always have a prev_name");
                request_builder = request_builder.header(name.as_str(), value.to_str()?);
                prev_name = Some(name);
            }

            let mut response = self.send(request_builder).await?;
            Ok(Response::builder()
                .status(response.status() as u16)
                .body(response.body_bytes().await?.into())?)
        }
    }
}

#[cfg(feature = "isahc")]
mod isahc {
    use super::{async_trait, Bytes, HttpClient, HttpError, Request, Response};
    use isahc::AsyncReadResponseExt;
    use std::convert::TryInto as _;

    #[async_trait]
    impl HttpClient for isahc::HttpClient {
        async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError> {
            let mut response = self.send_async(request).await?;
            let mut bytes = Vec::with_capacity(response.body().len().unwrap_or(0).try_into()?);
            response.copy_to(&mut bytes).await?;
            Ok(Response::builder()
                .status(response.status())
                .body(bytes.into())?)
        }
    }
}

/// Methods to make working with responses from the [`HttpClient`] trait easier.
pub trait ResponseExt: Sized {
    /// Turn a response into an error if the HTTP status does not indicate success (200 - 299).
    fn error_for_status(self) -> Result<Self, TraceError>;
}

impl<T> ResponseExt for Response<T> {
    fn error_for_status(self) -> Result<Self, TraceError> {
        if self.status().is_success() {
            Ok(self)
        } else {
            Err(format!("request failed with status {}", self.status()).into())
        }
    }
}

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

    #[test]
    fn http_headers_get() {
        let mut carrier = http::HeaderMap::new();
        HeaderInjector(&mut carrier).set("headerName", "value".to_string());

        assert_eq!(
            HeaderExtractor(&carrier).get("HEADERNAME"),
            Some("value"),
            "case insensitive extraction"
        )
    }

    #[test]
    fn http_headers_keys() {
        let mut carrier = http::HeaderMap::new();
        HeaderInjector(&mut carrier).set("headerName1", "value1".to_string());
        HeaderInjector(&mut carrier).set("headerName2", "value2".to_string());

        let extractor = HeaderExtractor(&carrier);
        let got = extractor.keys();
        assert_eq!(got.len(), 2);
        assert!(got.contains(&"headername1"));
        assert!(got.contains(&"headername2"));
    }
}
<commit_msg>style(http): re-export types in trait. (#798)<commit_after>use std::fmt::Debug;

#[doc(no_inline)]
pub use bytes::Bytes;
#[doc(no_inline)]
pub use http::{Request, Response};

use async_trait::async_trait;
use opentelemetry::{
    propagation::{Extractor, Injector},
    trace::TraceError,
};

pub struct HeaderInjector<'a>(pub &'a mut http::HeaderMap);

impl<'a> Injector for HeaderInjector<'a> {
    /// Set a key and value in the HeaderMap.  Does nothing if the key or value are not valid inputs.
    fn set(&mut self, key: &str, value: String) {
        if let Ok(name) = http::header::HeaderName::from_bytes(key.as_bytes()) {
            if let Ok(val) = http::header::HeaderValue::from_str(&value) {
                self.0.insert(name, val);
            }
        }
    }
}

pub struct HeaderExtractor<'a>(pub &'a http::HeaderMap);

impl<'a> Extractor for HeaderExtractor<'a> {
    /// Get a value for a key from the HeaderMap.  If the value is not valid ASCII, returns None.
    fn get(&self, key: &str) -> Option<&str> {
        self.0.get(key).and_then(|value| value.to_str().ok())
    }

    /// Collect all the keys from the HeaderMap.
    fn keys(&self) -> Vec<&str> {
        self.0
            .keys()
            .map(|value| value.as_str())
            .collect::<Vec<_>>()
    }
}

pub type HttpError = Box<dyn std::error::Error + Send + Sync + 'static>;

/// A minimal interface necessary for export spans over HTTP.
///
/// Users sometime choose HTTP clients that relay on a certain async runtime. This trait allows
/// users to bring their choice of HTTP client.
#[async_trait]
pub trait HttpClient: Debug + Send + Sync {
    /// Send the specified HTTP request
    ///
    /// Returns the HTTP response including the status code and body.
    ///
    /// Returns an error if it can't connect to the server or the request could not be completed,
    /// e.g. because of a timeout, infinite redirects, or a loss of connection.
    async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError>;
}

#[cfg(feature = "reqwest")]
mod reqwest {
    use super::{async_trait, Bytes, HttpClient, HttpError, Request, Response};
    use std::convert::TryInto;

    #[async_trait]
    impl HttpClient for reqwest::Client {
        async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError> {
            let request = request.try_into()?;
            let response = self.execute(request).await?;
            Ok(Response::builder()
                .status(response.status())
                .body(response.bytes().await?)?)
        }
    }

    #[async_trait]
    impl HttpClient for reqwest::blocking::Client {
        async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError> {
            let request = request.try_into()?;
            let response = self.execute(request)?;
            Ok(Response::builder()
                .status(response.status())
                .body(response.bytes()?)?)
        }
    }
}

#[cfg(feature = "surf")]
mod surf {
    use super::{async_trait, Bytes, HttpClient, HttpError, Request, Response};

    #[async_trait]
    impl HttpClient for surf::Client {
        async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError> {
            let (parts, body) = request.into_parts();
            let method = parts.method.as_str().parse()?;
            let uri = parts.uri.to_string().parse()?;

            let mut request_builder = surf::Request::builder(method, uri).body(body);
            let mut prev_name = None;
            for (new_name, value) in parts.headers.into_iter() {
                let name = new_name.or(prev_name).expect("the first time new_name should be set and from then on we always have a prev_name");
                request_builder = request_builder.header(name.as_str(), value.to_str()?);
                prev_name = Some(name);
            }

            let mut response = self.send(request_builder).await?;
            Ok(Response::builder()
                .status(response.status() as u16)
                .body(response.body_bytes().await?.into())?)
        }
    }
}

#[cfg(feature = "isahc")]
mod isahc {
    use super::{async_trait, Bytes, HttpClient, HttpError, Request, Response};
    use isahc::AsyncReadResponseExt;
    use std::convert::TryInto as _;

    #[async_trait]
    impl HttpClient for isahc::HttpClient {
        async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError> {
            let mut response = self.send_async(request).await?;
            let mut bytes = Vec::with_capacity(response.body().len().unwrap_or(0).try_into()?);
            response.copy_to(&mut bytes).await?;
            Ok(Response::builder()
                .status(response.status())
                .body(bytes.into())?)
        }
    }
}

/// Methods to make working with responses from the [`HttpClient`] trait easier.
pub trait ResponseExt: Sized {
    /// Turn a response into an error if the HTTP status does not indicate success (200 - 299).
    fn error_for_status(self) -> Result<Self, TraceError>;
}

impl<T> ResponseExt for Response<T> {
    fn error_for_status(self) -> Result<Self, TraceError> {
        if self.status().is_success() {
            Ok(self)
        } else {
            Err(format!("request failed with status {}", self.status()).into())
        }
    }
}

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

    #[test]
    fn http_headers_get() {
        let mut carrier = http::HeaderMap::new();
        HeaderInjector(&mut carrier).set("headerName", "value".to_string());

        assert_eq!(
            HeaderExtractor(&carrier).get("HEADERNAME"),
            Some("value"),
            "case insensitive extraction"
        )
    }

    #[test]
    fn http_headers_keys() {
        let mut carrier = http::HeaderMap::new();
        HeaderInjector(&mut carrier).set("headerName1", "value1".to_string());
        HeaderInjector(&mut carrier).set("headerName2", "value2".to_string());

        let extractor = HeaderExtractor(&carrier);
        let got = extractor.keys();
        assert_eq!(got.len(), 2);
        assert!(got.contains(&"headername1"));
        assert!(got.contains(&"headername2"));
    }
}
<|endoftext|>


<commit_before>use crate::gen::block::Block;
use crate::gen::ifndef;
use crate::gen::out::{Content, OutFile};

#[derive(Default, PartialEq)]
pub struct Builtins<'a> {
    pub panic: bool,
    pub rust_string: bool,
    pub rust_str: bool,
    pub rust_slice: bool,
    pub rust_box: bool,
    pub rust_vec: bool,
    pub rust_fn: bool,
    pub rust_isize: bool,
    pub opaque: bool,
    pub layout: bool,
    pub unsafe_bitcopy: bool,
    pub unsafe_bitcopy_t: bool,
    pub rust_error: bool,
    pub manually_drop: bool,
    pub maybe_uninit: bool,
    pub trycatch: bool,
    pub ptr_len: bool,
    pub repr_fat: bool,
    pub rust_str_new_unchecked: bool,
    pub rust_str_repr: bool,
    pub rust_slice_new: bool,
    pub rust_slice_repr: bool,
    pub exception: bool,
    pub relocatable: bool,
    pub relocatable_or_array: bool,
    pub friend_impl: bool,
    pub is_complete: bool,
    pub destroy: bool,
    pub deleter_if: bool,
    pub content: Content<'a>,
}

impl<'a> Builtins<'a> {
    pub fn new() -> Self {
        Builtins::default()
    }
}

pub(super) fn write(out: &mut OutFile) {
    if out.builtin == Default::default() {
        return;
    }

    let include = &mut out.include;
    let builtin = &mut out.builtin;
    let out = &mut builtin.content;

    if builtin.rust_string {
        include.array = true;
        include.cstdint = true;
        include.string = true;
    }

    if builtin.rust_str {
        include.array = true;
        include.cstdint = true;
        include.string = true;
        builtin.friend_impl = true;
    }

    if builtin.rust_vec {
        include.algorithm = true;
        include.array = true;
        include.cassert = true;
        include.cstddef = true;
        include.cstdint = true;
        include.initializer_list = true;
        include.iterator = true;
        include.new = true;
        include.stdexcept = true;
        include.type_traits = true;
        include.utility = true;
        builtin.panic = true;
        builtin.rust_slice = true;
        builtin.unsafe_bitcopy_t = true;
    }

    if builtin.rust_slice {
        include.array = true;
        include.cassert = true;
        include.cstddef = true;
        include.cstdint = true;
        include.iterator = true;
        include.stdexcept = true;
        include.type_traits = true;
        builtin.friend_impl = true;
        builtin.layout = true;
        builtin.panic = true;
    }

    if builtin.rust_box {
        include.new = true;
        include.type_traits = true;
        include.utility = true;
    }

    if builtin.rust_fn {
        include.utility = true;
    }

    if builtin.rust_error {
        include.exception = true;
        builtin.friend_impl = true;
    }

    if builtin.rust_isize {
        include.basetsd = true;
        include.sys_types = true;
    }

    if builtin.relocatable_or_array {
        include.cstddef = true;
        builtin.relocatable = true;
    }

    if builtin.relocatable {
        include.type_traits = true;
    }

    if builtin.layout {
        include.type_traits = true;
        include.cstddef = true;
        builtin.is_complete = true;
    }

    if builtin.is_complete {
        include.cstddef = true;
        include.type_traits = true;
    }

    if builtin.unsafe_bitcopy {
        builtin.unsafe_bitcopy_t = true;
    }

    out.begin_block(Block::Namespace("rust"));
    out.begin_block(Block::InlineNamespace("cxxbridge1"));

    let cxx_header = include.has_cxx_header();
    if !cxx_header {
        writeln!(out, "// #include \"rust/cxx.h\"");

        ifndef::write(out, builtin.panic, "CXXBRIDGE1_PANIC");

        if builtin.rust_string {
            out.next_section();
            writeln!(out, "struct unsafe_bitcopy_t;");
        }

        if builtin.friend_impl {
            out.begin_block(Block::AnonymousNamespace);
            writeln!(out, "template <typename T>");
            writeln!(out, "class impl;");
            out.end_block(Block::AnonymousNamespace);
        }

        out.next_section();
        if builtin.rust_str && !builtin.rust_string {
            writeln!(out, "class String;");
        }
        if builtin.layout && !builtin.opaque {
            writeln!(out, "class Opaque;");
        }

        if builtin.rust_slice {
            out.next_section();
            writeln!(out, "template <typename T>");
            writeln!(out, "::std::size_t size_of();");
            writeln!(out, "template <typename T>");
            writeln!(out, "::std::size_t align_of();");
        }

        ifndef::write(out, builtin.rust_string, "CXXBRIDGE1_RUST_STRING");
        ifndef::write(out, builtin.rust_str, "CXXBRIDGE1_RUST_STR");
        ifndef::write(out, builtin.rust_slice, "CXXBRIDGE1_RUST_SLICE");
        ifndef::write(out, builtin.rust_box, "CXXBRIDGE1_RUST_BOX");
        ifndef::write(out, builtin.unsafe_bitcopy_t, "CXXBRIDGE1_RUST_BITCOPY_T");
        ifndef::write(out, builtin.unsafe_bitcopy, "CXXBRIDGE1_RUST_BITCOPY");
        ifndef::write(out, builtin.rust_vec, "CXXBRIDGE1_RUST_VEC");
        ifndef::write(out, builtin.rust_fn, "CXXBRIDGE1_RUST_FN");
        ifndef::write(out, builtin.rust_error, "CXXBRIDGE1_RUST_ERROR");
        ifndef::write(out, builtin.rust_isize, "CXXBRIDGE1_RUST_ISIZE");
        ifndef::write(out, builtin.opaque, "CXXBRIDGE1_RUST_OPAQUE");
        ifndef::write(out, builtin.is_complete, "CXXBRIDGE1_IS_COMPLETE");
        ifndef::write(out, builtin.layout, "CXXBRIDGE1_LAYOUT");
        ifndef::write(out, builtin.relocatable, "CXXBRIDGE1_RELOCATABLE");
    }

    if builtin.rust_str_new_unchecked {
        out.next_section();
        writeln!(out, "class Str::uninit {{}};");
        writeln!(out, "inline Str::Str(uninit) noexcept {{}}");
    }

    if builtin.rust_slice_new {
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(out, "class Slice<T>::uninit {{}};");
        writeln!(out, "template <typename T>");
        writeln!(out, "inline Slice<T>::Slice(uninit) noexcept {{}}");
    }

    out.begin_block(Block::Namespace("repr"));

    if builtin.repr_fat {
        include.array = true;
        include.cstdint = true;
        out.next_section();
        writeln!(out, "using Fat = ::std::array<::std::uintptr_t, 2>;");
    }

    if builtin.ptr_len {
        include.cstddef = true;
        out.next_section();
        writeln!(out, "struct PtrLen final {{");
        writeln!(out, "  void *ptr;");
        writeln!(out, "  ::std::size_t len;");
        writeln!(out, "}};");
    }

    out.end_block(Block::Namespace("repr"));

    out.begin_block(Block::Namespace("detail"));

    if builtin.maybe_uninit {
        include.cstddef = true;
        include.new = true;
        out.next_section();
        writeln!(out, "template <typename T, typename = void *>");
        writeln!(out, "struct operator_new {{");
        writeln!(
            out,
            "  void *operator()(::std::size_t sz) {{ return ::operator new(sz); }}",
        );
        writeln!(out, "}};");
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(
            out,
            "struct operator_new<T, decltype(T::operator new(sizeof(T)))> {{",
        );
        writeln!(
            out,
            "  void *operator()(::std::size_t sz) {{ return T::operator new(sz); }}",
        );
        writeln!(out, "}};");
    }

    out.end_block(Block::Namespace("detail"));

    if builtin.manually_drop {
        out.next_section();
        include.utility = true;
        writeln!(out, "template <typename T>");
        writeln!(out, "union ManuallyDrop {{");
        writeln!(out, "  T value;");
        writeln!(
            out,
            "  ManuallyDrop(T &&value) : value(::std::move(value)) {{}}",
        );
        writeln!(out, "  ~ManuallyDrop() {{}}");
        writeln!(out, "}};");
    }

    if builtin.maybe_uninit {
        include.cstddef = true;
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(out, "union MaybeUninit {{");
        writeln!(out, "  T value;");
        writeln!(
            out,
            "  void *operator new(::std::size_t sz) {{ return detail::operator_new<T>{{}}(sz); }}",
        );
        writeln!(out, "  MaybeUninit() {{}}");
        writeln!(out, "  ~MaybeUninit() {{}}");
        writeln!(out, "}};");
    }

    out.begin_block(Block::AnonymousNamespace);

    if builtin.rust_str_new_unchecked || builtin.rust_str_repr {
        out.next_section();
        writeln!(out, "template <>");
        writeln!(out, "class impl<Str> final {{");
        writeln!(out, "public:");
        if builtin.rust_str_new_unchecked {
            writeln!(
                out,
                "  static Str new_unchecked(repr::Fat repr) noexcept {{",
            );
            writeln!(out, "    Str str = Str::uninit{{}};");
            writeln!(out, "    str.repr = repr;");
            writeln!(out, "    return str;");
            writeln!(out, "  }}");
        }
        if builtin.rust_str_repr {
            writeln!(out, "  static repr::Fat repr(Str str) noexcept {{");
            writeln!(out, "    return str.repr;");
            writeln!(out, "  }}");
        }
        writeln!(out, "}};");
    }

    if builtin.rust_slice_new || builtin.rust_slice_repr {
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(out, "class impl<Slice<T>> final {{");
        writeln!(out, "public:");
        if builtin.rust_slice_new {
            writeln!(out, "  static Slice<T> slice(repr::Fat repr) noexcept {{");
            writeln!(out, "    Slice<T> slice = typename Slice<T>::uninit{{}};");
            writeln!(out, "    slice.repr = repr;");
            writeln!(out, "    return slice;");
            writeln!(out, "  }}");
        }
        if builtin.rust_slice_repr {
            writeln!(out, "  static repr::Fat repr(Slice<T> slice) noexcept {{");
            writeln!(out, "    return slice.repr;");
            writeln!(out, "  }}");
        }
        writeln!(out, "}};");
    }

    if builtin.rust_error {
        out.next_section();
        writeln!(out, "template <>");
        writeln!(out, "class impl<Error> final {{");
        writeln!(out, "public:");
        writeln!(out, "  static Error error(repr::PtrLen repr) noexcept {{");
        writeln!(out, "    Error error;");
        writeln!(out, "    error.msg = static_cast<const char *>(repr.ptr);");
        writeln!(out, "    error.len = repr.len;");
        writeln!(out, "    return error;");
        writeln!(out, "  }}");
        writeln!(out, "}};");
    }

    if builtin.destroy {
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(out, "void destroy(T *ptr) {{");
        writeln!(out, "  ptr->~T();");
        writeln!(out, "}}");
    }

    if builtin.deleter_if {
        out.next_section();
        writeln!(out, "template <bool> struct deleter_if {{");
        writeln!(out, "  template <typename T> void operator()(T *) {{}}");
        writeln!(out, "}};");
        out.next_section();
        writeln!(out, "template <> struct deleter_if<true> {{");
        writeln!(
            out,
            "  template <typename T> void operator()(T *ptr) {{ ptr->~T(); }}",
        );
        writeln!(out, "}};");
    }

    if builtin.relocatable_or_array {
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(out, "struct IsRelocatableOrArray : IsRelocatable<T> {{}};");
        writeln!(out, "template <typename T, ::std::size_t N>");
        writeln!(
            out,
            "struct IsRelocatableOrArray<T[N]> : IsRelocatableOrArray<T> {{}};",
        );
    }

    out.end_block(Block::AnonymousNamespace);
    out.end_block(Block::InlineNamespace("cxxbridge1"));

    if builtin.trycatch {
        out.begin_block(Block::Namespace("behavior"));
        include.exception = true;
        include.type_traits = true;
        include.utility = true;
        writeln!(out, "class missing {{}};");
        writeln!(out, "missing trycatch(...);");
        writeln!(out);
        writeln!(out, "template <typename Try, typename Fail>");
        writeln!(out, "static typename ::std::enable_if<");
        writeln!(
            out,
            "    ::std::is_same<decltype(trycatch(::std::declval<Try>(), ::std::declval<Fail>())),",
        );
        writeln!(out, "                 missing>::value>::type");
        writeln!(out, "trycatch(Try &&func, Fail &&fail) noexcept try {{");
        writeln!(out, "  func();");
        writeln!(out, "}} catch (const ::std::exception &e) {{");
        writeln!(out, "  fail(e.what());");
        writeln!(out, "}}");
        out.end_block(Block::Namespace("behavior"));
    }

    out.end_block(Block::Namespace("rust"));

    if builtin.exception {
        include.cstddef = true;
        out.begin_block(Block::ExternC);
        writeln!(
            out,
            "const char *cxxbridge1$exception(const char *, ::std::size_t);",
        );
        out.end_block(Block::ExternC);
    }
}
<commit_msg>Mark cxxbridge1$exception noexcept<commit_after>use crate::gen::block::Block;
use crate::gen::ifndef;
use crate::gen::out::{Content, OutFile};

#[derive(Default, PartialEq)]
pub struct Builtins<'a> {
    pub panic: bool,
    pub rust_string: bool,
    pub rust_str: bool,
    pub rust_slice: bool,
    pub rust_box: bool,
    pub rust_vec: bool,
    pub rust_fn: bool,
    pub rust_isize: bool,
    pub opaque: bool,
    pub layout: bool,
    pub unsafe_bitcopy: bool,
    pub unsafe_bitcopy_t: bool,
    pub rust_error: bool,
    pub manually_drop: bool,
    pub maybe_uninit: bool,
    pub trycatch: bool,
    pub ptr_len: bool,
    pub repr_fat: bool,
    pub rust_str_new_unchecked: bool,
    pub rust_str_repr: bool,
    pub rust_slice_new: bool,
    pub rust_slice_repr: bool,
    pub exception: bool,
    pub relocatable: bool,
    pub relocatable_or_array: bool,
    pub friend_impl: bool,
    pub is_complete: bool,
    pub destroy: bool,
    pub deleter_if: bool,
    pub content: Content<'a>,
}

impl<'a> Builtins<'a> {
    pub fn new() -> Self {
        Builtins::default()
    }
}

pub(super) fn write(out: &mut OutFile) {
    if out.builtin == Default::default() {
        return;
    }

    let include = &mut out.include;
    let builtin = &mut out.builtin;
    let out = &mut builtin.content;

    if builtin.rust_string {
        include.array = true;
        include.cstdint = true;
        include.string = true;
    }

    if builtin.rust_str {
        include.array = true;
        include.cstdint = true;
        include.string = true;
        builtin.friend_impl = true;
    }

    if builtin.rust_vec {
        include.algorithm = true;
        include.array = true;
        include.cassert = true;
        include.cstddef = true;
        include.cstdint = true;
        include.initializer_list = true;
        include.iterator = true;
        include.new = true;
        include.stdexcept = true;
        include.type_traits = true;
        include.utility = true;
        builtin.panic = true;
        builtin.rust_slice = true;
        builtin.unsafe_bitcopy_t = true;
    }

    if builtin.rust_slice {
        include.array = true;
        include.cassert = true;
        include.cstddef = true;
        include.cstdint = true;
        include.iterator = true;
        include.stdexcept = true;
        include.type_traits = true;
        builtin.friend_impl = true;
        builtin.layout = true;
        builtin.panic = true;
    }

    if builtin.rust_box {
        include.new = true;
        include.type_traits = true;
        include.utility = true;
    }

    if builtin.rust_fn {
        include.utility = true;
    }

    if builtin.rust_error {
        include.exception = true;
        builtin.friend_impl = true;
    }

    if builtin.rust_isize {
        include.basetsd = true;
        include.sys_types = true;
    }

    if builtin.relocatable_or_array {
        include.cstddef = true;
        builtin.relocatable = true;
    }

    if builtin.relocatable {
        include.type_traits = true;
    }

    if builtin.layout {
        include.type_traits = true;
        include.cstddef = true;
        builtin.is_complete = true;
    }

    if builtin.is_complete {
        include.cstddef = true;
        include.type_traits = true;
    }

    if builtin.unsafe_bitcopy {
        builtin.unsafe_bitcopy_t = true;
    }

    out.begin_block(Block::Namespace("rust"));
    out.begin_block(Block::InlineNamespace("cxxbridge1"));

    let cxx_header = include.has_cxx_header();
    if !cxx_header {
        writeln!(out, "// #include \"rust/cxx.h\"");

        ifndef::write(out, builtin.panic, "CXXBRIDGE1_PANIC");

        if builtin.rust_string {
            out.next_section();
            writeln!(out, "struct unsafe_bitcopy_t;");
        }

        if builtin.friend_impl {
            out.begin_block(Block::AnonymousNamespace);
            writeln!(out, "template <typename T>");
            writeln!(out, "class impl;");
            out.end_block(Block::AnonymousNamespace);
        }

        out.next_section();
        if builtin.rust_str && !builtin.rust_string {
            writeln!(out, "class String;");
        }
        if builtin.layout && !builtin.opaque {
            writeln!(out, "class Opaque;");
        }

        if builtin.rust_slice {
            out.next_section();
            writeln!(out, "template <typename T>");
            writeln!(out, "::std::size_t size_of();");
            writeln!(out, "template <typename T>");
            writeln!(out, "::std::size_t align_of();");
        }

        ifndef::write(out, builtin.rust_string, "CXXBRIDGE1_RUST_STRING");
        ifndef::write(out, builtin.rust_str, "CXXBRIDGE1_RUST_STR");
        ifndef::write(out, builtin.rust_slice, "CXXBRIDGE1_RUST_SLICE");
        ifndef::write(out, builtin.rust_box, "CXXBRIDGE1_RUST_BOX");
        ifndef::write(out, builtin.unsafe_bitcopy_t, "CXXBRIDGE1_RUST_BITCOPY_T");
        ifndef::write(out, builtin.unsafe_bitcopy, "CXXBRIDGE1_RUST_BITCOPY");
        ifndef::write(out, builtin.rust_vec, "CXXBRIDGE1_RUST_VEC");
        ifndef::write(out, builtin.rust_fn, "CXXBRIDGE1_RUST_FN");
        ifndef::write(out, builtin.rust_error, "CXXBRIDGE1_RUST_ERROR");
        ifndef::write(out, builtin.rust_isize, "CXXBRIDGE1_RUST_ISIZE");
        ifndef::write(out, builtin.opaque, "CXXBRIDGE1_RUST_OPAQUE");
        ifndef::write(out, builtin.is_complete, "CXXBRIDGE1_IS_COMPLETE");
        ifndef::write(out, builtin.layout, "CXXBRIDGE1_LAYOUT");
        ifndef::write(out, builtin.relocatable, "CXXBRIDGE1_RELOCATABLE");
    }

    if builtin.rust_str_new_unchecked {
        out.next_section();
        writeln!(out, "class Str::uninit {{}};");
        writeln!(out, "inline Str::Str(uninit) noexcept {{}}");
    }

    if builtin.rust_slice_new {
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(out, "class Slice<T>::uninit {{}};");
        writeln!(out, "template <typename T>");
        writeln!(out, "inline Slice<T>::Slice(uninit) noexcept {{}}");
    }

    out.begin_block(Block::Namespace("repr"));

    if builtin.repr_fat {
        include.array = true;
        include.cstdint = true;
        out.next_section();
        writeln!(out, "using Fat = ::std::array<::std::uintptr_t, 2>;");
    }

    if builtin.ptr_len {
        include.cstddef = true;
        out.next_section();
        writeln!(out, "struct PtrLen final {{");
        writeln!(out, "  void *ptr;");
        writeln!(out, "  ::std::size_t len;");
        writeln!(out, "}};");
    }

    out.end_block(Block::Namespace("repr"));

    out.begin_block(Block::Namespace("detail"));

    if builtin.maybe_uninit {
        include.cstddef = true;
        include.new = true;
        out.next_section();
        writeln!(out, "template <typename T, typename = void *>");
        writeln!(out, "struct operator_new {{");
        writeln!(
            out,
            "  void *operator()(::std::size_t sz) {{ return ::operator new(sz); }}",
        );
        writeln!(out, "}};");
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(
            out,
            "struct operator_new<T, decltype(T::operator new(sizeof(T)))> {{",
        );
        writeln!(
            out,
            "  void *operator()(::std::size_t sz) {{ return T::operator new(sz); }}",
        );
        writeln!(out, "}};");
    }

    out.end_block(Block::Namespace("detail"));

    if builtin.manually_drop {
        out.next_section();
        include.utility = true;
        writeln!(out, "template <typename T>");
        writeln!(out, "union ManuallyDrop {{");
        writeln!(out, "  T value;");
        writeln!(
            out,
            "  ManuallyDrop(T &&value) : value(::std::move(value)) {{}}",
        );
        writeln!(out, "  ~ManuallyDrop() {{}}");
        writeln!(out, "}};");
    }

    if builtin.maybe_uninit {
        include.cstddef = true;
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(out, "union MaybeUninit {{");
        writeln!(out, "  T value;");
        writeln!(
            out,
            "  void *operator new(::std::size_t sz) {{ return detail::operator_new<T>{{}}(sz); }}",
        );
        writeln!(out, "  MaybeUninit() {{}}");
        writeln!(out, "  ~MaybeUninit() {{}}");
        writeln!(out, "}};");
    }

    out.begin_block(Block::AnonymousNamespace);

    if builtin.rust_str_new_unchecked || builtin.rust_str_repr {
        out.next_section();
        writeln!(out, "template <>");
        writeln!(out, "class impl<Str> final {{");
        writeln!(out, "public:");
        if builtin.rust_str_new_unchecked {
            writeln!(
                out,
                "  static Str new_unchecked(repr::Fat repr) noexcept {{",
            );
            writeln!(out, "    Str str = Str::uninit{{}};");
            writeln!(out, "    str.repr = repr;");
            writeln!(out, "    return str;");
            writeln!(out, "  }}");
        }
        if builtin.rust_str_repr {
            writeln!(out, "  static repr::Fat repr(Str str) noexcept {{");
            writeln!(out, "    return str.repr;");
            writeln!(out, "  }}");
        }
        writeln!(out, "}};");
    }

    if builtin.rust_slice_new || builtin.rust_slice_repr {
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(out, "class impl<Slice<T>> final {{");
        writeln!(out, "public:");
        if builtin.rust_slice_new {
            writeln!(out, "  static Slice<T> slice(repr::Fat repr) noexcept {{");
            writeln!(out, "    Slice<T> slice = typename Slice<T>::uninit{{}};");
            writeln!(out, "    slice.repr = repr;");
            writeln!(out, "    return slice;");
            writeln!(out, "  }}");
        }
        if builtin.rust_slice_repr {
            writeln!(out, "  static repr::Fat repr(Slice<T> slice) noexcept {{");
            writeln!(out, "    return slice.repr;");
            writeln!(out, "  }}");
        }
        writeln!(out, "}};");
    }

    if builtin.rust_error {
        out.next_section();
        writeln!(out, "template <>");
        writeln!(out, "class impl<Error> final {{");
        writeln!(out, "public:");
        writeln!(out, "  static Error error(repr::PtrLen repr) noexcept {{");
        writeln!(out, "    Error error;");
        writeln!(out, "    error.msg = static_cast<const char *>(repr.ptr);");
        writeln!(out, "    error.len = repr.len;");
        writeln!(out, "    return error;");
        writeln!(out, "  }}");
        writeln!(out, "}};");
    }

    if builtin.destroy {
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(out, "void destroy(T *ptr) {{");
        writeln!(out, "  ptr->~T();");
        writeln!(out, "}}");
    }

    if builtin.deleter_if {
        out.next_section();
        writeln!(out, "template <bool> struct deleter_if {{");
        writeln!(out, "  template <typename T> void operator()(T *) {{}}");
        writeln!(out, "}};");
        out.next_section();
        writeln!(out, "template <> struct deleter_if<true> {{");
        writeln!(
            out,
            "  template <typename T> void operator()(T *ptr) {{ ptr->~T(); }}",
        );
        writeln!(out, "}};");
    }

    if builtin.relocatable_or_array {
        out.next_section();
        writeln!(out, "template <typename T>");
        writeln!(out, "struct IsRelocatableOrArray : IsRelocatable<T> {{}};");
        writeln!(out, "template <typename T, ::std::size_t N>");
        writeln!(
            out,
            "struct IsRelocatableOrArray<T[N]> : IsRelocatableOrArray<T> {{}};",
        );
    }

    out.end_block(Block::AnonymousNamespace);
    out.end_block(Block::InlineNamespace("cxxbridge1"));

    if builtin.trycatch {
        out.begin_block(Block::Namespace("behavior"));
        include.exception = true;
        include.type_traits = true;
        include.utility = true;
        writeln!(out, "class missing {{}};");
        writeln!(out, "missing trycatch(...);");
        writeln!(out);
        writeln!(out, "template <typename Try, typename Fail>");
        writeln!(out, "static typename ::std::enable_if<");
        writeln!(
            out,
            "    ::std::is_same<decltype(trycatch(::std::declval<Try>(), ::std::declval<Fail>())),",
        );
        writeln!(out, "                 missing>::value>::type");
        writeln!(out, "trycatch(Try &&func, Fail &&fail) noexcept try {{");
        writeln!(out, "  func();");
        writeln!(out, "}} catch (const ::std::exception &e) {{");
        writeln!(out, "  fail(e.what());");
        writeln!(out, "}}");
        out.end_block(Block::Namespace("behavior"));
    }

    out.end_block(Block::Namespace("rust"));

    if builtin.exception {
        include.cstddef = true;
        out.begin_block(Block::ExternC);
        writeln!(
            out,
            "const char *cxxbridge1$exception(const char *, ::std::size_t) noexcept;",
        );
        out.end_block(Block::ExternC);
    }
}
<|endoftext|>


<commit_before>//! Error types.

use std::error::{self, Error};
use std::fmt;

use cssparser::{BasicParseError, BasicParseErrorKind, ParseErrorKind, ToCss};
use markup5ever::QualName;

use crate::allowed_url::Fragment;
use crate::node::RsvgNode;

/// A short-lived error.
///
/// The lifetime of the error is the same as the `cssparser::ParserInput` that
/// was used to create a `cssparser::Parser`.  That is, it is the lifetime of
/// the string data that is being parsed.
///
/// The code flow will sometimes require preserving this error as a long-lived struct;
/// see the `impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>>` for that
/// purpose.
pub type ParseError<'i> = cssparser::ParseError<'i, ValueErrorKind>;

/// A simple error which refers to an attribute's value
#[derive(Debug, Clone, PartialEq)]
pub enum ValueErrorKind {
    /// A property with the specified name was not found
    UnknownProperty,

    /// The value could not be parsed
    Parse(String),

    // The value could be parsed, but is invalid
    Value(String),
}

impl ValueErrorKind {
    pub fn parse_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Parse(s.to_string())
    }

    pub fn value_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Value(s.to_string())
    }
}

impl fmt::Display for ValueErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ValueErrorKind::UnknownProperty => write!(f, "unknown property name"),

            ValueErrorKind::Parse(ref s) => write!(f, "parse error: {}", s),

            ValueErrorKind::Value(ref s) => write!(f, "invalid value: {}", s),
        }
    }
}

impl<'a> From<BasicParseError<'a>> for ValueErrorKind {
    fn from(e: BasicParseError<'_>) -> ValueErrorKind {
        let BasicParseError { kind, location: _ } = e;

        let msg = match kind {
            BasicParseErrorKind::UnexpectedToken(_) => "unexpected token",
            BasicParseErrorKind::EndOfInput => "unexpected end of input",
            BasicParseErrorKind::AtRuleInvalid(_) => "invalid @-rule",
            BasicParseErrorKind::AtRuleBodyInvalid => "invalid @-rule body",
            BasicParseErrorKind::QualifiedRuleInvalid => "invalid qualified rule",
        };

        ValueErrorKind::parse_error(msg)
    }
}

/// A complete error for an attribute and its erroneous value
#[derive(Debug, Clone, PartialEq)]
pub struct NodeError {
    pub attr: QualName,
    pub err: ValueErrorKind,
}

impl error::Error for NodeError {
    fn description(&self) -> &str {
        match self.err {
            ValueErrorKind::UnknownProperty => "unknown property",
            ValueErrorKind::Parse(_) => "parse error",
            ValueErrorKind::Value(_) => "invalid attribute value",
        }
    }
}

impl fmt::Display for NodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}: {}", self.attr.expanded(), self.err)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum DefsLookupErrorKind {
    HrefError(HrefError),
    CannotLookupExternalReferences,
    NotFound,
}

#[derive(Debug, Clone, PartialEq)]
pub enum RenderingError {
    Cairo(cairo::Status),
    CircularReference,
    InstancingLimit,
    InvalidId(DefsLookupErrorKind),
    InvalidHref,
    OutOfMemory,
    HandleIsNotLoaded,
}

impl From<cairo::Status> for RenderingError {
    fn from(e: cairo::Status) -> RenderingError {
        assert!(e != cairo::Status::Success);

        RenderingError::Cairo(e)
    }
}

pub enum AcquireError {
    LinkNotFound(Fragment),
    InvalidLinkType(Fragment),
    CircularReference(RsvgNode),
    MaxReferencesExceeded,
}

impl fmt::Display for AcquireError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            AcquireError::LinkNotFound(ref frag) => write!(f, "link not found: {}", frag),

            AcquireError::InvalidLinkType(ref frag) => {
                write!(f, "link {} is to object of invalid type", frag)
            }

            AcquireError::CircularReference(ref node) => {
                write!(f, "circular reference in node {}", node)
            }

            AcquireError::MaxReferencesExceeded => {
                write!(f, "maximum number of references exceeded")
            }
        }
    }
}

/// Helper for converting `Result<O, E>` into `Result<O, NodeError>`
///
/// A `NodeError` requires a `QualName` that corresponds to the attribute to which the
/// error refers, plus the actual `ValueErrorKind` that describes the error.  However,
/// parsing functions for attribute value types will want to return their own kind of
/// error, instead of `ValueErrorKind`.  If that particular error type has an `impl
/// From<FooError> for ValueErrorKind`, then this trait helps assign attribute values in
/// `set_atts()` methods as follows:
///
/// ```ignore
/// use error::AttributeResultExt;
///
/// // fn parse_foo(...) -> Result<Foo, FooError>
///
/// // It is assumed that there is an impl From<FooError> for ValueErrorKind
///
/// self.foo = parse_foo(value).attribute(local_name!("foo"))?;
/// ```
///
/// The call to `.attribute(attr)` converts the `Result` from `parse_foo()` into a full
/// `NodeError` with the provided `attr`.
pub trait AttributeResultExt<O> {
    fn attribute(self, attr: QualName) -> Result<O, NodeError>;
}

impl<O, E: Into<ValueErrorKind>> AttributeResultExt<O> for Result<O, E> {
    fn attribute(self, attr: QualName) -> Result<O, NodeError> {
        self.map_err(|e| e.into())
            .map_err(|err| NodeError { attr, err })
    }
}

/// Turns a short-lived `ParseError` into a long-lived `NodeError`
impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>> {
    fn attribute(self, attr: QualName) -> Result<O, NodeError> {
        self.map_err(|e| {
            // FIXME: eventually, here we'll want to preserve the location information

            let ParseError {
                kind,
                location: _location,
            } = e;

            match kind {
                ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(tok)) => {
                    let mut s = String::from("unexpected token '");
                    tok.to_css(&mut s).unwrap(); // FIXME: what do we do with a fmt::Error?
                    s.push_str("'");

                    NodeError {
                        attr,
                        err: ValueErrorKind::Parse(s),
                    }
                }

                ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput) => NodeError {
                    attr,
                    err: ValueErrorKind::parse_error("unexpected end of input"),
                },

                ParseErrorKind::Basic(_) => {
                    unreachable!("attribute parsers should not return errors for CSS rules")
                }

                ParseErrorKind::Custom(err) => NodeError { attr, err },
            }
        })
    }
}

/// Errors returned when creating an `Href` out of a string
#[derive(Debug, Clone, PartialEq)]
pub enum HrefError {
    /// The href is an invalid URI or has empty components.
    ParseError,

    /// A fragment identifier ("`#foo`") is not allowed here
    ///
    /// For example, the SVG `<image>` element only allows referencing
    /// resources without fragment identifiers like
    /// `xlink:href="foo.png"`.
    FragmentForbidden,

    /// A fragment identifier ("`#foo`") was required but not found.  For example,
    /// the SVG `<use>` element requires one, as in `<use xlink:href="foo.svg#bar">`.
    FragmentRequired,
}

impl From<HrefError> for ValueErrorKind {
    fn from(e: HrefError) -> ValueErrorKind {
        match e {
            HrefError::ParseError => ValueErrorKind::parse_error("url parse error"),
            HrefError::FragmentForbidden => {
                ValueErrorKind::value_error("fragment identifier not allowed")
            }
            HrefError::FragmentRequired => {
                ValueErrorKind::value_error("fragment identifier required")
            }
        }
    }
}

#[derive(Debug, Clone)]
pub enum LoadingError {
    NoDataPassedToParser,
    XmlParseError(String),
    // Could not parse data: URL
    CouldNotCreateXmlParser,
    BadUrl,
    BadDataUrl,
    BadStylesheet,
    BadCss,
    Cairo(cairo::Status),
    EmptyData,
    SvgHasNoElements,
    RootElementIsNotSvg,
    Glib(glib::Error),
    Unknown,
}

impl error::Error for LoadingError {
    fn description(&self) -> &str {
        match *self {
            LoadingError::NoDataPassedToParser => "no data passed to parser",
            LoadingError::CouldNotCreateXmlParser => "could not create XML parser",
            LoadingError::XmlParseError(_) => "XML parse error",
            LoadingError::BadUrl => "invalid URL",
            LoadingError::BadDataUrl => "invalid data: URL",
            LoadingError::BadStylesheet => "invalid stylesheet",
            LoadingError::BadCss => "invalid CSS",
            LoadingError::Cairo(_) => "cairo error",
            LoadingError::EmptyData => "empty data",
            LoadingError::SvgHasNoElements => "SVG has no elements",
            LoadingError::RootElementIsNotSvg => "root element is not <svg>",
            LoadingError::Glib(ref e) => e.description(),
            LoadingError::Unknown => "unknown error",
        }
    }
}

impl fmt::Display for LoadingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            LoadingError::Cairo(status) => write!(f, "cairo error: {:?}", status),
            LoadingError::XmlParseError(ref s) => write!(f, "XML parse error: {}", s),
            LoadingError::NoDataPassedToParser
            | LoadingError::CouldNotCreateXmlParser
            | LoadingError::BadUrl
            | LoadingError::BadDataUrl
            | LoadingError::BadStylesheet
            | LoadingError::BadCss
            | LoadingError::EmptyData
            | LoadingError::SvgHasNoElements
            | LoadingError::RootElementIsNotSvg
            | LoadingError::Glib(_)
            | LoadingError::Unknown => write!(f, "{}", self.description()),
        }
    }
}

impl error::Error for RenderingError {
    fn description(&self) -> &str {
        match *self {
            RenderingError::Cairo(_) => "cairo error",
            RenderingError::CircularReference => "circular reference",
            RenderingError::InstancingLimit => "instancing limit",
            RenderingError::InvalidId(_) => "invalid id",
            RenderingError::InvalidHref => "invalid href",
            RenderingError::OutOfMemory => "out of memory",
            RenderingError::HandleIsNotLoaded => "SVG data is not loaded into handle",
        }
    }
}

impl fmt::Display for RenderingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            RenderingError::Cairo(ref status) => write!(f, "cairo error: {:?}", status),
            RenderingError::InvalidId(ref id) => write!(f, "invalid id: {:?}", id),
            RenderingError::CircularReference
            | RenderingError::InstancingLimit
            | RenderingError::InvalidHref
            | RenderingError::OutOfMemory
            | RenderingError::HandleIsNotLoaded => write!(f, "{}", self.description()),
        }
    }
}

impl From<cairo::Status> for LoadingError {
    fn from(e: cairo::Status) -> LoadingError {
        assert!(e != cairo::Status::Success);

        LoadingError::Cairo(e)
    }
}

impl From<glib::Error> for LoadingError {
    fn from(e: glib::Error) -> LoadingError {
        LoadingError::Glib(e)
    }
}
<commit_msg>Avoid structure field patterns bound to wildcards<commit_after>//! Error types.

use std::error::{self, Error};
use std::fmt;

use cssparser::{BasicParseError, BasicParseErrorKind, ParseErrorKind, ToCss};
use markup5ever::QualName;

use crate::allowed_url::Fragment;
use crate::node::RsvgNode;

/// A short-lived error.
///
/// The lifetime of the error is the same as the `cssparser::ParserInput` that
/// was used to create a `cssparser::Parser`.  That is, it is the lifetime of
/// the string data that is being parsed.
///
/// The code flow will sometimes require preserving this error as a long-lived struct;
/// see the `impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>>` for that
/// purpose.
pub type ParseError<'i> = cssparser::ParseError<'i, ValueErrorKind>;

/// A simple error which refers to an attribute's value
#[derive(Debug, Clone, PartialEq)]
pub enum ValueErrorKind {
    /// A property with the specified name was not found
    UnknownProperty,

    /// The value could not be parsed
    Parse(String),

    // The value could be parsed, but is invalid
    Value(String),
}

impl ValueErrorKind {
    pub fn parse_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Parse(s.to_string())
    }

    pub fn value_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Value(s.to_string())
    }
}

impl fmt::Display for ValueErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ValueErrorKind::UnknownProperty => write!(f, "unknown property name"),

            ValueErrorKind::Parse(ref s) => write!(f, "parse error: {}", s),

            ValueErrorKind::Value(ref s) => write!(f, "invalid value: {}", s),
        }
    }
}

impl<'a> From<BasicParseError<'a>> for ValueErrorKind {
    fn from(e: BasicParseError<'_>) -> ValueErrorKind {
        let BasicParseError { kind, .. } = e;

        let msg = match kind {
            BasicParseErrorKind::UnexpectedToken(_) => "unexpected token",
            BasicParseErrorKind::EndOfInput => "unexpected end of input",
            BasicParseErrorKind::AtRuleInvalid(_) => "invalid @-rule",
            BasicParseErrorKind::AtRuleBodyInvalid => "invalid @-rule body",
            BasicParseErrorKind::QualifiedRuleInvalid => "invalid qualified rule",
        };

        ValueErrorKind::parse_error(msg)
    }
}

/// A complete error for an attribute and its erroneous value
#[derive(Debug, Clone, PartialEq)]
pub struct NodeError {
    pub attr: QualName,
    pub err: ValueErrorKind,
}

impl error::Error for NodeError {
    fn description(&self) -> &str {
        match self.err {
            ValueErrorKind::UnknownProperty => "unknown property",
            ValueErrorKind::Parse(_) => "parse error",
            ValueErrorKind::Value(_) => "invalid attribute value",
        }
    }
}

impl fmt::Display for NodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}: {}", self.attr.expanded(), self.err)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum DefsLookupErrorKind {
    HrefError(HrefError),
    CannotLookupExternalReferences,
    NotFound,
}

#[derive(Debug, Clone, PartialEq)]
pub enum RenderingError {
    Cairo(cairo::Status),
    CircularReference,
    InstancingLimit,
    InvalidId(DefsLookupErrorKind),
    InvalidHref,
    OutOfMemory,
    HandleIsNotLoaded,
}

impl From<cairo::Status> for RenderingError {
    fn from(e: cairo::Status) -> RenderingError {
        assert!(e != cairo::Status::Success);

        RenderingError::Cairo(e)
    }
}

pub enum AcquireError {
    LinkNotFound(Fragment),
    InvalidLinkType(Fragment),
    CircularReference(RsvgNode),
    MaxReferencesExceeded,
}

impl fmt::Display for AcquireError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            AcquireError::LinkNotFound(ref frag) => write!(f, "link not found: {}", frag),

            AcquireError::InvalidLinkType(ref frag) => {
                write!(f, "link {} is to object of invalid type", frag)
            }

            AcquireError::CircularReference(ref node) => {
                write!(f, "circular reference in node {}", node)
            }

            AcquireError::MaxReferencesExceeded => {
                write!(f, "maximum number of references exceeded")
            }
        }
    }
}

/// Helper for converting `Result<O, E>` into `Result<O, NodeError>`
///
/// A `NodeError` requires a `QualName` that corresponds to the attribute to which the
/// error refers, plus the actual `ValueErrorKind` that describes the error.  However,
/// parsing functions for attribute value types will want to return their own kind of
/// error, instead of `ValueErrorKind`.  If that particular error type has an `impl
/// From<FooError> for ValueErrorKind`, then this trait helps assign attribute values in
/// `set_atts()` methods as follows:
///
/// ```ignore
/// use error::AttributeResultExt;
///
/// // fn parse_foo(...) -> Result<Foo, FooError>
///
/// // It is assumed that there is an impl From<FooError> for ValueErrorKind
///
/// self.foo = parse_foo(value).attribute(local_name!("foo"))?;
/// ```
///
/// The call to `.attribute(attr)` converts the `Result` from `parse_foo()` into a full
/// `NodeError` with the provided `attr`.
pub trait AttributeResultExt<O> {
    fn attribute(self, attr: QualName) -> Result<O, NodeError>;
}

impl<O, E: Into<ValueErrorKind>> AttributeResultExt<O> for Result<O, E> {
    fn attribute(self, attr: QualName) -> Result<O, NodeError> {
        self.map_err(|e| e.into())
            .map_err(|err| NodeError { attr, err })
    }
}

/// Turns a short-lived `ParseError` into a long-lived `NodeError`
impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>> {
    fn attribute(self, attr: QualName) -> Result<O, NodeError> {
        self.map_err(|e| {
            // FIXME: eventually, here we'll want to preserve the location information

            let ParseError {
                kind,
                location: _location,
            } = e;

            match kind {
                ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(tok)) => {
                    let mut s = String::from("unexpected token '");
                    tok.to_css(&mut s).unwrap(); // FIXME: what do we do with a fmt::Error?
                    s.push_str("'");

                    NodeError {
                        attr,
                        err: ValueErrorKind::Parse(s),
                    }
                }

                ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput) => NodeError {
                    attr,
                    err: ValueErrorKind::parse_error("unexpected end of input"),
                },

                ParseErrorKind::Basic(_) => {
                    unreachable!("attribute parsers should not return errors for CSS rules")
                }

                ParseErrorKind::Custom(err) => NodeError { attr, err },
            }
        })
    }
}

/// Errors returned when creating an `Href` out of a string
#[derive(Debug, Clone, PartialEq)]
pub enum HrefError {
    /// The href is an invalid URI or has empty components.
    ParseError,

    /// A fragment identifier ("`#foo`") is not allowed here
    ///
    /// For example, the SVG `<image>` element only allows referencing
    /// resources without fragment identifiers like
    /// `xlink:href="foo.png"`.
    FragmentForbidden,

    /// A fragment identifier ("`#foo`") was required but not found.  For example,
    /// the SVG `<use>` element requires one, as in `<use xlink:href="foo.svg#bar">`.
    FragmentRequired,
}

impl From<HrefError> for ValueErrorKind {
    fn from(e: HrefError) -> ValueErrorKind {
        match e {
            HrefError::ParseError => ValueErrorKind::parse_error("url parse error"),
            HrefError::FragmentForbidden => {
                ValueErrorKind::value_error("fragment identifier not allowed")
            }
            HrefError::FragmentRequired => {
                ValueErrorKind::value_error("fragment identifier required")
            }
        }
    }
}

#[derive(Debug, Clone)]
pub enum LoadingError {
    NoDataPassedToParser,
    XmlParseError(String),
    // Could not parse data: URL
    CouldNotCreateXmlParser,
    BadUrl,
    BadDataUrl,
    BadStylesheet,
    BadCss,
    Cairo(cairo::Status),
    EmptyData,
    SvgHasNoElements,
    RootElementIsNotSvg,
    Glib(glib::Error),
    Unknown,
}

impl error::Error for LoadingError {
    fn description(&self) -> &str {
        match *self {
            LoadingError::NoDataPassedToParser => "no data passed to parser",
            LoadingError::CouldNotCreateXmlParser => "could not create XML parser",
            LoadingError::XmlParseError(_) => "XML parse error",
            LoadingError::BadUrl => "invalid URL",
            LoadingError::BadDataUrl => "invalid data: URL",
            LoadingError::BadStylesheet => "invalid stylesheet",
            LoadingError::BadCss => "invalid CSS",
            LoadingError::Cairo(_) => "cairo error",
            LoadingError::EmptyData => "empty data",
            LoadingError::SvgHasNoElements => "SVG has no elements",
            LoadingError::RootElementIsNotSvg => "root element is not <svg>",
            LoadingError::Glib(ref e) => e.description(),
            LoadingError::Unknown => "unknown error",
        }
    }
}

impl fmt::Display for LoadingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            LoadingError::Cairo(status) => write!(f, "cairo error: {:?}", status),
            LoadingError::XmlParseError(ref s) => write!(f, "XML parse error: {}", s),
            LoadingError::NoDataPassedToParser
            | LoadingError::CouldNotCreateXmlParser
            | LoadingError::BadUrl
            | LoadingError::BadDataUrl
            | LoadingError::BadStylesheet
            | LoadingError::BadCss
            | LoadingError::EmptyData
            | LoadingError::SvgHasNoElements
            | LoadingError::RootElementIsNotSvg
            | LoadingError::Glib(_)
            | LoadingError::Unknown => write!(f, "{}", self.description()),
        }
    }
}

impl error::Error for RenderingError {
    fn description(&self) -> &str {
        match *self {
            RenderingError::Cairo(_) => "cairo error",
            RenderingError::CircularReference => "circular reference",
            RenderingError::InstancingLimit => "instancing limit",
            RenderingError::InvalidId(_) => "invalid id",
            RenderingError::InvalidHref => "invalid href",
            RenderingError::OutOfMemory => "out of memory",
            RenderingError::HandleIsNotLoaded => "SVG data is not loaded into handle",
        }
    }
}

impl fmt::Display for RenderingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            RenderingError::Cairo(ref status) => write!(f, "cairo error: {:?}", status),
            RenderingError::InvalidId(ref id) => write!(f, "invalid id: {:?}", id),
            RenderingError::CircularReference
            | RenderingError::InstancingLimit
            | RenderingError::InvalidHref
            | RenderingError::OutOfMemory
            | RenderingError::HandleIsNotLoaded => write!(f, "{}", self.description()),
        }
    }
}

impl From<cairo::Status> for LoadingError {
    fn from(e: cairo::Status) -> LoadingError {
        assert!(e != cairo::Status::Success);

        LoadingError::Cairo(e)
    }
}

impl From<glib::Error> for LoadingError {
    fn from(e: glib::Error) -> LoadingError {
        LoadingError::Glib(e)
    }
}
<|endoftext|>


<commit_before>enum Token {
    Mine,
    Empty,
}

impl Token {
    fn from(c: char) -> Result<Token, ()> {
        match c {
            '*' => Ok(Token::Mine),
            ' ' => Ok(Token::Empty),
            _ => Err(()),
        }
    }
}

struct Board {
    field: Vec<Vec<char>>,
}

// Board tokens
const MINE: char = '*';
const EMPTY: char = ' ';

impl Board {
    fn new(minefield: &[&str]) -> Self {
        let mut field: Vec<Vec<char>> = Vec::new();

        for row in minefield {
            field.push(row.chars().collect());
        }
        Board { field }
    }

    fn annotated(&self) -> Vec<String> {
        let mut annotated: Vec<String> = Vec::new();

        for (y, row) in self.field.iter().enumerate() {
            let mut annotated_row = String::new();
            for (x, token) in row.iter().enumerate() {
                match token {
                    &MINE => annotated_row.push(MINE),
                    &EMPTY => {
                        let neighbor_mines = self.num_neighbor_mines(y as u32, x as u32);
                        let annotated_location = if neighbor_mines == 0 {
                            " ".to_string()
                        } else {
                            neighbor_mines.to_string()
                        };
                        annotated_row.push_str(&annotated_location)
                    }
                    _ => panic!("unsupported token"),
                }
            }
            annotated.push(annotated_row)
        }

        annotated
    }

    fn num_neighbor_mines(&self, y: u32, x: u32) -> usize {
        return self
            .get_neighbors(y, x)
            .iter()
            .filter(|neighbor| neighbor == &&&MINE)
            .count();
    }

    fn get_neighbors(&self, y: u32, x: u32) -> Vec<&char> {
        let mut neighbors = Vec::new();
        let y = y as i32;
        let x = x as i32;

        let delta_ys: Vec<i32> = (-1..=1).collect();
        for delta_y in delta_ys {
            let delta_xs: Vec<i32> = (-1..=1).collect();
            for delta_x in delta_xs {
                if delta_y == 0 && delta_x == 0 {
                    continue;
                }
                if y + delta_y < 0 || y + delta_y >= self.field.len() as i32 {
                    continue;
                }
                if x + delta_x < 0 || x + delta_x >= self.field[0].len() as i32 {
                    continue;
                }
                let neighbor = &self.field[(y + delta_y) as usize][(x + delta_x) as usize];
                neighbors.push(neighbor)
            }
        }

        neighbors
    }
}

pub fn annotate(minefield: &[&str]) -> Vec<String> {
    let board = Board::new(minefield);
    return board.annotated();
}
<commit_msg>Extract Token type<commit_after>#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
enum Token {
    Mine = b'*',
    Empty = b' ',
}

impl Into<char> for Token {
    fn into(self) -> char {
        self as u8 as char
    }
}

impl Token {
    fn from(c: char) -> Result<Token, ()> {
        match c {
            '*' => Ok(Token::Mine),
            ' ' => Ok(Token::Empty),
            _ => Err(()),
        }
    }
}

struct Board {
    field: Vec<Vec<Token>>,
}

impl Board {
    fn new(minefield: &[&str]) -> Self {
        let mut field: Vec<Vec<Token>> = Vec::new();

        for row in minefield {
            let mut field_row: Vec<Token> = Vec::new();
            for char in row.chars() {
                let token = Token::from(char).unwrap();
                field_row.push(token);
            }
            field.push(field_row);
        }
        Board { field }
    }

    fn annotated(&self) -> Vec<String> {
        let mut annotated: Vec<String> = Vec::new();

        for (y, row) in self.field.iter().enumerate() {
            let mut annotated_row = String::new();
            for (x, token) in row.iter().enumerate() {
                match token {
                    Token::Mine => annotated_row.push(Token::Mine.into()),
                    Token::Empty => {
                        let neighbor_mines = self.num_neighbor_mines(y as u32, x as u32);
                        let annotated_location = if neighbor_mines == 0 {
                            " ".to_string()
                        } else {
                            neighbor_mines.to_string()
                        };
                        annotated_row.push_str(&annotated_location)
                    }
                }
            }
            annotated.push(annotated_row)
        }

        annotated
    }

    fn num_neighbor_mines(&self, y: u32, x: u32) -> usize {
        return self
            .get_neighbors(y, x)
            .iter()
            .filter(|neighbor| neighbor == &&&Token::Mine)
            .count();
    }

    fn get_neighbors(&self, y: u32, x: u32) -> Vec<&Token> {
        let mut neighbors = Vec::new();
        let y = y as i32;
        let x = x as i32;

        let delta_ys: Vec<i32> = (-1..=1).collect();
        for delta_y in delta_ys {
            let delta_xs: Vec<i32> = (-1..=1).collect();
            for delta_x in delta_xs {
                if delta_y == 0 && delta_x == 0 {
                    continue;
                }
                if y + delta_y < 0 || y + delta_y >= self.field.len() as i32 {
                    continue;
                }
                if x + delta_x < 0 || x + delta_x >= self.field[0].len() as i32 {
                    continue;
                }
                let neighbor = &self.field[(y + delta_y) as usize][(x + delta_x) as usize];
                neighbors.push(neighbor)
            }
        }

        neighbors
    }
}

pub fn annotate(minefield: &[&str]) -> Vec<String> {
    let board = Board::new(minefield);
    return board.annotated();
}
<|endoftext|>