<commit_before>use neb::ram::schema::Field;
use neb::ram::types::{TypeId, Id, key_hash, Map, Value};
use neb::ram::cell::{Cell, WriteError, ReadError};
use neb::client::{Client as NebClient};
use neb::client::transaction::{Transaction, TxnError};
use bifrost::rpc::RPCError;

use server::schema::{MorpheusSchema, SchemaType, SchemaContainer, SchemaError};
use graph::vertex::Vertex;
use graph::edge::bilateral::BilateralEdge;

use std::sync::Arc;
use serde::Serialize;

pub mod vertex;
pub mod edge;
pub mod fields;
mod id_list;
#[cfg(test)]
mod test;

pub enum NewVertexError {
    SchemaNotFound,
    SchemaNotVertex,
    CannotGenerateCellByData,
    DataNotMap,
    RPCError(RPCError),
    WriteError(WriteError)
}

pub enum ReadVertexError {
    RPCError(RPCError),
    ReadError(ReadError),
}

pub enum LinkVerticesError {
    EdgeSchemaNotFound,
    SchemaNotEdge,
    BodyRequired,
    BodyShouldNotExisted,
    EdgeError(edge::EdgeError),
}

#[derive(Clone, Copy, Serialize, Deserialize)]
pub enum CellType {
    Vertex,
    Edge(edge::EdgeType)
}

#[derive(Clone, Copy)]
pub enum EdgeDirection {
    Inbound,
    Outbound,
    Undirected
}

impl EdgeDirection {
    pub fn as_field(&self) -> u64 {
        match self {
            &EdgeDirection::Inbound => *fields::INBOUND_KEY_ID,
            &EdgeDirection::Outbound => *fields::OUTBOUND_KEY_ID,
            &EdgeDirection::Undirected => *fields::UNDIRECTED_KEY_ID,
        }
    }
}

fn vertex_to_cell_for_write(schemas: &Arc<SchemaContainer>, vertex: Vertex) -> Result<Cell, NewVertexError> {
    let schema_id = vertex.schema();
    if let Some(stype) = schemas.schema_type(schema_id) {
        if stype != SchemaType::Vertex {
            return Err(NewVertexError::SchemaNotVertex)
        }
    } else {
        return Err(NewVertexError::SchemaNotFound)
    }
    let neb_schema = match schemas.get_neb_schema(schema_id) {
        Some(schema) => schema,
        None => return Err(NewVertexError::SchemaNotFound)
    };
    let mut data = {
        match vertex.cell.data {
            Value::Map(map) => map,
            _ => return Err(NewVertexError::DataNotMap)
        }
    };
    data.insert_key_id(*fields::INBOUND_KEY_ID, Value::Id(Id::unit_id()));
    data.insert_key_id(*fields::OUTBOUND_KEY_ID, Value::Id(Id::unit_id()));
    data.insert_key_id(*fields::UNDIRECTED_KEY_ID, Value::Id(Id::unit_id()));
    match Cell::new(&neb_schema, Value::Map(data)) {
        Some(cell) => Ok(cell),
        None => return Err(NewVertexError::CannotGenerateCellByData)
    }
}

pub struct Graph {
    schemas: Arc<SchemaContainer>,
    neb_client: Arc<NebClient>
}

impl Graph {
    pub fn new(schemas: &Arc<SchemaContainer>, neb_client: &Arc<NebClient>) -> Graph {
        Graph {
            schemas: schemas.clone(),
            neb_client: neb_client.clone()
        }
    }
    pub fn new_vertex_group(&self, schema: &mut MorpheusSchema) -> Result<(), SchemaError> {
        schema.schema_type = SchemaType::Vertex;
        self.schemas.new_schema(schema)
    }
    pub fn new_edge_group(&self, schema: &mut MorpheusSchema, edge_attrs: edge::EdgeAttributes) -> Result<(), SchemaError> {
        schema.schema_type = SchemaType::Edge(edge_attrs);
        self.schemas.new_schema(schema)
    }
    pub fn new_vertex(&self, schema_id: u32, data: Map) -> Result<Vertex, NewVertexError> {
        let vertex = Vertex::new(schema_id, data);
        let mut cell = vertex_to_cell_for_write(&self.schemas, vertex)?;
        let header = match self.neb_client.write_cell(&cell) {
            Ok(Ok(header)) => header,
            Ok(Err(e)) => return Err(NewVertexError::WriteError(e)),
            Err(e) => return Err(NewVertexError::RPCError(e))
        };
        cell.header = header;
        Ok(vertex::cell_to_vertex(cell))
    }
    pub fn remove_vertex(&self, id: &Id) -> Result<(), TxnError> {
        self.neb_client.transaction(|mut txn| {
            vertex::txn_remove(&mut txn, id)
        })
    }
    pub fn remove_vertex_by_key<K>(&self, schema_id: u32, key: &K) -> Result<(), TxnError>
        where K: Serialize {
        let id = Cell::encode_cell_key(schema_id, key);
        self.remove_vertex(&id)
    }
    pub fn update_vertex<U>(&self, id: &Id, update: U) -> Result<(), TxnError>
        where U: Fn(Vertex) -> Option<Vertex> {
        self.neb_client.transaction(|txn|{
            vertex::txn_update(txn, id, &update)
        })
    }
    pub fn update_vertex_by_key<K, U>(&self, schema_id: u32, key: &K, update: U)
                                      -> Result<(), TxnError>
        where K: Serialize, U: Fn(Vertex) -> Option<Vertex>{
        let id = Cell::encode_cell_key(schema_id, key);
        self.update_vertex(&id, update)
    }

    pub fn read_vertex(&self, id: &Id) -> Result<Option<Vertex>, ReadVertexError> {
        match self.neb_client.read_cell(id) {
            Err(e) => Err(ReadVertexError::RPCError(e)),
            Ok(Err(ReadError::CellDoesNotExisted)) => Ok(None),
            Ok(Err(e)) => Err(ReadVertexError::ReadError(e)),
            Ok(Ok(cell)) => Ok(Some(vertex::cell_to_vertex(cell)))
        }
    }

    pub fn get_vertex<K>(&self, schema_id: u32, key: &K) -> Result<Option<Vertex>, ReadVertexError>
        where K: Serialize {
        let id = Cell::encode_cell_key(schema_id, key);
        self.read_vertex(&id)
    }

    pub fn graph_transaction<TFN>(&self, func: TFN) -> Result<(), TxnError>
        where TFN: Fn(&mut GraphTransaction) -> Result<(), TxnError>
    {
        let wrapper = |neb_txn: &mut Transaction| {
            func(&mut GraphTransaction {
                neb_txn: neb_txn,
                schemas: self.schemas.clone()
            })
        };
        self.neb_client.transaction(wrapper)
    }
}

pub struct GraphTransaction<'a> {
    pub neb_txn: & 'a mut Transaction,
    schemas: Arc<SchemaContainer>
}

impl <'a>GraphTransaction<'a> {
    pub fn new_vertex(&mut self, schema_id: u32, data: Map)
                      -> Result<Result<Vertex, NewVertexError>, TxnError> {
        let vertex = Vertex::new(schema_id, data);
        let mut cell = match vertex_to_cell_for_write(&self.schemas, vertex) {
            Ok(cell) => cell, Err(e) => return Ok(Err(e))
        };
        self.neb_txn.write(&cell)?;
        Ok(Ok(vertex::cell_to_vertex(cell)))
    }
    // TODO: Update edge list
    pub fn remove_vertex(&mut self, id: &Id) -> Result<(), TxnError> {
        vertex::txn_remove(self.neb_txn, id)
    }
    pub fn remove_vertex_by_key<K>(&mut self, schema_id: u32, key: &K) -> Result<(), TxnError>
        where K: Serialize {
        let id = Cell::encode_cell_key(schema_id, key);
        self.remove_vertex(&id)
    }

    pub fn link(&mut self, schema_id: u32, from_id: &Id, to_id: &Id, body: Option<Map>)
                -> Result<Result<edge::Edge, LinkVerticesError>, TxnError> {
        let edge_attr = match self.schemas.schema_type(schema_id) {
            Some(SchemaType::Edge(ea)) => ea,
            Some(_) => return Ok(Err(LinkVerticesError::SchemaNotEdge)),
            None => return Ok(Err(LinkVerticesError::EdgeSchemaNotFound))
        };
        match edge_attr.edge_type {
            edge::EdgeType::Directed =>
                Ok(edge::directed::DirectedEdge::link(from_id, to_id, body, &mut self.neb_txn, schema_id, &self.schemas)?
                    .map_err(LinkVerticesError::EdgeError).map(edge::Edge::Directed)),

            edge::EdgeType::Undirected =>
                Ok(edge::undirectd::UndirectedEdge::link(from_id, to_id, body, &mut self.neb_txn, schema_id, &self.schemas)?
                    .map_err(LinkVerticesError::EdgeError).map(edge::Edge::Undirected))
        }
    }
    pub fn update_vertex<U>(&mut self, id: &Id, update: U) -> Result<(), TxnError>
        where U: Fn(Vertex) -> Option<Vertex> {
        vertex::txn_update(self.neb_txn, id, &update)
    }
    pub fn update_vertex_by_key<K, U>(&mut self, schema_id: u32, key: &K, update: U)
                                      -> Result<(), TxnError>
        where K: Serialize, U: Fn(Vertex) -> Option<Vertex>{
        let id = Cell::encode_cell_key(schema_id, key);
        self.update_vertex(&id, update)
    }

    pub fn read_vertex(&mut self, id: &Id) -> Result<Option<Vertex>, TxnError> {
        self.neb_txn.read(id).map(|c| c.map(vertex::cell_to_vertex))
    }

    pub fn get_vertex<K>(&mut self, schema_id: u32, key: &K) -> Result<Option<Vertex>, TxnError>
        where K: Serialize {
        let id = Cell::encode_cell_key(schema_id, key);
        self.read_vertex(&id)
    }

    pub fn linkage(&mut self, vertex_id: &Id, schema_id: u32, ed: EdgeDirection)
                   -> Result<Result<Vec<edge::Edge>, edge::EdgeError>, TxnError> {
        let vertex_field = ed.as_field();
        match id_list::IdList::from_txn_and_container
            (self.neb_txn, vertex_id, vertex_field, schema_id).all()? {
            Err(e) => Ok(Err(edge::EdgeError::IdListError(e))),
            Ok(ids) => Ok(Ok({
                let mut edges = Vec::new();
                for id in ids {
                    match edge::from_id(
                        vertex_id, vertex_field, schema_id, &self.schemas, self.neb_txn, &id
                    )? {
                        Ok(e) => edges.push(e),
                        Err(er) => return Ok(Err(er))
                    }
                }
                edges
            }))
        }
    }
}<commit_msg>use graph transaction for untransactional remove<commit_after>use neb::ram::schema::Field;
use neb::ram::types::{TypeId, Id, key_hash, Map, Value};
use neb::ram::cell::{Cell, WriteError, ReadError};
use neb::client::{Client as NebClient};
use neb::client::transaction::{Transaction, TxnError};
use bifrost::rpc::RPCError;

use server::schema::{MorpheusSchema, SchemaType, SchemaContainer, SchemaError};
use graph::vertex::Vertex;
use graph::edge::bilateral::BilateralEdge;

use std::sync::Arc;
use serde::Serialize;

pub mod vertex;
pub mod edge;
pub mod fields;
mod id_list;
#[cfg(test)]
mod test;

pub enum NewVertexError {
    SchemaNotFound,
    SchemaNotVertex,
    CannotGenerateCellByData,
    DataNotMap,
    RPCError(RPCError),
    WriteError(WriteError)
}

