identity_document/utils/
did_url_query.rsuse std::borrow::Cow;
use identity_did::CoreDID;
use identity_did::DIDUrl;
use identity_did::RelativeDIDUrl;
use identity_did::DID;
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct DIDUrlQuery<'query>(Cow<'query, str>);
impl DIDUrlQuery<'_> {
pub(crate) fn matches(&self, did_url: &DIDUrl) -> bool {
if let Some(did_str) = self.did_str() {
if did_str != did_url.did().as_str() {
return false;
}
}
match self.fragment().zip(did_url.fragment()) {
Some((a, b)) => a == b,
None => false,
}
}
fn did_str(&self) -> Option<&str> {
let query: &str = self.0.as_ref();
if !query.starts_with(CoreDID::SCHEME) {
return None;
}
let mut end_pos: usize = query.len();
end_pos = end_pos.min(query.find('?').unwrap_or(end_pos));
end_pos = end_pos.min(query.find('/').unwrap_or(end_pos));
end_pos = end_pos.min(query.find('#').unwrap_or(end_pos));
query.get(0..end_pos)
}
fn fragment(&self) -> Option<&str> {
let query: &str = self.0.as_ref();
let fragment_maybe: Option<&str> = if query.starts_with(CoreDID::SCHEME) {
query.rfind('#').and_then(|index| query.get(index + 1..))
} else if let Some(fragment_delimiter_index) = query.rfind('#') {
query.get(fragment_delimiter_index + 1..)
} else {
Some(query)
};
fragment_maybe.filter(|fragment| !fragment.is_empty())
}
}
impl<'query> From<&'query str> for DIDUrlQuery<'query> {
fn from(other: &'query str) -> Self {
Self(Cow::Borrowed(other))
}
}
impl<'query> From<&'query String> for DIDUrlQuery<'query> {
fn from(other: &'query String) -> Self {
Self(Cow::Borrowed(&**other))
}
}
impl<'query> From<&'query DIDUrl> for DIDUrlQuery<'query> {
fn from(other: &'query DIDUrl) -> Self {
Self(Cow::Owned(other.to_string()))
}
}
impl From<DIDUrl> for DIDUrlQuery<'_> {
fn from(other: DIDUrl) -> Self {
Self(Cow::Owned(other.to_string()))
}
}
impl<'query> From<&'query RelativeDIDUrl> for DIDUrlQuery<'query> {
fn from(other: &'query RelativeDIDUrl) -> Self {
Self(Cow::Owned(other.to_string()))
}
}
#[cfg(test)]
mod tests {
use identity_did::DIDUrl;
use std::ops::Not;
use super::*;
#[test]
fn test_did_str() {
assert!(DIDUrlQuery::from("").did_str().is_none());
assert!(DIDUrlQuery::from("fragment").did_str().is_none());
assert!(DIDUrlQuery::from("#fragment").did_str().is_none());
assert!(DIDUrlQuery::from("?query").did_str().is_none());
assert!(DIDUrlQuery::from("/path").did_str().is_none());
assert!(DIDUrlQuery::from("/path?query#fragment").did_str().is_none());
assert!(DIDUrlQuery::from("method:missingscheme123").did_str().is_none());
assert!(DIDUrlQuery::from("iota:example").did_str().is_none());
assert_eq!(
DIDUrlQuery::from("did:iota:example").did_str(),
Some("did:iota:example")
);
assert_eq!(
DIDUrlQuery::from("did:iota:example#fragment").did_str(),
Some("did:iota:example")
);
assert_eq!(
DIDUrlQuery::from("did:iota:example?query").did_str(),
Some("did:iota:example")
);
assert_eq!(
DIDUrlQuery::from("did:iota:example/path").did_str(),
Some("did:iota:example")
);
assert_eq!(
DIDUrlQuery::from("did:iota:example/path?query#fragment").did_str(),
Some("did:iota:example")
);
assert_eq!(
DIDUrlQuery::from("did:iota:example/path?query&relativeRef=/#fragment").did_str(),
Some("did:iota:example")
);
}
#[test]
fn test_fragment() {
assert!(DIDUrlQuery::from("").fragment().is_none());
assert_eq!(DIDUrlQuery::from("fragment").fragment(), Some("fragment"));
assert_eq!(DIDUrlQuery::from("#fragment").fragment(), Some("fragment"));
assert_eq!(DIDUrlQuery::from("/path?query#fragment").fragment(), Some("fragment"));
assert!(DIDUrlQuery::from("did:iota:example").fragment().is_none());
assert_eq!(
DIDUrlQuery::from("did:iota:example#fragment").fragment(),
Some("fragment")
);
assert!(DIDUrlQuery::from("did:iota:example?query").fragment().is_none());
assert!(DIDUrlQuery::from("did:iota:example/path").fragment().is_none());
assert_eq!(
DIDUrlQuery::from("did:iota:example/path?query#fragment").fragment(),
Some("fragment")
);
assert_eq!(
DIDUrlQuery::from("did:iota:example/path?query&relativeRef=/#fragment").fragment(),
Some("fragment")
);
}
#[test]
fn test_matches() {
let did_base: DIDUrl = DIDUrl::parse("did:iota:example").unwrap();
let did_path: DIDUrl = DIDUrl::parse("did:iota:example/path").unwrap();
let did_query: DIDUrl = DIDUrl::parse("did:iota:example?query").unwrap();
let did_fragment: DIDUrl = DIDUrl::parse("did:iota:example#fragment").unwrap();
let did_different_fragment: DIDUrl = DIDUrl::parse("did:iota:example#differentfragment").unwrap();
let did_url: DIDUrl = DIDUrl::parse("did:iota:example/path?query#fragment").unwrap();
let did_url_complex: DIDUrl = DIDUrl::parse("did:iota:example/path?query&relativeRef=/#fragment").unwrap();
{
let query_empty = DIDUrlQuery::from("");
assert!(query_empty.matches(&did_base).not());
assert!(query_empty.matches(&did_path).not());
assert!(query_empty.matches(&did_query).not());
assert!(query_empty.matches(&did_fragment).not());
assert!(query_empty.matches(&did_different_fragment).not());
assert!(query_empty.matches(&did_url).not());
assert!(query_empty.matches(&did_url_complex).not());
}
{
let query_fragment_only = DIDUrlQuery::from("fragment");
assert!(query_fragment_only.matches(&did_base).not());
assert!(query_fragment_only.matches(&did_path).not());
assert!(query_fragment_only.matches(&did_query).not());
assert!(query_fragment_only.matches(&did_fragment));
assert!(query_fragment_only.matches(&did_different_fragment).not());
assert!(query_fragment_only.matches(&did_url));
assert!(query_fragment_only.matches(&did_url_complex));
}
{
let query_different_fragment = DIDUrlQuery::from("differentfragment");
assert!(query_different_fragment.matches(&did_base).not());
assert!(query_different_fragment.matches(&did_path).not());
assert!(query_different_fragment.matches(&did_query).not());
assert!(query_different_fragment.matches(&did_fragment).not());
assert!(query_different_fragment.matches(&did_different_fragment));
assert!(query_different_fragment.matches(&did_url).not());
assert!(query_different_fragment.matches(&did_url_complex).not());
}
{
let query_fragment_delimiter = DIDUrlQuery::from("#fragment");
assert!(query_fragment_delimiter.matches(&did_base).not());
assert!(query_fragment_delimiter.matches(&did_path).not());
assert!(query_fragment_delimiter.matches(&did_query).not());
assert!(query_fragment_delimiter.matches(&did_fragment));
assert!(query_fragment_delimiter.matches(&did_different_fragment).not());
assert!(query_fragment_delimiter.matches(&did_url));
assert!(query_fragment_delimiter.matches(&did_url_complex));
}
{
let query_relative_did_url = DIDUrlQuery::from("/path?query#fragment");
assert!(query_relative_did_url.matches(&did_base).not());
assert!(query_relative_did_url.matches(&did_path).not());
assert!(query_relative_did_url.matches(&did_query).not());
assert!(query_relative_did_url.matches(&did_fragment));
assert!(query_relative_did_url.matches(&did_different_fragment).not());
assert!(query_relative_did_url.matches(&did_url));
assert!(query_relative_did_url.matches(&did_url_complex));
}
{
let query_did = DIDUrlQuery::from("did:iota:example");
assert!(query_did.matches(&did_base).not());
assert!(query_did.matches(&did_path).not());
assert!(query_did.matches(&did_query).not());
assert!(query_did.matches(&did_fragment).not());
assert!(query_did.matches(&did_different_fragment).not());
assert!(query_did.matches(&did_url).not());
assert!(query_did.matches(&did_url_complex).not());
}
{
let query_did_fragment = DIDUrlQuery::from("did:iota:example#fragment");
assert!(query_did_fragment.matches(&did_base).not());
assert!(query_did_fragment.matches(&did_path).not());
assert!(query_did_fragment.matches(&did_query).not());
assert!(query_did_fragment.matches(&did_fragment));
assert!(query_did_fragment.matches(&did_different_fragment).not());
assert!(query_did_fragment.matches(&did_url));
assert!(query_did_fragment.matches(&did_url_complex));
}
{
let query_did_fragment = DIDUrlQuery::from("did:iota:example/path?query#fragment");
assert!(query_did_fragment.matches(&did_base).not());
assert!(query_did_fragment.matches(&did_path).not());
assert!(query_did_fragment.matches(&did_query).not());
assert!(query_did_fragment.matches(&did_fragment));
assert!(query_did_fragment.matches(&did_different_fragment).not());
assert!(query_did_fragment.matches(&did_url));
assert!(query_did_fragment.matches(&did_url_complex));
}
{
let query_did_fragment = DIDUrlQuery::from("did:iota:example/path?query&relativeRef=/#fragment");
assert!(query_did_fragment.matches(&did_base).not());
assert!(query_did_fragment.matches(&did_path).not());
assert!(query_did_fragment.matches(&did_query).not());
assert!(query_did_fragment.matches(&did_fragment));
assert!(query_did_fragment.matches(&did_different_fragment).not());
assert!(query_did_fragment.matches(&did_url));
assert!(query_did_fragment.matches(&did_url_complex));
}
}
}