pub struct Resolver<DOC = CoreDocument, CMD = SendSyncCommand<DOC>>
where CMD: for<'r> Command<'r, Result<DOC, Error>>,
{ /* private fields */ }
Available on crate feature resolver only.
Expand description

Convenience type for resolving DID documents from different DID methods.

§Configuration

The resolver will only be able to resolve DID documents for methods it has been configured for. This is done by attaching method specific handlers with Self::attach_handler.

Implementations§

source§

impl<M, DOC> Resolver<DOC, M>
where M: for<'r> Command<'r, Result<DOC, Error>>,

source

pub fn new() -> Resolver<DOC, M>

Constructs a new Resolver.

§Example

Construct a Resolver that resolves DID documents of type CoreDocument.


let mut resolver = Resolver::<CoreDocument>::new();
// Now attach some handlers whose output can be converted to a `CoreDocument`.
source

pub async fn resolve<D>(&self, did: &D) -> Result<DOC, Error>
where D: DID,

Fetches the DID Document of the given DID.

§Errors

Errors if the resolver has not been configured to handle the method corresponding to the given DID or the resolution process itself fails.

§Example

async fn configure_and_resolve(
  did: CoreDID,
) -> std::result::Result<CoreDocument, Box<dyn std::error::Error>> {
  let resolver: Resolver = configure_resolver(Resolver::new());
  let resolved_doc: CoreDocument = resolver.resolve(&did).await?;
  Ok(resolved_doc)
}

fn configure_resolver(mut resolver: Resolver) -> Resolver {
  resolver.attach_handler("foo".to_owned(), resolve_foo);
  // Attach handlers for other DID methods we are interested in.
  resolver
}

async fn resolve_foo(did: CoreDID) -> std::result::Result<CoreDocument, std::io::Error> {
  todo!()
}
source

pub async fn resolve_multiple<D>( &self, dids: &[D] ) -> Result<HashMap<D, DOC>, Error>
where D: DID,

Concurrently fetches the DID Documents of the multiple given DIDs.

§Errors
  • If the resolver has not been configured to handle the method of any of the given DIDs.
  • If the resolution process of any DID fails.
§Note
  • If dids contains duplicates, these will be resolved only once.
source§

impl<DOC> Resolver<DOC>
where DOC: 'static,

source

pub fn attach_handler<D, F, Fut, DOCUMENT, E, DIDERR>( &mut self, method: String, handler: F )
where D: DID<Error = DIDERR> + Send + for<'r> TryFrom<&'r str> + 'static, DOCUMENT: 'static + Into<DOC>, F: Fn(D) -> Fut + 'static + Clone + Send + Sync, Fut: Future<Output = Result<DOCUMENT, E>> + Send, E: Into<Box<dyn Error + Send + Sync>>, DIDERR: Into<Box<dyn Error + Send + Sync>>,

Attach a new handler responsible for resolving DIDs of the given DID method.

The handler is expected to be a closure taking an owned DID and asynchronously returning a DID Document which can be converted to the type this Resolver is parametrized over. The handler is required to be Clone, Send, Sync and 'static hence all captured variables must satisfy these bounds. In this regard the move keyword and (possibly) wrapping values in an Arc may come in handy (see the example below).

NOTE: If there already exists a handler for this method then it will be replaced with the new handler. In the case where one would like to have a “backup handler” for the same DID method, one can achieve this with composition.

§Example

   // A client that can resolve DIDs of our invented "foo" method.
   struct Client;

   impl Client {
     // Resolves some of the DIDs we are interested in.
     async fn resolve(&self, _did: &CoreDID) -> std::result::Result<CoreDocument, std::io::Error> {
       todo!()
     }
   }

   // This way we can essentially produce (cheap) clones of our client.
   let client = std::sync::Arc::new(Client {});

   // Get a clone we can move into a handler.
   let client_clone = client.clone();

   // Construct a resolver that resolves documents of type `CoreDocument`.
   let mut resolver = Resolver::<CoreDocument>::new();

   // Now we want to attach a handler that uses the client to resolve DIDs whose method is "foo".
   resolver.attach_handler("foo".to_owned(), move |did: CoreDID| {
     // We want to resolve the did asynchronously, but since we do not know when it will be awaited we
     // let the future take ownership of the client by moving a clone into the asynchronous block.
     let future_client = client_clone.clone();
     async move { future_client.resolve(&did).await }
   });
source§

impl<DOC> Resolver<DOC, SingleThreadedCommand<DOC>>
where DOC: 'static,

source