pub enum ReadVertexError {
    RPCError(RPCError),
    ReadError(ReadError),
}

pub enum LinkVerticesError {
    EdgeSchemaNotFound,
    SchemaNotEdge,
    BodyRequired,
    BodyShouldNotExisted,
    EdgeError(edge::EdgeError),
}

#[derive(Clone, Copy, Serialize, Deserialize)]
pub enum CellType {
    Vertex,
    Edge(edge::EdgeType)
}

#[derive(Clone, Copy)]
pub enum EdgeDirection {
    Inbound,
    Outbound,
    Undirected
}

impl EdgeDirection {
    pub fn as_field(&self) -> u64 {
        match self {
            &EdgeDirection::Inbound => *fields::INBOUND_KEY_ID,
            &EdgeDirection::Outbound => *fields::OUTBOUND_KEY_ID,
            &EdgeDirection::Undirected => *fields::UNDIRECTED_KEY_ID,
        }
    }
}

fn vertex_to_cell_for_write(schemas: &Arc<SchemaContainer>, vertex: Vertex) -> Result<Cell, NewVertexError> {
    let schema_id = vertex.schema();
    if let Some(stype) = schemas.schema_type(schema_id) {
        if stype != SchemaType::Vertex {
            return Err(NewVertexError::SchemaNotVertex)
        }
    } else {
        return Err(NewVertexError::SchemaNotFound)
    }
    let neb_schema = match schemas.get_neb_schema(schema_id) {
        Some(schema) => schema,
        None => return Err(NewVertexError::SchemaNotFound)
    };
    let mut data = {
        match vertex.cell.data {
            Value::Map(map) => map,
            _ => return Err(NewVertexError::DataNotMap)
        }
    };
    data.insert_key_id(*fields::INBOUND_KEY_ID, Value::Id(Id::unit_id()));
    data.insert_key_id(*fields::OUTBOUND_KEY_ID, Value::Id(Id::unit_id()));
    data.insert_key_id(*fields::UNDIRECTED_KEY_ID, Value::Id(Id::unit_id()));
    match Cell::new(&neb_schema, Value::Map(data)) {
        Some(cell) => Ok(cell),
        None => return Err(NewVertexError::CannotGenerateCellByData)
    }
}

pub struct Graph {
    schemas: Arc<SchemaContainer>,
    neb_client: Arc<NebClient>
}

impl Graph {
    pub fn new(schemas: &Arc<SchemaContainer>, neb_client: &Arc<NebClient>) -> Graph {
        Graph {
            schemas: schemas.clone(),
            neb_client: neb_client.clone()
        }
    }
    pub fn new_vertex_group(&self, schema: &mut MorpheusSchema) -> Result<(), SchemaError> {
        schema.schema_type = SchemaType::Vertex;
        self.schemas.new_schema(schema)
    }
    pub fn new_edge_group(&self, schema: &mut MorpheusSchema, edge_attrs: edge::EdgeAttributes) -> Result<(), SchemaError> {
        schema.schema_type = SchemaType::Edge(edge_attrs);
        self.schemas.new_schema(schema)
    }
    pub fn new_vertex(&self, schema_id: u32, data: Map) -> Result<Vertex, NewVertexError> {
        let vertex = Vertex::new(schema_id, data);
        let mut cell = vertex_to_cell_for_write(&self.schemas, vertex)?;
        let header = match self.neb_client.write_cell(&cell) {
            Ok(Ok(header)) => header,
            Ok(Err(e)) => return Err(NewVertexError::WriteError(e)),
            Err(e) => return Err(NewVertexError::RPCError(e))
        };
        cell.header = header;
        Ok(vertex::cell_to_vertex(cell))
    }
    pub fn remove_vertex(&self, id: &Id) -> Result<(), TxnError> {
        self.graph_transaction(|txn| txn.remove_vertex(id))
    }
    pub fn remove_vertex_by_key<K>(&self, schema_id: u32, key: &K) -> Result<(), TxnError>
        where K: Serialize {
        let id = Cell::encode_cell_key(schema_id, key);
        self.remove_vertex(&id)
    }
    pub fn update_vertex<U>(&self, id: &Id, update: U) -> Result<(), TxnError>
        where U: Fn(Vertex) -> Option<Vertex> {
        self.neb_client.transaction(|txn|{
            vertex::txn_update(txn, id, &update)
        })
    }
    pub fn update_vertex_by_key<K, U>(&self, schema_id: u32, key: &K, update: U)
                                      -> Result<(), TxnError>
        where K: Serialize, U: Fn(Vertex) -> Option<Vertex>{
        let id = Cell::encode_cell_key(schema_id, key);
        self.update_vertex(&id, update)
    }

    pub fn read_vertex(&self, id: &Id) -> Result<Option<Vertex>, ReadVertexError> {
        match self.neb_client.read_cell(id) {
            Err(e) => Err(ReadVertexError::RPCError(e)),
            Ok(Err(ReadError::CellDoesNotExisted)) => Ok(None),
            Ok(Err(e)) => Err(ReadVertexError::ReadError(e)),
            Ok(Ok(cell)) => Ok(Some(vertex::cell_to_vertex(cell)))
        }
    }

    pub fn get_vertex<K>(&self, schema_id: u32, key: &K) -> Result<Option<Vertex>, ReadVertexError>
        where K: Serialize {
        let id = Cell::encode_cell_key(schema_id, key);
        self.read_vertex(&id)
    }

    pub fn graph_transaction<TFN>(&self, func: TFN) -> Result<(), TxnError>
        where TFN: Fn(&mut GraphTransaction) -> Result<(), TxnError>
    {
        let wrapper = |neb_txn: &mut Transaction| {
            func(&mut GraphTransaction {
                neb_txn: neb_txn,
                schemas: self.schemas.clone()
            })
        };
        self.neb_client.transaction(wrapper)
    }
}

pub struct GraphTransaction<'a> {
    pub neb_txn: & 'a mut Transaction,
    schemas: Arc<SchemaContainer>
}

impl <'a>GraphTransaction<'a> {
    pub fn new_vertex(&mut self, schema_id: u32, data: Map)
                      -> Result<Result<Vertex, NewVertexError>, TxnError> {
        let vertex = Vertex::new(schema_id, data);
        let mut cell = match vertex_to_cell_for_write(&self.schemas, vertex) {
            Ok(cell) => cell, Err(e) => return Ok(Err(e))
        };
        self.neb_txn.write(&cell)?;
        Ok(Ok(vertex::cell_to_vertex(cell)))
    }
    // TODO: Update edge list
    pub fn remove_vertex(&mut self, id: &Id) -> Result<(), TxnError> {
        vertex::txn_remove(self.neb_txn, id)
    }
    pub fn remove_vertex_by_key<K>(&mut self, schema_id: u32, key: &K) -> Result<(), TxnError>
        where K: Serialize {
        let id = Cell::encode_cell_key(schema_id, key);
        self.remove_vertex(&id)
    }

    pub fn link(&mut self, schema_id: u32, from_id: &Id, to_id: &Id, body: Option<Map>)
                -> Result<Result<edge::Edge, LinkVerticesError>, TxnError> {
        let edge_attr = match self.schemas.schema_type(schema_id) {
            Some(SchemaType::Edge(ea)) => ea,
            Some(_) => return Ok(Err(LinkVerticesError::SchemaNotEdge)),
            None => return Ok(Err(LinkVerticesError::EdgeSchemaNotFound))
        };
        match edge_attr.edge_type {
            edge::EdgeType::Directed =>
                Ok(edge::directed::DirectedEdge::link(from_id, to_id, body, &mut self.neb_txn, schema_id, &self.schemas)?
                    .map_err(LinkVerticesError::EdgeError).map(edge::Edge::Directed)),

            edge::EdgeType::Undirected =>
                Ok(edge::undirectd::UndirectedEdge::link(from_id, to_id, body, &mut self.neb_txn, schema_id, &self.schemas)?
                    .map_err(LinkVerticesError::EdgeError).map(edge::Edge::Undirected))
        }
    }
    pub fn update_vertex<U>(&mut self, id: &Id, update: U) -> Result<(), TxnError>
        where U: Fn(Vertex) -> Option<Vertex> {
        vertex::txn_update(self.neb_txn, id, &update)
    }
    pub fn update_vertex_by_key<K, U>(&mut self, schema_id: u32, key: &K, update: U)
                                      -> Result<(), TxnError>
        where K: Serialize, U: Fn(Vertex) -> Option<Vertex>{
        let id = Cell::encode_cell_key(schema_id, key);
        self.update_vertex(&id, update)
    }

    pub fn read_vertex(&mut self, id: &Id) -> Result<Option<Vertex>, TxnError> {
        self.neb_txn.read(id).map(|c| c.map(vertex::cell_to_vertex))
    }

    pub fn get_vertex<K>(&mut self, schema_id: u32, key: &K) -> Result<Option<Vertex>, TxnError>
        where K: Serialize {
        let id = Cell::encode_cell_key(schema_id, key);
        self.read_vertex(&id)
    }

    pub fn linkage(&mut self, vertex_id: &Id, schema_id: u32, ed: EdgeDirection)
                   -> Result<Result<Vec<edge::Edge>, edge::EdgeError>, TxnError> {
        let vertex_field = ed.as_field();
        match id_list::IdList::from_txn_and_container
            (self.neb_txn, vertex_id, vertex_field, schema_id).all()? {
            Err(e) => Ok(Err(edge::EdgeError::IdListError(e))),
            Ok(ids) => Ok(Ok({
                let mut edges = Vec::new();
                for id in ids {
                    match edge::from_id(
                        vertex_id, vertex_field, schema_id, &self.schemas, self.neb_txn, &id
                    )? {
                        Ok(e) => edges.push(e),
                        Err(er) => return Ok(Err(er))
                    }
                }
                edges
            }))
        }
    }
}<|endoftext|>


<commit_before>use voodoo::color::ColorValue;
use voodoo::window::{FormattedString, Point, Window};

use program::{Ability, Program};

pub struct InfoView {
    window: Window,
    ability_list: Vec<(String, Ability)>,
    selected_ability: Option<(usize, Ability)>,
}

impl InfoView {
    pub fn new(mut window: Window) -> InfoView {
        let mut f: FormattedString = "     End Turn     ".into();
        f.bg = Some(ColorValue::Magenta);
        window.print_at(Point::new(2, 23), f);

        InfoView {
            window: window,
            ability_list: Vec::new(),
            selected_ability: None,
        }
    }

    pub fn from_global_frame(&self, p: Point) -> Option<Point> {
        self.window.position.from_global_frame(p)
    }

    pub fn refresh(&mut self, stdout: &mut ::std::io::Stdout) {
        self.window.refresh(stdout);
    }

    pub fn clear(&mut self) {
        self.ability_list.clear();
        self.selected_ability = None;
        self.window.clear();
        self.window.border();
    }

    pub fn display_abilities(&mut self) {
        let mut y = 5;
        for (ability_number, &(ref name, _)) in self.ability_list.iter().enumerate() {
            let mut f: FormattedString = name.into();
            f.bg = if let Some((offset, _)) = self.selected_ability {
                if offset == ability_number {
                    Some(ColorValue::Red)
                }
                else {
                    Some(ColorValue::Magenta)
                }
            } else { Some(ColorValue::Magenta) };
            self.window.print_at(Point::new(2, y), f);
            y += 1;
        }
    }

