use rand;
use {Method, Attribute, Error};
use types::TransactionId;
use method::{Requestable, Indicatable};
use rfc5389::attributes::ErrorCode;
use types::TryAsRef;
pub use self::raw::{RawMessage, Class};
mod raw;
pub trait Message {
type Method: Method;
type Attribute: Attribute;
fn get_class(&self) -> Class;
fn get_method(&self) -> &Self::Method;
fn get_transaction_id(&self) -> &TransactionId;
fn get_attributes(&self) -> &[Self::Attribute];
fn get_attribute<A>(&self) -> Option<&A>
where Self::Attribute: TryAsRef<A>
{
self.get_attributes().iter().filter_map(|a| a.try_as_ref()).nth(0)
}
fn try_to_raw(&self) -> Result<RawMessage, Error> {
let mut raw = RawMessage::new(self.get_class(),
self.get_method().as_u12(),
self.get_transaction_id().clone(),
Vec::new());
for attr in self.get_attributes() {
let raw_attr = track_try!(attr.try_to_raw(&raw));
raw.push_attribute(raw_attr);
}
Ok(raw)
}
}
pub type Response<M, A> = Result<SuccessResponse<M, A>, ErrorResponse<M, A>>;
impl<M: Method, A: Attribute> Message for Response<M, A> {
type Method = M;
type Attribute = A;
fn get_class(&self) -> Class {
self.as_ref().map(|r| r.get_class()).unwrap_or_else(|r| r.get_class())
}
fn get_method(&self) -> &Self::Method {
self.as_ref().map(|r| r.get_method()).unwrap_or_else(|r| r.get_method())
}
fn get_transaction_id(&self) -> &TransactionId {
self.as_ref().map(|r| r.get_transaction_id()).unwrap_or_else(|r| r.get_transaction_id())
}
fn get_attributes(&self) -> &[Self::Attribute] {
self.as_ref().map(|r| r.get_attributes()).unwrap_or_else(|r| r.get_attributes())
}
}
#[derive(Debug, Clone)]
pub struct Request<M, A> {
method: M,
transaction_id: TransactionId,
attributes: Vec<A>,
}
impl<M, A> Request<M, A>
where M: Method,
A: Attribute
{
pub fn new(method: M) -> Self
where M: Requestable
{
Request {
method: method,
transaction_id: rand::random(),
attributes: Vec::new(),
}
}
pub fn add_attribute<T: Into<A>>(&mut self, attribute: T) -> &mut Self {
self.attributes.push(attribute.into());
self
}
pub fn with_attribute<T: Into<A>>(mut self, attribute: T) -> Self {
self.add_attribute(attribute);
self
}
pub fn method(&self) -> &M {
&self.method
}
pub fn transaction_id(&self) -> &TransactionId {
&self.transaction_id
}
pub fn attributes(&self) -> &[A] {
&self.attributes
}
pub fn into_success_response(self) -> SuccessResponse<M, A> {
SuccessResponse::new(self.method, self.transaction_id)
}
pub fn into_error_response(self) -> ErrorResponse<M, A> {
ErrorResponse::new(self.method, self.transaction_id)
}
}
impl<M: Method, A: Attribute> Message for Request<M, A> {
type Method = M;
type Attribute = A;
fn get_class(&self) -> Class {
Class::Request
}
fn get_method(&self) -> &Self::Method {
self.method()
}
fn get_transaction_id(&self) -> &TransactionId {
self.transaction_id()
}
fn get_attributes(&self) -> &[Self::Attribute] {
self.attributes()
}
}
#[derive(Debug, Clone)]
pub struct Indication<M, A> {
method: M,
transaction_id: TransactionId,
attributes: Vec<A>,
}
impl<M, A> Indication<M, A>
where M: Method,
A: Attribute
{
pub fn new(method: M) -> Self
where M: Indicatable
{
Indication {
method: method,
transaction_id: rand::random(),
attributes: Vec::new(),
}
}
pub fn add_attribute<T: Into<A>>(&mut self, attribute: T) -> &mut Self {
self.attributes.push(attribute.into());
self
}
pub fn with_attribute<T: Into<A>>(mut self, attribute: T) -> Self {
self.add_attribute(attribute);
self
}
pub fn method(&self) -> &M {
&self.method
}
pub fn transaction_id(&self) -> &TransactionId {
&self.transaction_id
}
pub fn attributes(&self) -> &[A] {
&self.attributes
}
}
impl<M: Method, A: Attribute> Message for Indication<M, A> {
type Method = M;
type Attribute = A;
fn get_class(&self) -> Class {
Class::Indication
}
fn get_method(&self) -> &Self::Method {
self.method()
}
fn get_transaction_id(&self) -> &TransactionId {
self.transaction_id()
}
fn get_attributes(&self) -> &[Self::Attribute] {
self.attributes()
}
}
#[derive(Debug, Clone)]
pub struct SuccessResponse<M, A> {
method: M,
transaction_id: TransactionId,
attributes: Vec<A>,
}
impl<M, A> SuccessResponse<M, A>
where M: Method,
A: Attribute
{
fn new(method: M, transaction_id: TransactionId) -> Self {
SuccessResponse {
method: method,
transaction_id: transaction_id,
attributes: Vec::new(),
}
}
pub fn add_attribute<T: Into<A>>(&mut self, attribute: T) -> &mut Self {
self.attributes.push(attribute.into());
self
}
pub fn with_attribute<T: Into<A>>(mut self, attribute: T) -> Self {
self.add_attribute(attribute);
self
}
pub fn method(&self) -> &M {
&self.method
}
pub fn transaction_id(&self) -> &TransactionId {
&self.transaction_id
}
pub fn attributes(&self) -> &[A] {
&self.attributes
}
}
impl<M: Method, A: Attribute> Message for SuccessResponse<M, A> {
type Method = M;
type Attribute = A;
fn get_class(&self) -> Class {
Class::SuccessResponse
}
fn get_method(&self) -> &Self::Method {
self.method()
}
fn get_transaction_id(&self) -> &TransactionId {
self.transaction_id()
}
fn get_attributes(&self) -> &[Self::Attribute] {
self.attributes()
}
}
#[derive(Debug, Clone)]
pub struct ErrorResponse<M, A> {
method: M,
transaction_id: TransactionId,
attributes: Vec<A>,
}
impl<M, A> ErrorResponse<M, A>
where M: Method,
A: Attribute
{
fn new(method: M, transaction_id: TransactionId) -> Self {
ErrorResponse {
method: method,
transaction_id: transaction_id,
attributes: Vec::new(),
}
}
pub fn add_attribute<T: Into<A>>(&mut self, attribute: T) -> &mut Self {
self.attributes.push(attribute.into());
self
}
pub fn with_attribute<T: Into<A>>(mut self, attribute: T) -> Self {
self.add_attribute(attribute);
self
}
pub fn with_error_code<T: Into<ErrorCode>>(self, error_code: T) -> Self
where A: From<ErrorCode>
{
self.with_attribute(error_code.into())
}
pub fn method(&self) -> &M {
&self.method
}
pub fn transaction_id(&self) -> &TransactionId {
&self.transaction_id
}
pub fn attributes(&self) -> &[A] {
&self.attributes
}
}
impl<M: Method, A: Attribute> Message for ErrorResponse<M, A> {
type Method = M;
type Attribute = A;
fn get_class(&self) -> Class {
Class::ErrorResponse
}
fn get_method(&self) -> &Self::Method {
self.method()
}
fn get_transaction_id(&self) -> &TransactionId {
self.transaction_id()
}
fn get_attributes(&self) -> &[Self::Attribute] {
self.attributes()
}
}