use core::marker::PhantomData;
use crate::base::header::{offsets, Header, HEADER_LEN};
use crate::base::{Encode, NewBody};
use crate::crypto;
use crate::options::{Options, OptionsList};
use crate::types::*;
use super::container::Container;
use super::header::WireHeader;
pub struct Init;
pub struct SetBody;
pub struct SetPrivateOptions;
pub struct SetPublicOptions;
pub struct Sign;
pub trait EncodeEncrypted {
fn encode<B: MutableData>(
&self,
buf: B,
secret_key: Option<&SecretKey>,
) -> Result<usize, Error>;
}
pub struct Builder<S, T: MutableData> {
buf: T,
n: usize,
c: usize,
_s: PhantomData<S>,
}
impl<S, T: MutableData> Builder<S, T> {
pub fn id(mut self, id: &Id) -> Self {
let d = self.buf.as_mut();
d[HEADER_LEN..HEADER_LEN + ID_LEN].clone_from_slice(id);
self
}
pub fn header_mut(&mut self) -> WireHeader<&mut [u8]> {
WireHeader::new(&mut self.buf.as_mut()[..HEADER_LEN])
}
}
impl<T: MutableData> Builder<Init, T> {
pub fn new(buf: T) -> Self {
Builder {
buf,
n: 0,
c: 0,
_s: PhantomData,
}
}
pub fn header(mut self, header: &Header) -> Self {
self.header_mut().encode(header);
self
}
pub fn body<B: ImmutableData>(
mut self,
body: &NewBody<B>,
secret_key: Option<&SecretKey>,
) -> Result<Builder<SetPrivateOptions, T>, Error> {
let b = self.buf.as_mut();
self.n = offsets::BODY;
let body_len = body.encode(&mut b[self.n..], secret_key)?;
self.n += body_len;
self.header_mut().set_data_len(body_len);
Ok(Builder {
buf: self.buf,
n: self.n,
c: 0,
_s: PhantomData,
})
}
}
impl<T: MutableData> Builder<SetPrivateOptions, T> {
pub fn private_options<C: AsRef<[Options]>, E: ImmutableData>(
mut self,
options: &OptionsList<C, E>,
secret_key: Option<&SecretKey>,
) -> Result<Builder<SetPublicOptions, T>, Error> {
let b = self.buf.as_mut();
let n = options.encode(&mut b[self.n..], secret_key)?;
self.n += n;
self.header_mut().set_private_options_len(n);
Ok(Builder {
buf: self.buf,
n: self.n,
c: 0,
_s: PhantomData,
})
}
}
impl<T: MutableData> Builder<SetPublicOptions, T> {
pub fn public_options<C: AsRef<[Options]>, E: ImmutableData>(
mut self,
options: &OptionsList<C, E>,
) -> Result<Builder<SetPublicOptions, T>, Error> {
let b = self.buf.as_mut();
let n = options.encode(&mut b[self.n..], None)?;
self.n += n;
self.c += n;
let c = self.c;
self.header_mut().set_public_options_len(c);
Ok(self)
}
pub fn public_option(&mut self, option: &Options) -> Result<(), Error> {
let b = self.buf.as_mut();
let n = option.encode(&mut b[self.n..])?;
self.n += n;
self.c += n;
let c = self.c;
self.header_mut().set_public_options_len(c);
Ok(())
}
pub fn sign(mut self, signing_key: &PrivateKey) -> Result<Container<T>, Error> {
let b = self.buf.as_mut();
let sig = crypto::pk_sign(signing_key, &b[..self.n]).unwrap();
&b[self.n..self.n + SIGNATURE_LEN].copy_from_slice(&sig);
self.n += SIGNATURE_LEN;
Ok(Container {
buff: self.buf,
len: self.n,
})
}
}
impl<T: ImmutableData> EncodeEncrypted for NewBody<T> {
fn encode<B: MutableData>(
&self,
mut buf: B,
secret_key: Option<&SecretKey>,
) -> Result<usize, Error> {
let b = buf.as_mut();
let n = match self {
NewBody::Cleartext(clear) => {
let c = clear.as_ref();
b[..c.len()].copy_from_slice(c);
if let Some(sk) = secret_key {
crypto::sk_encrypt2(sk, b, c.len()).unwrap()
} else {
c.len()
}
}
NewBody::Encrypted(enc) => {
let e = enc.as_ref();
b[..e.len()].copy_from_slice(e);
e.len()
}
NewBody::None => 0,
};
Ok(n)
}
}
impl<C: AsRef<[Options]>, E: ImmutableData> EncodeEncrypted for OptionsList<C, E> {
fn encode<B: MutableData>(
&self,
mut buf: B,
secret_key: Option<&SecretKey>,
) -> Result<usize, Error> {
let n = match self {
OptionsList::Cleartext(opts) => {
let mut n = Options::encode_vec(opts.as_ref(), buf.as_mut())?;
if let Some(sk) = secret_key {
n = crypto::sk_encrypt2(sk, buf.as_mut(), n).unwrap();
}
n
}
OptionsList::Encrypted(enc) => {
let b = buf.as_mut();
let e = enc.as_ref();
b[..e.len()].copy_from_slice(e.as_ref());
e.as_ref().len()
}
OptionsList::None => 0,
};
Ok(n)
}
}