    // TODO: take a ProgramRef and store it (maybe a weak reference)
    pub fn display_program(&mut self, program: &Program) {
        self.window.print_at(Point::new(2, 2), &program.name);

        self.window.print_at(Point::new(2, 4), "Abilities:");
        self.ability_list.extend(program.abilities.iter().cloned());

        self.display_abilities();
    }

    // TODO: return the ability range or something? Ability descriptor
    pub fn translate_click(&mut self, click: Point) -> Option<Ability> {
        for (offset, &(_, ability)) in self.ability_list.iter().enumerate() {
            if click.y == 5 + offset as u16 {
                self.selected_ability = Some((offset, ability));
                break;
            }
        }
        self.display_abilities();

        self.selected_ability.map(|(_, ability)| ability)
    }

    pub fn clear_ability(&mut self) {
        self.selected_ability = None;
        self.display_abilities();
    }
}
<commit_msg>fix: clear info view should still show end turn<commit_after>use voodoo::color::ColorValue;
use voodoo::window::{FormattedString, Point, Window};

use program::{Ability, Program};

pub struct InfoView {
    window: Window,
    ability_list: Vec<(String, Ability)>,
    selected_ability: Option<(usize, Ability)>,
}

impl InfoView {
    pub fn new(mut window: Window) -> InfoView {
        let mut f: FormattedString = "     End Turn     ".into();
        f.bg = Some(ColorValue::Magenta);
        window.print_at(Point::new(2, 23), f);

        InfoView {
            window: window,
            ability_list: Vec::new(),
            selected_ability: None,
        }
    }

    pub fn from_global_frame(&self, p: Point) -> Option<Point> {
        self.window.position.from_global_frame(p)
    }

    pub fn refresh(&mut self, stdout: &mut ::std::io::Stdout) {
        self.window.refresh(stdout);
    }

    pub fn clear(&mut self) {
        self.ability_list.clear();
        self.selected_ability = None;
        self.window.clear();
        self.window.border();
        let mut f: FormattedString = "     End Turn     ".into();
        f.bg = Some(ColorValue::Magenta);
        self.window.print_at(Point::new(2, 23), f);
    }

    pub fn display_abilities(&mut self) {
        let mut y = 5;
        for (ability_number, &(ref name, _)) in self.ability_list.iter().enumerate() {
            let mut f: FormattedString = name.into();
            f.bg = if let Some((offset, _)) = self.selected_ability {
                if offset == ability_number {
                    Some(ColorValue::Red)
                }
                else {
                    Some(ColorValue::Magenta)
                }
            } else { Some(ColorValue::Magenta) };
            self.window.print_at(Point::new(2, y), f);
            y += 1;
        }
    }

    // TODO: take a ProgramRef and store it (maybe a weak reference)
    pub fn display_program(&mut self, program: &Program) {
        self.window.print_at(Point::new(2, 2), &program.name);

        self.window.print_at(Point::new(2, 4), "Abilities:");
        self.ability_list.extend(program.abilities.iter().cloned());

        self.display_abilities();
    }

    // TODO: return the ability range or something? Ability descriptor
    pub fn translate_click(&mut self, click: Point) -> Option<Ability> {
        for (offset, &(_, ability)) in self.ability_list.iter().enumerate() {
            if click.y == 5 + offset as u16 {
                self.selected_ability = Some((offset, ability));
                break;
            }
        }
        self.display_abilities();

        self.selected_ability.map(|(_, ability)| ability)
    }

    pub fn clear_ability(&mut self) {
        self.selected_ability = None;
        self.display_abilities();
    }
}
<|endoftext|>


<commit_before>extern crate machine_id;
use self::machine_id::MachineId;

use super::arguments::DBusArguments;
use super::connection::DBusConnection;
use super::error::DBusError;
use super::message::DBusMessage;
use super::value::{DBusBasicValue, DBusDictionary, DBusSignature, DBusValue};

use std::cell::{Ref, RefCell};
use std::collections::btree_map::{BTreeMap, Entry};
use std::collections::HashMap;
use std::rc::Rc;

type DBusMap<T> = BTreeMap<String, T>;

pub struct DBusArgument {
    name: String,
    signature: String,
}

impl DBusArgument {
    pub fn new(name: &str, sig: &str) -> DBusArgument {
        DBusArgument {
            name: name.to_owned(),
            signature: sig.to_owned(),
        }
    }
}

pub struct DBusAnnotation {
    name: String,
    value: String,
}
type DBusAnnotations = Vec<DBusAnnotation>;

impl DBusAnnotation {
    pub fn new(name: &str, value: &str) -> DBusAnnotation {
        DBusAnnotation {
            name: name.to_owned(),
            value: value.to_owned(),
        }
    }
}

pub struct DBusErrorMessage {
    name: String,
    message: String,
}

impl DBusErrorMessage {
    pub fn new(name: &str, message: &str) -> DBusErrorMessage {
        DBusErrorMessage {
            name: name.to_owned(),
            message: message.to_owned(),
        }
    }
}

pub type DBusMethodResult = Result<Vec<DBusValue>, DBusErrorMessage>;
pub type DBusMethodHandler = Box<FnMut(&mut DBusMessage) -> DBusMethodResult>;

pub struct DBusMethod {
    in_args: Vec<DBusArgument>,
    out_args: Vec<DBusArgument>,
    cb: DBusMethodHandler,
    anns: DBusAnnotations,
}

impl DBusMethod {
    pub fn new<F>(cb: F) -> DBusMethod
        where F: FnMut(&mut DBusMessage) -> DBusMethodResult + 'static {
        DBusMethod {
            in_args: vec![],
            out_args: vec![],
            cb: Box::new(cb),
            anns: vec![],
        }
    }

    pub fn add_argument(mut self, arg: DBusArgument) -> DBusMethod {
        self.in_args.push(arg);

        self
    }

    pub fn add_result(mut self, arg: DBusArgument) -> DBusMethod {
        self.out_args.push(arg);

        self
    }

    pub fn annotate(mut self, ann: DBusAnnotation) -> DBusMethod {
        self.anns.push(ann);

        self
    }
}

pub type DBusPropertyGetResult = Result<DBusValue, DBusErrorMessage>;
pub type DBusPropertySetResult = Result<(), DBusErrorMessage>;

pub trait DBusPropertyReadHandler {
    fn get(&self) -> DBusPropertyGetResult;
}

pub trait DBusPropertyWriteHandler {
    fn set(&self, &DBusValue) -> DBusPropertySetResult;
}

pub trait DBusPropertyReadWriteHandler {
    fn get(&self) -> DBusPropertyGetResult;
    fn set(&self, &DBusValue) -> DBusPropertySetResult;
}

enum PropertyAccess {
    RO(Box<DBusPropertyReadHandler>),
    RW(Box<DBusPropertyReadWriteHandler>),
    WO(Box<DBusPropertyWriteHandler>),
}

pub struct DBusProperty {
    signature: DBusSignature,
    access: PropertyAccess,
    anns: DBusAnnotations,
}

impl DBusProperty {
    fn new(sig: DBusSignature, access: PropertyAccess) -> DBusProperty {
        DBusProperty {
            signature: sig,
            access: access,
            anns: vec![],
        }
    }

    pub fn new_ro(sig: DBusSignature, access: Box<DBusPropertyReadHandler>) -> DBusProperty {
        DBusProperty::new(sig, PropertyAccess::RO(access))
    }

    pub fn new_rw(sig: DBusSignature, access: Box<DBusPropertyReadWriteHandler>) -> DBusProperty {
        DBusProperty::new(sig, PropertyAccess::RW(access))
    }

    pub fn new_wo(sig: DBusSignature, access: Box<DBusPropertyWriteHandler>) -> DBusProperty {
        DBusProperty::new(sig, PropertyAccess::WO(access))
    }

    pub fn annotate(mut self, ann: DBusAnnotation) -> DBusProperty {
        self.anns.push(ann);

        self
    }
}

pub struct DBusSignal {
    args: Vec<DBusArgument>,
    anns: DBusAnnotations,
}

impl DBusSignal {
    pub fn new() -> DBusSignal {
        DBusSignal {
            args: vec![],
            anns: vec![],
        }
    }

    pub fn add_argument(mut self, arg: DBusArgument) -> DBusSignal {
        self.args.push(arg);

        self
    }

    pub fn annotate(mut self, ann: DBusAnnotation) -> DBusSignal {
        self.anns.push(ann);

        self
    }
}

pub struct DBusInterface {
    methods: DBusMap<DBusMethod>,
    properties: DBusMap<DBusProperty>,
    signals: DBusMap<DBusSignal>,
}

impl DBusInterface {
    pub fn new() -> DBusInterface {
        DBusInterface {
            methods: DBusMap::new(),
            properties: DBusMap::new(),
            signals: DBusMap::new(),
        }
    }

    pub fn add_method(mut self, name: &str, method: DBusMethod) -> DBusInterface {
        self.methods.insert(name.to_owned(), method);

        self
    }

    pub fn add_property(mut self, name: &str, property: DBusProperty) -> DBusInterface {
        self.properties.insert(name.to_owned(), property);

        self
    }

    pub fn get_property(&self, name: &str) -> Option<&DBusProperty> {
        self.properties.get(name)
    }

    pub fn add_signal(mut self, name: &str, signal: DBusSignal) -> DBusInterface {
        self.signals.insert(name.to_owned(), signal);

        self
    }

    fn _require_property(&self, name: &str) -> Result<&DBusProperty, DBusErrorMessage> {
        self.properties.get(name).ok_or(
            DBusErrorMessage::new("org.freedesktop.DBus.Error.UnknownProperty",
                                  &format!("unknown property: {}", name)))
    }

    pub fn get_property_value(&self, name: &str) -> DBusMethodResult {
        self._require_property(name).and_then(|prop| {
            match prop.access {
                // TODO: Verify that the signature matches the return.
                PropertyAccess::RO(ref ro) => ro.get().map(|v| vec![v]),
                PropertyAccess::RW(ref rw) => rw.get().map(|v| vec![v]),
                PropertyAccess::WO(_) =>
                    Err(DBusErrorMessage {
                        name: "org.freedesktop.DBus.Error.Failed".to_owned(),
                        message: format!("property is write-only: {}", name),
                    }),
            }
        })
    }

    pub fn set_property_value(&self, name: &str, value: &DBusValue) -> DBusMethodResult {
        self._require_property(name).and_then(|prop| {
            match prop.access {
                PropertyAccess::WO(ref wo) => wo.set(value).map(|_| vec![]),
                PropertyAccess::RW(ref rw) => rw.set(value).map(|_| vec![]),
                PropertyAccess::RO(_) =>
                    Err(DBusErrorMessage::new("org.freedesktop.DBus.Error.Failed",
                                              &format!("property is read-only: {}", name))),
            }
        })
    }

    pub fn get_property_map(&self) -> DBusDictionary {
        DBusDictionary::new(self.properties.iter().map(|(k, v)| {
            match v.access {
                // TODO: Message that failures occurred?
                // TODO: Verify that the signature matches the return.
                PropertyAccess::RO(ref ro) => ro.get().ok(),
                PropertyAccess::RW(ref rw) => rw.get().ok(),
                PropertyAccess::WO(_)      => None,
            }.map(|v| {
                (DBusBasicValue::String(k.clone()), v)
            })
        }).filter_map(|a| a).collect::<HashMap<DBusBasicValue, DBusValue>>())
    }
}

type InterfaceMap = Rc<RefCell<DBusMap<DBusInterface>>>;

pub struct DBusInterfaceMap {
    map: InterfaceMap,
    finalized: bool,
}

