use crate::{
Assertion, Envelope, EnvelopeEncodable, Error, Result,
base::envelope::EnvelopeCase, known_values,
};
impl Assertion {
pub fn new_attachment(
payload: impl EnvelopeEncodable,
vendor: &str,
conforms_to: Option<&str>,
) -> Self {
let conforms_to: Option<String> = conforms_to.map(|c| c.to_string());
Self::new(
known_values::ATTACHMENT,
payload
.into_envelope()
.wrap()
.add_assertion(known_values::VENDOR, vendor.to_string())
.add_optional_assertion(known_values::CONFORMS_TO, conforms_to),
)
}
pub fn attachment_payload(&self) -> Result<Envelope> {
self.object().try_unwrap()
}
pub fn attachment_vendor(&self) -> Result<String> {
self.object()
.extract_object_for_predicate(known_values::VENDOR)
}
pub fn attachment_conforms_to(&self) -> Result<Option<String>> {
self.object()
.extract_optional_object_for_predicate(known_values::CONFORMS_TO)
}
pub fn validate_attachment(&self) -> Result<()> {
let payload = self.attachment_payload()?;
let vendor = self.attachment_vendor()?;
let conforms_to: Option<String> = self.attachment_conforms_to()?;
let assertion = Assertion::new_attachment(
payload,
vendor.as_str(),
conforms_to.as_deref(),
);
let e: Envelope = assertion.to_envelope();
if !e.is_equivalent_to(&self.clone().to_envelope()) {
return Err(Error::InvalidAttachment);
}
Ok(())
}
}
impl Envelope {
pub fn new_attachment(
payload: impl EnvelopeEncodable,
vendor: &str,
conforms_to: Option<&str>,
) -> Self {
Assertion::new_attachment(payload, vendor, conforms_to).to_envelope()
}
pub fn add_attachment(
&self,
payload: impl EnvelopeEncodable,
vendor: &str,
conforms_to: Option<&str>,
) -> Self {
self.add_assertion_envelope(Assertion::new_attachment(
payload,
vendor,
conforms_to,
))
.unwrap()
}
}
impl Envelope {
pub fn attachment_payload(&self) -> Result<Self> {
if let EnvelopeCase::Assertion(assertion) = self.case() {
Ok(assertion.attachment_payload()?)
} else {
Err(Error::InvalidAttachment)
}
}
pub fn attachment_vendor(&self) -> Result<String> {
if let EnvelopeCase::Assertion(assertion) = self.case() {
Ok(assertion.attachment_vendor()?)
} else {
Err(Error::InvalidAttachment)
}
}
pub fn attachment_conforms_to(&self) -> Result<Option<String>> {
if let EnvelopeCase::Assertion(assertion) = self.case() {
Ok(assertion.attachment_conforms_to()?)
} else {
Err(Error::InvalidAttachment)
}
}
pub fn attachments_with_vendor_and_conforms_to(
&self,
vendor: Option<&str>,
conforms_to: Option<&str>,
) -> Result<Vec<Self>> {
let assertions =
self.assertions_with_predicate(known_values::ATTACHMENT);
for assertion in &assertions {
Self::validate_attachment(assertion)?;
}
let matching_assertions: Vec<_> = assertions
.into_iter()
.filter(|assertion| {
if let Some(vendor) = vendor
&& let Ok(v) = assertion.attachment_vendor()
&& v != vendor
{
return false;
}
if let Some(conforms_to) = conforms_to {
if let Ok(Some(c)) = assertion.attachment_conforms_to() {
if c != conforms_to {
return false;
}
} else {
return false;
}
}
true
})
.collect();
Result::Ok(matching_assertions)
}
pub fn attachments(&self) -> Result<Vec<Self>> {
self.attachments_with_vendor_and_conforms_to(None::<&str>, None::<&str>)
}
pub fn validate_attachment(&self) -> Result<()> {
if let EnvelopeCase::Assertion(assertion) = self.case() {
assertion.validate_attachment()?;
Ok(())
} else {
Err(Error::InvalidAttachment)
}
}
pub fn attachment_with_vendor_and_conforms_to(
&self,
vendor: Option<&str>,
conforms_to: Option<&str>,
) -> Result<Self> {
let attachments =
self.attachments_with_vendor_and_conforms_to(vendor, conforms_to)?;
if attachments.is_empty() {
return Err(Error::NonexistentAttachment);
}
if attachments.len() > 1 {
return Err(Error::AmbiguousAttachment);
}
Ok(attachments.first().unwrap().clone())
}
}