pub fn attach_handler<D, F, Fut, DOCUMENT, E, DIDERR>( &mut self, method: String, handler: F )
where D: DID<Error = DIDERR> + for<'r> TryFrom<&'r str> + 'static, DOCUMENT: 'static + Into<DOC>, F: Fn(D) -> Fut + 'static + Clone, Fut: Future<Output = Result<DOCUMENT, E>>, E: Into<Box<dyn Error + Send + Sync>>, DIDERR: Into<Box<dyn Error + Send + Sync>>,

Attach a new handler responsible for resolving DIDs of the given DID method.

The handler is expected to be a closure taking an owned DID and asynchronously returning a DID Document which can be converted to the type this Resolver is parametrized over. The handler is required to be Clone and 'static hence all captured variables must satisfy these bounds. In this regard the move keyword and (possibly) wrapping values in an std::rc::Rc may come in handy (see the example below).

NOTE: If there already exists a handler for this method then it will be replaced with the new handler. In the case where one would like to have a “backup handler” for the same DID method, one can achieve this with composition.

§Example

   // A client that can resolve DIDs of our invented "foo" method.
   struct Client;

   impl Client {
     // Resolves some of the DIDs we are interested in.
     async fn resolve(&self, _did: &CoreDID) -> std::result::Result<CoreDocument, std::io::Error> {
       todo!()
     }
   }

   // This way we can essentially produce (cheap) clones of our client.
   let client = std::rc::Rc::new(Client {});

   // Get a clone we can move into a handler.
   let client_clone = client.clone();

   // Construct a resolver that resolves documents of type `CoreDocument`.
   let mut resolver = SingleThreadedResolver::<CoreDocument>::new();

   // Now we want to attach a handler that uses the client to resolve DIDs whose method is "foo".
   resolver.attach_handler("foo".to_owned(), move |did: CoreDID| {
     // We want to resolve the did asynchronously, but since we do not know when it will be awaited we
     // let the future take ownership of the client by moving a clone into the asynchronous block.
     let future_client = client_clone.clone();
     async move { future_client.resolve(&did).await }
   });
source§

impl<DOC> Resolver<DOC>
where DOC: From<IotaDocument> + AsRef<CoreDocument> + 'static,

source

pub fn attach_iota_handler<CLI>(&mut self, client: CLI)
where CLI: IotaIdentityClientExt + Send + Sync + 'static,

Convenience method for attaching a new handler responsible for resolving IOTA DIDs.

See also attach_handler.

source

pub fn attach_multiple_iota_handlers<CLI, I>(&mut self, clients: I)
where CLI: IotaIdentityClientExt + Send + Sync + 'static, I: IntoIterator<Item = (&'static str, CLI)>,

Convenience method for attaching multiple handlers responsible for resolving IOTA DIDs on multiple networks.

§Arguments
  • clients - A collection of tuples where each tuple contains the name of the network name and its corresponding client.
§Examples
// Assume `smr_client` and `iota_client` are instances IOTA clients `iota_sdk::client::Client`.
attach_multiple_iota_handlers(vec![("smr", smr_client), ("iota", iota_client)]);
§See Also
§Note
  • Using attach_iota_handler or attach_handler for the IOTA method would override all previously added clients.
  • This function does not validate the provided configuration. Ensure that the provided network name corresponds with the client, possibly by using client.network_name().

Trait Implementations§

source§

impl<CMD, DOC> Debug for Resolver<DOC, CMD>
where CMD: for<'r> Command<'r, Result<DOC, Error>>, DOC: AsRef<CoreDocument>,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
source§

impl<CMD, DOC> Default for Resolver<DOC, CMD>
where CMD: for<'r> Command<'r, Result<DOC, Error>>, DOC: AsRef<CoreDocument>,

source§

fn default() -> Resolver<DOC, CMD>

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<DOC, CMD> Freeze for Resolver<DOC, CMD>

§

impl<DOC, CMD> RefUnwindSafe for Resolver<DOC, CMD>
where CMD: RefUnwindSafe, DOC: RefUnwindSafe,

§

impl<DOC, CMD> Send for Resolver<DOC, CMD>
where CMD: Send, DOC: Send,

§

impl<DOC, CMD> Sync for Resolver<DOC, CMD>
where CMD: Sync, DOC: Sync,

§

impl<DOC, CMD> Unpin for Resolver<DOC, CMD>
where CMD: Unpin, DOC: Unpin,

§

impl<DOC, CMD> UnwindSafe for Resolver<DOC, CMD>
where CMD: UnwindSafe, DOC: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> ConvertTo<T> for T
where T: Send,

source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

source§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more