impl DBusInterfaceMap {
    pub fn new() -> DBusInterfaceMap {
        DBusInterfaceMap {
            map: Rc::new(RefCell::new(DBusMap::new())),
            finalized: false,
        }
    }

    // Marked as mut for intent; Rc<> doesn't require it though.
    #[allow(unused_mut)]
    pub fn add_interface(mut self, name: &str, iface: DBusInterface) -> Result<DBusInterfaceMap, DBusError> {
        if self.finalized {
            return Err(DBusError::InterfaceMapFinalized(name.to_owned()));
        }

        {
            let mut map = self.map.borrow_mut();

            match map.entry(name.to_owned()) {
                Entry::Vacant(v)    => {
                    v.insert(iface);

                    Ok(())
                },
                Entry::Occupied(_)  => Err(DBusError::InterfaceAlreadyRegistered(name.to_owned())),
            }
        }.map(|_| self)
    }

    fn ping() -> DBusMethodResult {
        Ok(vec![])
    }

    fn get_machine_id() -> DBusMethodResult {
        let mid = format!("{}", MachineId::get());
        Ok(vec![DBusValue::BasicValue(DBusBasicValue::String(mid))])
    }

    fn _require_interface<'a>(map: &'a Ref<'a, DBusMap<DBusInterface>>, name: &str) -> Result<&'a DBusInterface, DBusErrorMessage> {
        map.get(name).ok_or(
            DBusErrorMessage {
                name: "org.freedesktop.DBus.Error.UnknownInterface".to_owned(),
                message: format!("unknown interface: {}", name),
            })
    }

    fn get_property(map: &InterfaceMap, m: &mut DBusMessage) -> DBusMethodResult {
        let values = try!(DBusArguments::new(m));
        let iface = try!(values.extract_string(0));
        let property = try!(values.extract_string(1));

        Self::_require_interface(&map.borrow(), iface).and_then(|iface| {
            iface.get_property_value(property)
        })
    }

    fn set_property(map: &mut InterfaceMap, m: &mut DBusMessage) -> DBusMethodResult {
        let values = try!(DBusArguments::new(m));
        let iface = try!(values.extract_string(0));
        let property = try!(values.extract_string(1));
        let value = try!(values.extract(2));

        Self::_require_interface(&map.borrow(), iface).and_then(|iface| {
            iface.set_property_value(property, value)
        })
    }

    fn get_all_properties(map: &InterfaceMap, m: &mut DBusMessage) -> DBusMethodResult {
        let values = try!(DBusArguments::new(m));
        let iface = try!(values.extract_string(0));

        Self::_require_interface(&map.borrow(), iface).map(|iface| {
            vec![DBusValue::Dictionary(iface.get_property_map())]
        })
    }

    pub fn finalize(mut self) -> Result<DBusInterfaceMap, DBusError> {
        self = try!(self.add_interface("org.freedesktop.DBus.Peer", DBusInterface::new()
            .add_method("Ping", DBusMethod::new(|_| Self::ping()))
            .add_method("GetMachineId", DBusMethod::new(|_| Self::get_machine_id())
                .add_result(DBusArgument::new("machine_uuid", "s")))
        ));

        let get_map = self.map.clone();
        let mut set_map = self.map.clone();
        let get_all_map = self.map.clone();

        self = try!(self.add_interface("org.freedesktop.DBus.Properties", DBusInterface::new()
            .add_method("Get", DBusMethod::new(move |m| Self::get_property(&get_map, m))
                .add_argument(DBusArgument::new("interface_name", "s"))
                .add_argument(DBusArgument::new("property_name", "s"))
                .add_result(DBusArgument::new("value", "v")))
            .add_method("Set", DBusMethod::new(move |m| Self::set_property(&mut set_map, m))
                .add_argument(DBusArgument::new("interface_name", "s"))
                .add_argument(DBusArgument::new("property_name", "s"))
                .add_result(DBusArgument::new("value", "v")))
            .add_method("GetAll", DBusMethod::new(move |m| Self::get_all_properties(&get_all_map, m))
                .add_argument(DBusArgument::new("interface_name", "s"))
                .add_result(DBusArgument::new("props", "{sv}")))
        ));

        // TODO: Add core interfaces.

        self.finalized = true;
        Ok(self)
    }

    pub fn handle(&self, conn: &DBusConnection, msg: &mut DBusMessage) -> Option<Result<(), ()>> {
        msg.call_headers().and_then(|hdrs| {
            let iface_name = hdrs.interface;
            let method_name = hdrs.method;
            self.map.borrow_mut().get_mut(&iface_name).and_then(|iface| iface.methods.get_mut(&method_name)).map(|method| {
                // TODO: Verify input argument signature.

                let msg = match (method.cb)(msg) {
                    Ok(vals) => {
                        vals.iter().fold(msg.return_message(), |msg, val| {
                            msg.add_argument(val)
                        })
                    },
                    Err(err) => msg.error_message(&err.name)
                                   .add_argument(&err.message),
                };

                // TODO: Verify that the signature matches the return.

                conn.send(msg)
                    .map(|_| ())
                    .map_err(|_| ())
            })
        })
    }
}
<commit_msg>interface: refactor out interfaces into structs<commit_after>extern crate machine_id;
use self::machine_id::MachineId;

use super::arguments::DBusArguments;
use super::connection::DBusConnection;
use super::error::DBusError;
use super::message::DBusMessage;
use super::value::{DBusBasicValue, DBusDictionary, DBusSignature, DBusValue};

use std::cell::{Ref, RefCell};
use std::collections::btree_map::{BTreeMap, Entry};
use std::collections::HashMap;
use std::rc::Rc;

type DBusMap<T> = BTreeMap<String, T>;

pub struct DBusArgument {
    name: String,
    signature: String,
}

impl DBusArgument {
    pub fn new(name: &str, sig: &str) -> DBusArgument {
        DBusArgument {
            name: name.to_owned(),
            signature: sig.to_owned(),
        }
    }
}

pub struct DBusAnnotation {
    name: String,
    value: String,
}
type DBusAnnotations = Vec<DBusAnnotation>;

impl DBusAnnotation {
    pub fn new(name: &str, value: &str) -> DBusAnnotation {
        DBusAnnotation {
            name: name.to_owned(),
            value: value.to_owned(),
        }
    }
}

pub struct DBusErrorMessage {
    name: String,
    message: String,
}

impl DBusErrorMessage {
    pub fn new(name: &str, message: &str) -> DBusErrorMessage {
        DBusErrorMessage {
            name: name.to_owned(),
            message: message.to_owned(),
        }
    }
}

pub type DBusMethodResult = Result<Vec<DBusValue>, DBusErrorMessage>;
pub type DBusMethodHandler = Box<FnMut(&mut DBusMessage) -> DBusMethodResult>;

pub struct DBusMethod {
    in_args: Vec<DBusArgument>,
    out_args: Vec<DBusArgument>,
    cb: DBusMethodHandler,
    anns: DBusAnnotations,
}

impl DBusMethod {
    pub fn new<F>(cb: F) -> DBusMethod
        where F: FnMut(&mut DBusMessage) -> DBusMethodResult + 'static {
        DBusMethod {
            in_args: vec![],
            out_args: vec![],
            cb: Box::new(cb),
            anns: vec![],
        }
    }

    pub fn add_argument(mut self, arg: DBusArgument) -> DBusMethod {
        self.in_args.push(arg);

        self
    }

    pub fn add_result(mut self, arg: DBusArgument) -> DBusMethod {
        self.out_args.push(arg);

        self
    }

    pub fn annotate(mut self, ann: DBusAnnotation) -> DBusMethod {
        self.anns.push(ann);

        self
    }
}

pub type DBusPropertyGetResult = Result<DBusValue, DBusErrorMessage>;
pub type DBusPropertySetResult = Result<(), DBusErrorMessage>;

pub trait DBusPropertyReadHandler {
    fn get(&self) -> DBusPropertyGetResult;
}

pub trait DBusPropertyWriteHandler {
    fn set(&self, &DBusValue) -> DBusPropertySetResult;
}

pub trait DBusPropertyReadWriteHandler {
    fn get(&self) -> DBusPropertyGetResult;
    fn set(&self, &DBusValue) -> DBusPropertySetResult;
}

enum PropertyAccess {
    RO(Box<DBusPropertyReadHandler>),
    RW(Box<DBusPropertyReadWriteHandler>),
    WO(Box<DBusPropertyWriteHandler>),
}

pub struct DBusProperty {
    signature: DBusSignature,
    access: PropertyAccess,
    anns: DBusAnnotations,
}

impl DBusProperty {
    fn new(sig: DBusSignature, access: PropertyAccess) -> DBusProperty {
        DBusProperty {
            signature: sig,
            access: access,
            anns: vec![],
        }
    }

    pub fn new_ro(sig: DBusSignature, access: Box<DBusPropertyReadHandler>) -> DBusProperty {
        DBusProperty::new(sig, PropertyAccess::RO(access))
    }

    pub fn new_rw(sig: DBusSignature, access: Box<DBusPropertyReadWriteHandler>) -> DBusProperty {
        DBusProperty::new(sig, PropertyAccess::RW(access))
    }

    pub fn new_wo(sig: DBusSignature, access: Box<DBusPropertyWriteHandler>) -> DBusProperty {
        DBusProperty::new(sig, PropertyAccess::WO(access))
    }

    pub fn annotate(mut self, ann: DBusAnnotation) -> DBusProperty {
        self.anns.push(ann);

        self
    }
}

pub struct DBusSignal {
    args: Vec<DBusArgument>,
    anns: DBusAnnotations,
}

impl DBusSignal {
    pub fn new() -> DBusSignal {
        DBusSignal {
            args: vec![],
            anns: vec![],
        }
    }

    pub fn add_argument(mut self, arg: DBusArgument) -> DBusSignal {
        self.args.push(arg);

        self
    }

    pub fn annotate(mut self, ann: DBusAnnotation) -> DBusSignal {
        self.anns.push(ann);

        self
    }
}

pub struct DBusInterface {
    methods: DBusMap<DBusMethod>,
    properties: DBusMap<DBusProperty>,
    signals: DBusMap<DBusSignal>,
}

impl DBusInterface {
    pub fn new() -> DBusInterface {
        DBusInterface {
            methods: DBusMap::new(),
            properties: DBusMap::new(),
            signals: DBusMap::new(),
        }
    }

    pub fn add_method(mut self, name: &str, method: DBusMethod) -> DBusInterface {
        self.methods.insert(name.to_owned(), method);

        self
    }

    pub fn add_property(mut self, name: &str, property: DBusProperty) -> DBusInterface {
        self.properties.insert(name.to_owned(), property);

        self
    }

    pub fn get_property(&self, name: &str) -> Option<&DBusProperty> {
        self.properties.get(name)
    }

    pub fn add_signal(mut self, name: &str, signal: DBusSignal) -> DBusInterface {
        self.signals.insert(name.to_owned(), signal);

        self
    }

    fn _require_property(&self, name: &str) -> Result<&DBusProperty, DBusErrorMessage> {
        self.properties.get(name).ok_or(
            DBusErrorMessage::new("org.freedesktop.DBus.Error.UnknownProperty",
                                  &format!("unknown property: {}", name)))
    }

    pub fn get_property_value(&self, name: &str) -> DBusMethodResult {
        self._require_property(name).and_then(|prop| {
            match prop.access {
                // TODO: Verify that the signature matches the return.
                PropertyAccess::RO(ref ro) => ro.get().map(|v| vec![v]),
                PropertyAccess::RW(ref rw) => rw.get().map(|v| vec![v]),
                PropertyAccess::WO(_) =>
                    Err(DBusErrorMessage {
                        name: "org.freedesktop.DBus.Error.Failed".to_owned(),
                        message: format!("property is write-only: {}", name),
                    }),
            }
        })
    }

    pub fn set_property_value(&self, name: &str, value: &DBusValue) -> DBusMethodResult {
        self._require_property(name).and_then(|prop| {
            match prop.access {
                PropertyAccess::WO(ref wo) => wo.set(value).map(|_| vec![]),
                PropertyAccess::RW(ref rw) => rw.set(value).map(|_| vec![]),
                PropertyAccess::RO(_) =>
                    Err(DBusErrorMessage::new("org.freedesktop.DBus.Error.Failed",
                                              &format!("property is read-only: {}", name))),
            }
        })
    }

    pub fn get_property_map(&self) -> DBusDictionary {
        DBusDictionary::new(self.properties.iter().map(|(k, v)| {
            match v.access {
                // TODO: Message that failures occurred?
                // TODO: Verify that the signature matches the return.
                PropertyAccess::RO(ref ro) => ro.get().ok(),
                PropertyAccess::RW(ref rw) => rw.get().ok(),
                PropertyAccess::WO(_)      => None,
            }.map(|v| {
                (DBusBasicValue::String(k.clone()), v)
            })
        }).filter_map(|a| a).collect::<HashMap<DBusBasicValue, DBusValue>>())
    }
}

type InterfaceMap = Rc<RefCell<DBusMap<DBusInterface>>>;

fn require_interface<'a>(map: &'a Ref<'a, DBusMap<DBusInterface>>, name: &str) -> Result<&'a DBusInterface, DBusErrorMessage> {
    map.get(name).ok_or(
        DBusErrorMessage {
            name: "org.freedesktop.DBus.Error.UnknownInterface".to_owned(),
            message: format!("unknown interface: {}", name),
        })
}

pub struct DBusInterfaceMap {
    map: InterfaceMap,
    finalized: bool,
}

struct DBusPeerInterface;

impl DBusPeerInterface {
    fn ping() -> DBusMethodResult {
        Ok(vec![])
    }

    fn get_machine_id() -> DBusMethodResult {
        let mid = format!("{}", MachineId::get());
        Ok(vec![DBusValue::BasicValue(DBusBasicValue::String(mid))])
    }

    pub fn new() -> DBusInterface {
        DBusInterface::new()
            .add_method("Ping", DBusMethod::new(|_| Self::ping()))
            .add_method("GetMachineId", DBusMethod::new(|_| Self::get_machine_id())
                .add_result(DBusArgument::new("machine_uuid", "s")))
    }
}

struct DBusPropertyInterface;

impl DBusPropertyInterface {
    fn get_property(map: &InterfaceMap, m: &mut DBusMessage) -> DBusMethodResult {
        let values = try!(DBusArguments::new(m));
        let iface = try!(values.extract_string(0));
        let property = try!(values.extract_string(1));

        require_interface(&map.borrow(), iface).and_then(|iface| {
            iface.get_property_value(property)
        })
    }

    fn set_property(map: &mut InterfaceMap, m: &mut DBusMessage) -> DBusMethodResult {
        let values = try!(DBusArguments::new(m));
        let iface = try!(values.extract_string(0));
        let property = try!(values.extract_string(1));
        let value = try!(values.extract(2));

        require_interface(&map.borrow(), iface).and_then(|iface| {
            iface.set_property_value(property, value)
        })
    }

    fn get_all_properties(map: &InterfaceMap, m: &mut DBusMessage) -> DBusMethodResult {
        let values = try!(DBusArguments::new(m));
        let iface = try!(values.extract_string(0));

        require_interface(&map.borrow(), iface).map(|iface| {
            vec![DBusValue::Dictionary(iface.get_property_map())]
        })
    }

    pub fn new(map: InterfaceMap) -> DBusInterface {
        let get_map = map.clone();
        let mut set_map = map.clone();
        let get_all_map = map.clone();

        DBusInterface::new()
            .add_method("Get", DBusMethod::new(move |m| Self::get_property(&get_map, m))
                .add_argument(DBusArgument::new("interface_name", "s"))
                .add_argument(DBusArgument::new("property_name", "s"))
                .add_result(DBusArgument::new("value", "v")))
            .add_method("Set", DBusMethod::new(move |m| Self::set_property(&mut set_map, m))
                .add_argument(DBusArgument::new("interface_name", "s"))
                .add_argument(DBusArgument::new("property_name", "s"))
                .add_result(DBusArgument::new("value", "v")))
            .add_method("GetAll", DBusMethod::new(move |m| Self::get_all_properties(&get_all_map, m))
                .add_argument(DBusArgument::new("interface_name", "s"))
                .add_result(DBusArgument::new("props", "{sv}")))
    }
}

impl DBusInterfaceMap {
    pub fn new() -> DBusInterfaceMap {
        DBusInterfaceMap {
            map: Rc::new(RefCell::new(DBusMap::new())),
            finalized: false,
        }
    }

    // Marked as mut for intent; Rc<> doesn't require it though.
    #[allow(unused_mut)]
    pub fn add_interface(mut self, name: &str, iface: DBusInterface) -> Result<DBusInterfaceMap, DBusError> {
        if self.finalized {
            return Err(DBusError::InterfaceMapFinalized(name.to_owned()));
        }

        {
            let mut map = self.map.borrow_mut();

            match map.entry(name.to_owned()) {
                Entry::Vacant(v)    => {
                    v.insert(iface);

                    Ok(())
                },
                Entry::Occupied(_)  => Err(DBusError::InterfaceAlreadyRegistered(name.to_owned())),
            }
        }.map(|_| self)
    }

    pub fn finalize(mut self) -> Result<DBusInterfaceMap, DBusError> {
        self = try!(self.add_interface("org.freedesktop.DBus.Peer", DBusPeerInterface::new()));

        let property_map = self.map.clone();
        self = try!(self.add_interface("org.freedesktop.DBus.Properties", DBusPropertyInterface::new(property_map)));

        self.finalized = true;
        Ok(self)
    }

    pub fn handle(&self, conn: &DBusConnection, msg: &mut DBusMessage) -> Option<Result<(), ()>> {
        msg.call_headers().and_then(|hdrs| {
            let iface_name = hdrs.interface;
            let method_name = hdrs.method;
            self.map.borrow_mut().get_mut(&iface_name).and_then(|iface| iface.methods.get_mut(&method_name)).map(|method| {
                // TODO: Verify input argument signature.

                let msg = match (method.cb)(msg) {
                    Ok(vals) => {
                        vals.iter().fold(msg.return_message(), |msg, val| {
                            msg.add_argument(val)
                        })
                    },
                    Err(err) => msg.error_message(&err.name)
                                   .add_argument(&err.message),
                };

                // TODO: Verify that the signature matches the return.

                conn.send(msg)
                    .map(|_| ())
                    .map_err(|_| ())
            })
        })
    }
}
<|endoftext|>


<commit_before>use super::*;
use serde::{Deserialize, Serialize};

/// Defines the class of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Deserialize, Serialize)]
pub enum GeoClass {
    /// Lines (segments) class
    Lin,

    /// Triangles class
    Tri,

    /// Quadrilaterals class
    Qua,

    /// Tetrahedra class
    Tet,

    /// Hexahedra class
    Hex,
}

/// Defines the kind of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Deserialize, Serialize)]
pub enum GeoKind {
    /// Line (segment) with 2 nodes (linear functions)
    Lin2 = 1_002,

    /// Line (segment) with 3 nodes (quadratic functions)
    Lin3 = 1_003,

    /// Line (segment) with 4 nodes (cubic functions)
    Lin4 = 1_004,

    /// Line (segment) with 5 nodes (quartic functions)
    Lin5 = 1_005,

    /// Triangle with 3 nodes (linear edges)
    Tri3 = 2_003,

    /// Triangle with 6 nodes (quadratic edges)
    Tri6 = 2_006,

    /// Triangle with 10 nodes (cubic edges; interior node)
    Tri10 = 2_010,

    /// Triangle with 15 nodes (quartic edges; interior nodes)
    Tri15 = 2_015,

    /// Quadrilateral with 4 nodes (linear edges)
    Qua4 = 2_004,

    /// Quadrilateral with 8 nodes (quadratic edges)
    Qua8 = 2_008,

    /// Quadrilateral with 9 nodes (quadratic edges; interior node)
    Qua9 = 2_009,

    /// Quadrilateral with 12 nodes (cubic edges)
    Qua12 = 2_012,

    /// Quadrilateral with 16 nodes (cubic edges; interior nodes)
    Qua16 = 2_016,

    /// Quadrilateral with 17 nodes (quartic edges; interior node)
    Qua17 = 2_017,

    /// Tetrahedron with 4 nodes (linear faces)
    Tet4 = 3_004,

    /// Tetrahedron with 10 nodes (quadratic faces)
    Tet10 = 3_010,

    /// Hexahedron with 8 nodes (bilinear faces)
    Hex8 = 3_008,

    /// Hexahedron with 20 nodes (quadratic faces)
    Hex20 = 3_020,
}

impl GeoKind {
    /// Holds all enum values
    pub const VALUES: [Self; 18] = [
        Self::Lin2,
        Self::Lin3,
        Self::Lin4,
        Self::Lin5,
        Self::Tri3,
        Self::Tri6,
        Self::Tri10,
        Self::Tri15,
        Self::Qua4,
        Self::Qua8,
        Self::Qua9,
        Self::Qua12,
        Self::Qua16,
        Self::Qua17,
        Self::Tet4,
        Self::Tet10,
        Self::Hex8,
        Self::Hex20,
    ];
}

pub(crate) fn i32_to_fn_interp(kind: i32) -> FnInterp {
    match kind {
        // Lin
        1_002 => FnInterp(GeoKind::Lin2, Lin2::calc_interp),
        1_003 => FnInterp(GeoKind::Lin3, Lin3::calc_interp),
        1_004 => FnInterp(GeoKind::Lin4, Lin4::calc_interp),
        1_005 => FnInterp(GeoKind::Lin5, Lin5::calc_interp),
        // Tri
        2_003 => FnInterp(GeoKind::Tri3, Tri3::calc_interp),
        2_006 => FnInterp(GeoKind::Tri6, Tri6::calc_interp),
        2_010 => FnInterp(GeoKind::Tri10, Tri10::calc_interp),
        2_015 => FnInterp(GeoKind::Tri15, Tri15::calc_interp),
        // Qua
        2_004 => FnInterp(GeoKind::Qua4, Qua4::calc_interp),
        2_008 => FnInterp(GeoKind::Qua8, Qua8::calc_interp),
        2_009 => FnInterp(GeoKind::Qua9, Qua9::calc_interp),
        2_012 => FnInterp(GeoKind::Qua12, Qua12::calc_interp),
        2_016 => FnInterp(GeoKind::Qua16, Qua16::calc_interp),
        2_017 => FnInterp(GeoKind::Qua17, Qua17::calc_interp),
        // Tet
        3_004 => FnInterp(GeoKind::Tet4, Tet4::calc_interp),
        3_010 => FnInterp(GeoKind::Tet10, Tet10::calc_interp),
        // Hex
        3_008 => FnInterp(GeoKind::Hex8, Hex8::calc_interp),
        3_020 => FnInterp(GeoKind::Hex20, Hex20::calc_interp),
        _ => panic!("INTERNAL ERROR: cannot convert i32 to FnInterp"),
    }
}

pub(crate) fn i32_to_fn_deriv(kind: i32) -> FnDeriv {
    match kind {
        // Lin
        1_002 => FnDeriv(GeoKind::Lin2, Lin2::calc_deriv),
        1_003 => FnDeriv(GeoKind::Lin3, Lin3::calc_deriv),
        1_004 => FnDeriv(GeoKind::Lin4, Lin4::calc_deriv),
        1_005 => FnDeriv(GeoKind::Lin5, Lin5::calc_deriv),
        // Tri
        2_003 => FnDeriv(GeoKind::Tri3, Tri3::calc_deriv),
        2_006 => FnDeriv(GeoKind::Tri6, Tri6::calc_deriv),
        2_010 => FnDeriv(GeoKind::Tri10, Tri10::calc_deriv),
        2_015 => FnDeriv(GeoKind::Tri15, Tri15::calc_deriv),
        // Qua
        2_004 => FnDeriv(GeoKind::Qua4, Qua4::calc_deriv),
        2_008 => FnDeriv(GeoKind::Qua8, Qua8::calc_deriv),
        2_009 => FnDeriv(GeoKind::Qua9, Qua9::calc_deriv),
        2_012 => FnDeriv(GeoKind::Qua12, Qua12::calc_deriv),
        2_016 => FnDeriv(GeoKind::Qua16, Qua16::calc_deriv),
        2_017 => FnDeriv(GeoKind::Qua17, Qua17::calc_deriv),
        // Tet
        3_004 => FnDeriv(GeoKind::Tet4, Tet4::calc_deriv),
        3_010 => FnDeriv(GeoKind::Tet10, Tet10::calc_deriv),
        // Hex
        3_008 => FnDeriv(GeoKind::Hex8, Hex8::calc_deriv),
        3_020 => FnDeriv(GeoKind::Hex20, Hex20::calc_deriv),
        _ => panic!("INTERNAL ERROR: cannot convert i32 to FnDeriv"),
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{i32_to_fn_deriv, i32_to_fn_interp};
    use crate::shapes::{GeoClass, GeoKind};
    use std::collections::HashSet;

    #[test]
    fn derive_works() {
        let class = GeoClass::Tri.clone();
        let kind = GeoKind::Tri6.clone();
        let classes = HashSet::from([GeoClass::Tri, GeoClass::Qua]);
        let kinds = HashSet::from([GeoKind::Tri3, GeoKind::Qua4]);
        assert_eq!(class, GeoClass::Tri);
        assert_eq!(kind, GeoKind::Tri6);
        assert_eq!(format!("{:?}", class), "Tri");
        assert_eq!(format!("{:?}", kind), "Tri6");
        assert_eq!(classes.contains(&GeoClass::Tri), true);
        assert_eq!(kinds.contains(&GeoKind::Tri3), true);
    }

    #[test]
    fn data_is_consistent() {
        for kind in GeoKind::VALUES {
            match kind {
                // Lin
                GeoKind::Lin2 => {
                    let k = kind as i32;
                    let nnode = k - 1000;
                    assert_eq!(nnode, 2);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Lin2);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Lin2);
                }
                GeoKind::Lin3 => {
                    let k = kind as i32;
                    let nnode = k - 1000;
                    assert_eq!(nnode, 3);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Lin3);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Lin3);
                }
                GeoKind::Lin4 => {
                    let k = kind as i32;
                    let nnode = k - 1000;
                    assert_eq!(nnode, 4);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Lin4);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Lin4);
                }
                GeoKind::Lin5 => {
                    let k = kind as i32;
                    let nnode = k - 1000;
                    assert_eq!(nnode, 5);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Lin5);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Lin5);
                }

                // Tri
                GeoKind::Tri3 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 3);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tri3);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tri3);
                }
                GeoKind::Tri6 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 6);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tri6);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tri6);
                }
                GeoKind::Tri10 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 10);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tri10);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tri10);
                }
                GeoKind::Tri15 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 15);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tri15);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tri15);
                }

                // Qua
                GeoKind::Qua4 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 4);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua4);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua4);
                }
                GeoKind::Qua8 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 8);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua8);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua8);
                }
                GeoKind::Qua9 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 9);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua9);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua9);
                }
                GeoKind::Qua12 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 12);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua12);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua12);
                }
                GeoKind::Qua16 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 16);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua16);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua16);
                }
                GeoKind::Qua17 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 17);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua17);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua17);
                }

                // Tet
                GeoKind::Tet4 => {
                    let k = kind as i32;
                    let nnode = k - 3000;
                    assert_eq!(nnode, 4);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tet4);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tet4);
                }
                GeoKind::Tet10 => {
                    let k = kind as i32;
                    let nnode = k - 3000;
                    assert_eq!(nnode, 10);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tet10);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tet10);
                }

                // Hex
                GeoKind::Hex8 => {
                    let k = kind as i32;
                    let nnode = k - 3000;
                    assert_eq!(nnode, 8);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Hex8);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Hex8);
                }
                GeoKind::Hex20 => {
                    let k = kind as i32;
                    let nnode = k - 3000;
                    assert_eq!(nnode, 20);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Hex20);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Hex20);
                }
            }
        }
    }
}
<commit_msg>Add comments<commit_after>use super::*;
use serde::{Deserialize, Serialize};

/// Defines the class of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Deserialize, Serialize)]
pub enum GeoClass {
    /// Lines (segments) class
    Lin,

    /// Triangles class
    Tri,

    /// Quadrilaterals class
    Qua,

    /// Tetrahedra class
    Tet,

    /// Hexahedra class
    Hex,
}

/// Defines the kind of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Deserialize, Serialize)]
pub enum GeoKind {
    /// Line (segment) with 2 nodes (linear functions)
    Lin2 = 1_002,

    /// Line (segment) with 3 nodes (quadratic functions)
    Lin3 = 1_003,

    /// Line (segment) with 4 nodes (cubic functions)
    Lin4 = 1_004,

    /// Line (segment) with 5 nodes (quartic functions)
    Lin5 = 1_005,

    /// Triangle with 3 nodes (linear edges)
    Tri3 = 2_003,

    /// Triangle with 6 nodes (quadratic edges)
    Tri6 = 2_006,

    /// Triangle with 10 nodes (cubic edges; interior node)
    Tri10 = 2_010,

    /// Triangle with 15 nodes (quartic edges; interior nodes)
    Tri15 = 2_015,

    /// Quadrilateral with 4 nodes (linear edges)
    Qua4 = 2_004,

    /// Quadrilateral with 8 nodes (quadratic edges)
    Qua8 = 2_008,

    /// Quadrilateral with 9 nodes (quadratic edges; interior node)
    Qua9 = 2_009,

    /// Quadrilateral with 12 nodes (cubic edges)
    Qua12 = 2_012,

    /// Quadrilateral with 16 nodes (cubic edges; interior nodes)
    Qua16 = 2_016,

    /// Quadrilateral with 17 nodes (quartic edges; interior node)
    Qua17 = 2_017,

    /// Tetrahedron with 4 nodes (linear faces)
    Tet4 = 3_004,

    /// Tetrahedron with 10 nodes (quadratic faces)
    Tet10 = 3_010,

    /// Hexahedron with 8 nodes (bilinear faces)
    Hex8 = 3_008,

    /// Hexahedron with 20 nodes (quadratic faces)
    Hex20 = 3_020,
}

impl GeoKind {
    /// Holds all enum values
    pub const VALUES: [Self; 18] = [
        // Lin
        Self::Lin2,
        Self::Lin3,
        Self::Lin4,
        Self::Lin5,
        // Tri
        Self::Tri3,
        Self::Tri6,
        Self::Tri10,
        Self::Tri15,
        // Qua
        Self::Qua4,
        Self::Qua8,
        Self::Qua9,
        Self::Qua12,
        Self::Qua16,
        Self::Qua17,
        // Tet
        Self::Tet4,
        Self::Tet10,
        // Hex
        Self::Hex8,
        Self::Hex20,
    ];
}

pub(crate) fn i32_to_fn_interp(kind: i32) -> FnInterp {
    match kind {
        // Lin
        1_002 => FnInterp(GeoKind::Lin2, Lin2::calc_interp),
        1_003 => FnInterp(GeoKind::Lin3, Lin3::calc_interp),
        1_004 => FnInterp(GeoKind::Lin4, Lin4::calc_interp),
        1_005 => FnInterp(GeoKind::Lin5, Lin5::calc_interp),
        // Tri
        2_003 => FnInterp(GeoKind::Tri3, Tri3::calc_interp),
        2_006 => FnInterp(GeoKind::Tri6, Tri6::calc_interp),
        2_010 => FnInterp(GeoKind::Tri10, Tri10::calc_interp),
        2_015 => FnInterp(GeoKind::Tri15, Tri15::calc_interp),
        // Qua
        2_004 => FnInterp(GeoKind::Qua4, Qua4::calc_interp),
        2_008 => FnInterp(GeoKind::Qua8, Qua8::calc_interp),
        2_009 => FnInterp(GeoKind::Qua9, Qua9::calc_interp),
        2_012 => FnInterp(GeoKind::Qua12, Qua12::calc_interp),
        2_016 => FnInterp(GeoKind::Qua16, Qua16::calc_interp),
        2_017 => FnInterp(GeoKind::Qua17, Qua17::calc_interp),
        // Tet
        3_004 => FnInterp(GeoKind::Tet4, Tet4::calc_interp),
        3_010 => FnInterp(GeoKind::Tet10, Tet10::calc_interp),
        // Hex
        3_008 => FnInterp(GeoKind::Hex8, Hex8::calc_interp),
        3_020 => FnInterp(GeoKind::Hex20, Hex20::calc_interp),
        _ => panic!("INTERNAL ERROR: cannot convert i32 to FnInterp"),
    }
}

pub(crate) fn i32_to_fn_deriv(kind: i32) -> FnDeriv {
    match kind {
        // Lin
        1_002 => FnDeriv(GeoKind::Lin2, Lin2::calc_deriv),
        1_003 => FnDeriv(GeoKind::Lin3, Lin3::calc_deriv),
        1_004 => FnDeriv(GeoKind::Lin4, Lin4::calc_deriv),
        1_005 => FnDeriv(GeoKind::Lin5, Lin5::calc_deriv),
        // Tri
        2_003 => FnDeriv(GeoKind::Tri3, Tri3::calc_deriv),
        2_006 => FnDeriv(GeoKind::Tri6, Tri6::calc_deriv),
        2_010 => FnDeriv(GeoKind::Tri10, Tri10::calc_deriv),
        2_015 => FnDeriv(GeoKind::Tri15, Tri15::calc_deriv),
        // Qua
        2_004 => FnDeriv(GeoKind::Qua4, Qua4::calc_deriv),
        2_008 => FnDeriv(GeoKind::Qua8, Qua8::calc_deriv),
        2_009 => FnDeriv(GeoKind::Qua9, Qua9::calc_deriv),
        2_012 => FnDeriv(GeoKind::Qua12, Qua12::calc_deriv),
        2_016 => FnDeriv(GeoKind::Qua16, Qua16::calc_deriv),
        2_017 => FnDeriv(GeoKind::Qua17, Qua17::calc_deriv),
        // Tet
        3_004 => FnDeriv(GeoKind::Tet4, Tet4::calc_deriv),
        3_010 => FnDeriv(GeoKind::Tet10, Tet10::calc_deriv),
        // Hex
        3_008 => FnDeriv(GeoKind::Hex8, Hex8::calc_deriv),
        3_020 => FnDeriv(GeoKind::Hex20, Hex20::calc_deriv),
        _ => panic!("INTERNAL ERROR: cannot convert i32 to FnDeriv"),
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{i32_to_fn_deriv, i32_to_fn_interp};
    use crate::shapes::{GeoClass, GeoKind};
    use std::collections::HashSet;

    #[test]
    fn derive_works() {
        let class = GeoClass::Tri.clone();
        let kind = GeoKind::Tri6.clone();
        let classes = HashSet::from([GeoClass::Tri, GeoClass::Qua]);
        let kinds = HashSet::from([GeoKind::Tri3, GeoKind::Qua4]);
        assert_eq!(class, GeoClass::Tri);
        assert_eq!(kind, GeoKind::Tri6);
        assert_eq!(format!("{:?}", class), "Tri");
        assert_eq!(format!("{:?}", kind), "Tri6");
        assert_eq!(classes.contains(&GeoClass::Tri), true);
        assert_eq!(kinds.contains(&GeoKind::Tri3), true);
    }

    #[test]
    fn data_is_consistent() {
        for kind in GeoKind::VALUES {
            match kind {
                // Lin
                GeoKind::Lin2 => {
                    let k = kind as i32;
                    let nnode = k - 1000;
                    assert_eq!(nnode, 2);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Lin2);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Lin2);
                }
                GeoKind::Lin3 => {
                    let k = kind as i32;
                    let nnode = k - 1000;
                    assert_eq!(nnode, 3);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Lin3);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Lin3);
                }
                GeoKind::Lin4 => {
                    let k = kind as i32;
                    let nnode = k - 1000;
                    assert_eq!(nnode, 4);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Lin4);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Lin4);
                }
                GeoKind::Lin5 => {
                    let k = kind as i32;
                    let nnode = k - 1000;
                    assert_eq!(nnode, 5);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Lin5);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Lin5);
                }

                // Tri
                GeoKind::Tri3 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 3);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tri3);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tri3);
                }
                GeoKind::Tri6 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 6);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tri6);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tri6);
                }
                GeoKind::Tri10 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 10);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tri10);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tri10);
                }
                GeoKind::Tri15 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 15);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tri15);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tri15);
                }

                // Qua
                GeoKind::Qua4 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 4);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua4);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua4);
                }
                GeoKind::Qua8 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 8);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua8);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua8);
                }
                GeoKind::Qua9 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 9);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua9);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua9);
                }
                GeoKind::Qua12 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 12);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua12);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua12);
                }
                GeoKind::Qua16 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 16);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua16);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua16);
                }
                GeoKind::Qua17 => {
                    let k = kind as i32;
                    let nnode = k - 2000;
                    assert_eq!(nnode, 17);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Qua17);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Qua17);
                }

                // Tet
                GeoKind::Tet4 => {
                    let k = kind as i32;
                    let nnode = k - 3000;
                    assert_eq!(nnode, 4);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tet4);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tet4);
                }
                GeoKind::Tet10 => {
                    let k = kind as i32;
                    let nnode = k - 3000;
                    assert_eq!(nnode, 10);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Tet10);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Tet10);
                }

                // Hex
                GeoKind::Hex8 => {
                    let k = kind as i32;
                    let nnode = k - 3000;
                    assert_eq!(nnode, 8);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Hex8);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Hex8);
                }
                GeoKind::Hex20 => {
                    let k = kind as i32;
                    let nnode = k - 3000;
                    assert_eq!(nnode, 20);
                    assert_eq!(i32_to_fn_interp(k).0, GeoKind::Hex20);
                    assert_eq!(i32_to_fn_deriv(k).0, GeoKind::Hex20);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>deserialize 'view' bits<commit_after><|endoftext|>


<commit_before>use std::{
    collections::HashSet,
    fs::File,
    future::Future,
    io::{self, prelude::*},
    path::PathBuf,
    pin::Pin,
    str,
    sync::{mpsc, Arc, Mutex},
    task::{Context, Poll},
    thread,
};

use futures_channel::oneshot;
use futures_util::future;
use hyper::{body::to_bytes, Body, Error, Request, Response, Server, StatusCode, Uri};
use tokio::{
    net::{TcpListener, TcpStream},
    runtime,
};

// A "bomb" so when the test task exists we know when to shut down
// the server and fail if the subtask failed.
pub struct Bomb {
    iorx: Sink,
    quittx: Option<oneshot::Sender<()>>,
    #[allow(clippy::type_complexity)]
    thread: Option<thread::JoinHandle<Option<(Vec<u8>, PathBuf)>>>,
}

#[derive(Clone)]
struct Sink(Arc<Mutex<Vec<u8>>>);

impl<'a> Write for &'a Sink {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Write::write(&mut *self.0.lock().unwrap(), data)
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for Bomb {
    fn drop(&mut self) {
        drop(self.quittx.take());
        let res = self.thread.take().unwrap().join();
        let stderr = str::from_utf8(&self.iorx.0.lock().unwrap())
            .unwrap()
            .to_string();
        match res {
            Err(..) if !thread::panicking() => panic!("server subtask failed: {}", stderr),
            Err(e) => {
                if !stderr.is_empty() {
                    println!("server subtask failed ({e:?}): {stderr}")
                }
            }
            Ok(_) if thread::panicking() => {}
            Ok(None) => {}
            Ok(Some((data, file))) => {
                assert_ok!(assert_ok!(File::create(&file)).write_all(&data));
            }
        }
    }
}

fn cache_file(name: &str) -> PathBuf {
    PathBuf::from(file!())
        .parent()
        .unwrap()
        .join("http-data")
        .join(name)
}

enum Record {
    Capture(Vec<Exchange>, PathBuf),
    Replay(Vec<Exchange>),
}

pub fn proxy() -> (String, Bomb) {
    let me = thread::current().name().unwrap().to_string();
    let record = dotenv::var("RECORD").is_ok();

    let (url_tx, url_rx) = mpsc::channel();

    let data = cache_file(&me.replace("::", "_"));
    let record = if record && !data.exists() {
        Record::Capture(Vec::new(), data)
    } else if !data.exists() {
        Record::Replay(serde_json::from_slice(b"[]").unwrap())
    } else {
        let mut body = Vec::new();
        assert_ok!(assert_ok!(File::open(&data)).read_to_end(&mut body));
        Record::Replay(serde_json::from_slice(&body).unwrap())
    };

    let sink = Arc::new(Mutex::new(Vec::new()));
    let sink2 = Sink(Arc::clone(&sink));

    let (quittx, quitrx) = oneshot::channel();

    let thread = thread::spawn(move || {
        let rt = assert_ok!(runtime::Builder::new_current_thread().enable_io().build());

        let client = if let Record::Capture(_, _) = record {
            Some(hyper::Client::builder().build(hyper_tls::HttpsConnector::new()))
        } else {
            None
        };

        let listener = assert_ok!(rt.block_on(TcpListener::bind("127.0.0.1:0")));
        url_tx
            .send(format!("http://{}", assert_ok!(listener.local_addr())))
            .unwrap();

        let record = Arc::new(Mutex::new(record));
        let srv = Server::builder(hyper::server::accept::poll_fn(move |cx| {
            listener
                .poll_accept(cx)
                .map(|res| Some(res.map(|(stream, _)| stream)))
        }))
        .serve(Proxy {
            sink: sink2,
            record: Arc::clone(&record),
            client,
        })
        .with_graceful_shutdown(async {
            quitrx.await.ok();
        });

        rt.block_on(srv).ok();

        let record = record.lock().unwrap();
        match *record {
            Record::Capture(ref data, ref path) => {
                let data = assert_ok!(serde_json::to_string_pretty(data));
                Some((data.into_bytes(), path.clone()))
            }
            Record::Replay(..) => None,
        }
    });

    (
        url_rx.recv().unwrap(),
        Bomb {
            iorx: Sink(sink),
            quittx: Some(quittx),
            thread: Some(thread),
        },
    )
}

#[derive(Clone)]
struct Proxy {
    sink: Sink,
    record: Arc<Mutex<Record>>,
    client: Option<Client>,
}

impl tower_service::Service<Request<Body>> for Proxy {
    type Response = Response<Body>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Response<Body>, Error>> + Send>>;

    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Request<Body>) -> Self::Future {
        match *self.record.lock().unwrap() {
            Record::Capture(_, _) => {
                let client = self.client.as_ref().unwrap().clone();
                let record2 = self.record.clone();
                Box::pin(async move {
                    let (response, exchange) = record_http(req, client).await?;
                    if let Record::Capture(ref mut d, _) = *record2.lock().unwrap() {
                        d.push(exchange);
                    }
                    Ok(response)
                })
            }
            Record::Replay(ref mut exchanges) => {
                Box::pin(replay_http(req, exchanges.remove(0), &mut &self.sink))
            }
        }
    }
}

impl<'a> tower_service::Service<&'a TcpStream> for Proxy {
    type Response = Proxy;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Proxy, Error>> + Send + 'static>>;

    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, _: &'a TcpStream) -> Self::Future {
        Box::pin(future::ok(self.clone()))
    }
}

#[derive(Serialize, Deserialize)]
struct Exchange {
    request: RecordedRequest,
    response: RecordedResponse,
}

#[derive(Serialize, Deserialize)]
struct RecordedRequest {
    uri: String,
    method: String,
    headers: HashSet<(String, String)>,
    body: String,
}

#[derive(Serialize, Deserialize)]
struct RecordedResponse {
    status: u16,
    headers: HashSet<(String, String)>,
    body: String,
}

type Client = hyper::Client<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>;
type ResponseAndExchange = (Response<Body>, Exchange);

async fn record_http(req: Request<Body>, client: Client) -> Result<ResponseAndExchange, Error> {
    // Deconstruct the incoming request and await for the full body
    let (header_parts, body) = req.into_parts();
    let method = header_parts.method;
    let uri = header_parts.uri;
    let headers = header_parts.headers;
    let body = to_bytes(body).await?;

    // Save info on the incoming request for the exchange log
    let request = RecordedRequest {
        uri: uri.to_string(),
        method: method.to_string(),
        headers: headers
            .iter()
            .map(|h| (h.0.as_str().to_string(), h.1.to_str().unwrap().to_string()))
            .collect(),
        body: base64::encode(&body),
    };

    // Construct an outgoing request
    let uri = uri.to_string().replace("http://", "https://");
    let uri = uri.parse::<Uri>().unwrap();
    let mut req = Request::builder()
        .method(method.clone())
        .uri(uri)
        .body(body.into())
        .unwrap();
    *req.headers_mut() = headers.clone();

    // Deconstruct the incoming response and await for the full body
    let hyper_response = client.request(req).await?;
    let status = hyper_response.status();
    let headers = hyper_response.headers().clone();
    let body = to_bytes(hyper_response.into_body()).await?;

    // Save the response for the exchange log
    let response = RecordedResponse {
        status: status.as_u16(),
        headers: headers
            .iter()
            .map(|h| (h.0.as_str().to_string(), h.1.to_str().unwrap().to_string()))
            .collect(),
        body: base64::encode(&body),
    };

    // Construct an outgoing response
    let mut hyper_response = Response::builder()
        .status(status)
        .body(body.into())
        .unwrap();
    *hyper_response.headers_mut() = headers;

    Ok((hyper_response, Exchange { request, response }))
}

fn replay_http(
    req: Request<Body>,
    mut exchange: Exchange,
    stdout: &mut dyn Write,
) -> impl Future<Output = Result<Response<Body>, Error>> + Send {
    static IGNORED_HEADERS: &[&str] = &["authorization", "date", "cache-control"];

    debug!("<- {req:?}");
    assert_eq!(req.uri().to_string(), exchange.request.uri);
    assert_eq!(req.method().to_string(), exchange.request.method);
    assert_ok!(writeln!(
        stdout,
        "expecting: {:?}",
        exchange.request.headers
    ));
    for (name, value) in req.headers().iter() {
        let pair = (
            name.as_str().to_string(),
            value.to_str().unwrap().to_string(),
        );
        assert_ok!(writeln!(stdout, "received: {:?}", pair));
        if name == "user-agent" {
            assert_eq!(value, "crates.io (https://crates.io)");
            continue;
        }
        if IGNORED_HEADERS.contains(&name.as_str()) {
            continue;
        }
        if !exchange.request.headers.remove(&pair) {
            panic!("found {:?} but didn't expect it", pair);
        }
    }
    for (name, value) in exchange.request.headers.drain() {
        if IGNORED_HEADERS.contains(&name.as_str()) {
            continue;
        }
        panic!("didn't find header {:?}", (name, value));
    }

    async {
        let _ = &exchange;
        assert_eq!(
            to_bytes(req.into_body()).await.unwrap(),
            base64::decode(&exchange.request.body).unwrap()
        );

        let mut builder = Response::builder();
        for (key, value) in exchange.response.headers {
            builder = builder.header(key.as_str(), value.as_str());
        }
        let body = base64::decode(exchange.response.body.as_bytes()).unwrap();
        let status = StatusCode::from_u16(exchange.response.status).unwrap();
        let response = builder.status(status).body(body.into()).unwrap();

        debug!("-> {response:?}");
        Ok(response)
    }
}
<commit_msg>Fail a test if there are remaining exchanges in the queue<commit_after>use std::{
    collections::HashSet,
    fs::File,
    future::Future,
    io::{self, prelude::*},
    path::PathBuf,
    pin::Pin,
    str,
    sync::{mpsc, Arc, Mutex},
    task::{Context, Poll},
    thread,
};

use futures_channel::oneshot;
use futures_util::future;
use hyper::{body::to_bytes, Body, Error, Request, Response, Server, StatusCode, Uri};
use tokio::{
    net::{TcpListener, TcpStream},
    runtime,
};

// A "bomb" so when the test task exists we know when to shut down
// the server and fail if the subtask failed.
pub struct Bomb {
    iorx: Sink,
    quittx: Option<oneshot::Sender<()>>,
    #[allow(clippy::type_complexity)]
    thread: Option<thread::JoinHandle<Option<(Vec<u8>, PathBuf)>>>,
}

#[derive(Clone)]
struct Sink(Arc<Mutex<Vec<u8>>>);

impl<'a> Write for &'a Sink {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Write::write(&mut *self.0.lock().unwrap(), data)
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for Bomb {
    fn drop(&mut self) {
        drop(self.quittx.take());
        let res = self.thread.take().unwrap().join();
        let stderr = str::from_utf8(&self.iorx.0.lock().unwrap())
            .unwrap()
            .to_string();
        match res {
            Err(..) if !thread::panicking() => panic!("server subtask failed: {}", stderr),
            Err(e) => {
                if !stderr.is_empty() {
                    println!("server subtask failed ({e:?}): {stderr}")
                }
            }
            Ok(_) if thread::panicking() => {}
            Ok(None) => {}
            Ok(Some((data, file))) => {
                assert_ok!(assert_ok!(File::create(&file)).write_all(&data));
            }
        }
    }
}

fn cache_file(name: &str) -> PathBuf {
    PathBuf::from(file!())
        .parent()
        .unwrap()
        .join("http-data")
        .join(name)
}

enum Record {
    Capture(Vec<Exchange>, PathBuf),
    Replay(Vec<Exchange>),
}

pub fn proxy() -> (String, Bomb) {
    let me = thread::current().name().unwrap().to_string();
    let record = dotenv::var("RECORD").is_ok();

    let (url_tx, url_rx) = mpsc::channel();

    let data = cache_file(&me.replace("::", "_"));
    let record = if record && !data.exists() {
        Record::Capture(Vec::new(), data)
    } else if !data.exists() {
        Record::Replay(serde_json::from_slice(b"[]").unwrap())
    } else {
        let mut body = Vec::new();
        assert_ok!(assert_ok!(File::open(&data)).read_to_end(&mut body));
        Record::Replay(serde_json::from_slice(&body).unwrap())
    };

    let sink = Arc::new(Mutex::new(Vec::new()));
    let sink2 = Sink(Arc::clone(&sink));

    let (quittx, quitrx) = oneshot::channel();

    let thread = thread::spawn(move || {
        let rt = assert_ok!(runtime::Builder::new_current_thread().enable_io().build());

        let client = if let Record::Capture(_, _) = record {
            Some(hyper::Client::builder().build(hyper_tls::HttpsConnector::new()))
        } else {
            None
        };

        let listener = assert_ok!(rt.block_on(TcpListener::bind("127.0.0.1:0")));
        url_tx
            .send(format!("http://{}", assert_ok!(listener.local_addr())))
            .unwrap();

        let record = Arc::new(Mutex::new(record));
        let srv = Server::builder(hyper::server::accept::poll_fn(move |cx| {
            listener
                .poll_accept(cx)
                .map(|res| Some(res.map(|(stream, _)| stream)))
        }))
        .serve(Proxy {
            sink: sink2,
            record: Arc::clone(&record),
            client,
        })
        .with_graceful_shutdown(async {
            quitrx.await.ok();
        });

        rt.block_on(srv).ok();

        let record = record.lock().unwrap();
        match *record {
            Record::Capture(ref data, ref path) => {
                let data = assert_ok!(serde_json::to_string_pretty(data));
                Some((data.into_bytes(), path.clone()))
            }
            Record::Replay(ref remaining_exchanges) if !remaining_exchanges.is_empty() =>
                panic!(
                    "The HTTP proxy for this test received fewer requests than expected (remaining: {})",
                    remaining_exchanges.len()
                ),
            Record::Replay(..) => None,
        }
    });

    (
        url_rx.recv().unwrap(),
        Bomb {
            iorx: Sink(sink),
            quittx: Some(quittx),
            thread: Some(thread),
        },
    )
}

#[derive(Clone)]
struct Proxy {
    sink: Sink,
    record: Arc<Mutex<Record>>,
    client: Option<Client>,
}

impl tower_service::Service<Request<Body>> for Proxy {
    type Response = Response<Body>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Response<Body>, Error>> + Send>>;

    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Request<Body>) -> Self::Future {
        match *self.record.lock().unwrap() {
            Record::Capture(_, _) => {
                let client = self.client.as_ref().unwrap().clone();
                let record2 = self.record.clone();
                Box::pin(async move {
                    let (response, exchange) = record_http(req, client).await?;
                    if let Record::Capture(ref mut d, _) = *record2.lock().unwrap() {
                        d.push(exchange);
                    }
                    Ok(response)
                })
            }
            Record::Replay(ref mut exchanges) => {
                Box::pin(replay_http(req, exchanges.remove(0), &mut &self.sink))
            }
        }
    }
}

impl<'a> tower_service::Service<&'a TcpStream> for Proxy {
    type Response = Proxy;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Proxy, Error>> + Send + 'static>>;

    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, _: &'a TcpStream) -> Self::Future {
        Box::pin(future::ok(self.clone()))
    }
}

#[derive(Serialize, Deserialize)]
struct Exchange {
    request: RecordedRequest,
    response: RecordedResponse,
}

#[derive(Serialize, Deserialize)]
struct RecordedRequest {
    uri: String,
    method: String,
    headers: HashSet<(String, String)>,
    body: String,
}

#[derive(Serialize, Deserialize)]
struct RecordedResponse {
    status: u16,
    headers: HashSet<(String, String)>,
    body: String,
}

type Client = hyper::Client<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>;
type ResponseAndExchange = (Response<Body>, Exchange);

async fn record_http(req: Request<Body>, client: Client) -> Result<ResponseAndExchange, Error> {
    // Deconstruct the incoming request and await for the full body
    let (header_parts, body) = req.into_parts();
    let method = header_parts.method;
    let uri = header_parts.uri;
    let headers = header_parts.headers;
    let body = to_bytes(body).await?;

    // Save info on the incoming request for the exchange log
    let request = RecordedRequest {
        uri: uri.to_string(),
        method: method.to_string(),
        headers: headers
            .iter()
            .map(|h| (h.0.as_str().to_string(), h.1.to_str().unwrap().to_string()))
            .collect(),
        body: base64::encode(&body),
    };

    // Construct an outgoing request
    let uri = uri.to_string().replace("http://", "https://");
    let uri = uri.parse::<Uri>().unwrap();
    let mut req = Request::builder()
        .method(method.clone())
        .uri(uri)
        .body(body.into())
        .unwrap();
    *req.headers_mut() = headers.clone();

    // Deconstruct the incoming response and await for the full body
    let hyper_response = client.request(req).await?;
    let status = hyper_response.status();
    let headers = hyper_response.headers().clone();
    let body = to_bytes(hyper_response.into_body()).await?;

    // Save the response for the exchange log
    let response = RecordedResponse {
        status: status.as_u16(),
        headers: headers
            .iter()
            .map(|h| (h.0.as_str().to_string(), h.1.to_str().unwrap().to_string()))
            .collect(),
        body: base64::encode(&body),
    };

    // Construct an outgoing response
    let mut hyper_response = Response::builder()
        .status(status)
        .body(body.into())
        .unwrap();
    *hyper_response.headers_mut() = headers;

    Ok((hyper_response, Exchange { request, response }))
}

fn replay_http(
    req: Request<Body>,
    mut exchange: Exchange,
    stdout: &mut dyn Write,
) -> impl Future<Output = Result<Response<Body>, Error>> + Send {
    static IGNORED_HEADERS: &[&str] = &["authorization", "date", "cache-control"];

    debug!("<- {req:?}");
    assert_eq!(req.uri().to_string(), exchange.request.uri);
    assert_eq!(req.method().to_string(), exchange.request.method);
    assert_ok!(writeln!(
        stdout,
        "expecting: {:?}",
        exchange.request.headers
    ));
    for (name, value) in req.headers().iter() {
        let pair = (
            name.as_str().to_string(),
            value.to_str().unwrap().to_string(),
        );
        assert_ok!(writeln!(stdout, "received: {:?}", pair));
        if name == "user-agent" {
            assert_eq!(value, "crates.io (https://crates.io)");
            continue;
        }
        if IGNORED_HEADERS.contains(&name.as_str()) {
            continue;
        }
        if !exchange.request.headers.remove(&pair) {
            panic!("found {:?} but didn't expect it", pair);
        }
    }
    for (name, value) in exchange.request.headers.drain() {
        if IGNORED_HEADERS.contains(&name.as_str()) {
            continue;
        }
        panic!("didn't find header {:?}", (name, value));
    }

    async {
        let _ = &exchange;
        assert_eq!(
            to_bytes(req.into_body()).await.unwrap(),
            base64::decode(&exchange.request.body).unwrap()
        );

        let mut builder = Response::builder();
        for (key, value) in exchange.response.headers {
            builder = builder.header(key.as_str(), value.as_str());
        }
        let body = base64::decode(exchange.response.body.as_bytes()).unwrap();
        let status = StatusCode::from_u16(exchange.response.status).unwrap();
        let response = builder.status(status).body(body.into()).unwrap();

        debug!("-> {response:?}");
        Ok(response)
    }
}
<|endoftext|>