use super::{Url, Time};
use super::scope::Scope;
use std::borrow::{Cow, ToOwned};
use std::collections::HashMap;
use std::collections::hash_map::Iter;
use std::rc::Rc;
use std::sync::Arc;
pub trait GrantExtension {
fn identifier(&self) -> &'static str;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
Public(Option<String>),
Private(Option<String>),
}
#[derive(Clone, Default, Debug, PartialEq, Eq)]
pub struct Extensions {
extensions: HashMap<String, Value>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Grant {
pub owner_id: String,
pub client_id: String,
pub scope: Scope,
pub redirect_uri: Url,
pub until: Time,
pub extensions: Extensions,
}
impl Value {
pub fn public(content: Option<String>) -> Self {
Value::Public(content)
}
pub fn private(content: Option<String>) -> Value {
Value::Private(content)
}
pub fn as_public(self) -> Result<Option<String>, ()> {
match self {
Value::Public(content) => Ok(content),
_ => Err(())
}
}
pub fn as_private(self) -> Result<Option<String>, ()> {
match self {
Value::Private(content) => Ok(content),
_ => Err(())
}
}
}
impl Extensions {
pub fn new() -> Extensions {
Extensions::default()
}
pub fn set(&mut self, extension: &dyn GrantExtension, content: Value) {
self.extensions.insert(extension.identifier().to_string(), content);
}
pub fn set_raw(&mut self, identifier: String, content: Value) {
self.extensions.insert(identifier, content);
}
pub fn remove(&mut self, extension: &dyn GrantExtension) -> Option<Value> {
self.extensions.remove(extension.identifier())
}
#[deprecated = "Use the simpler `public` instead."]
pub fn iter_public(&self) -> PublicExtensions {
self.public()
}
pub fn public(&self) -> PublicExtensions {
PublicExtensions { iter: self.extensions.iter(), private: false }
}
#[deprecated = "The method return type is incorrect. Use the `private` method instead,
or `public` if you actually intended to iterate public extensions."]
pub fn iter_private(&self) -> PublicExtensions {
PublicExtensions { iter: self.extensions.iter(), private: true }
}
pub fn private(&self) -> PrivateExtensions {
PrivateExtensions(self.extensions.iter())
}
}
pub struct PublicExtensions<'a> {
iter: Iter<'a, String, Value>,
private: bool,
}
pub struct PrivateExtensions<'a>(Iter<'a, String, Value>);
impl PublicExtensions<'_> {
#[deprecated = "This interface should not be required and will be removed."]
pub fn is_private(&self) -> bool {
self.private
}
}
impl<'a> Iterator for PublicExtensions<'a> {
type Item = (&'a str, Option<&'a str>);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.iter.next() {
None => return None,
Some((key, Value::Public(content))) if !self.private
=> return Some((key, content.as_ref().map(String::as_str))),
Some((key, Value::Private(content))) if self.private
=> return Some((key, content.as_ref().map(String::as_str))),
_ => (),
}
}
}
}
impl<'a> Iterator for PrivateExtensions<'a> {
type Item = (&'a str, Option<&'a str>);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
None => return None,
Some((key, Value::Private(content)))
=> return Some((key, content.as_ref().map(String::as_str))),
_ => (),
}
}
}
}
impl<'a, T: GrantExtension + ?Sized> GrantExtension for &'a T {
fn identifier(&self) -> &'static str {
(**self).identifier()
}
}
impl<'a, T: GrantExtension + ?Sized> GrantExtension for Cow<'a, T>
where T: Clone + ToOwned
{
fn identifier(&self) -> &'static str {
self.as_ref().identifier()
}
}
impl<T: GrantExtension + ?Sized> GrantExtension for Box<T> {
fn identifier(&self) -> &'static str {
(**self).identifier()
}
}
impl<T: GrantExtension + ?Sized> GrantExtension for Arc<T> {
fn identifier(&self) -> &'static str {
(**self).identifier()
}
}
impl<T: GrantExtension + ?Sized> GrantExtension for Rc<T> {
fn identifier(&self) -> &'static str {
(**self).identifier()
}
}
#[cfg(test)]
mod tests {
use super::{Extensions, Value};
#[test]
#[allow(deprecated)]
fn iteration() {
let mut extensions = Extensions::new();
extensions.set_raw("pub".into(), Value::Public(Some("content".into())));
extensions.set_raw("pub_none".into(), Value::Public(None));
extensions.set_raw("priv".into(), Value::Private(Some("private".into())));
extensions.set_raw("priv_none".into(), Value::Private(None));
assert_eq!(extensions.public()
.filter(|&(name, value)| name == "pub" && value == Some("content"))
.count(), 1);
assert_eq!(extensions.iter_public()
.filter(|&(name, value)| name == "pub" && value == Some("content"))
.count(), 1);
assert_eq!(extensions.public()
.filter(|&(name, value)| name == "pub_none" && value == None)
.count(), 1);
assert_eq!(extensions.iter_public()
.filter(|&(name, value)| name == "pub_none" && value == None)
.count(), 1);
assert_eq!(extensions.public().count(), 2);
assert_eq!(extensions.private()
.filter(|&(name, value)| name == "priv" && value == Some("private"))
.count(), 1);
assert_eq!(extensions.iter_private()
.filter(|&(name, value)| name == "priv" && value == Some("private"))
.count(), 1);
assert_eq!(extensions.private()
.filter(|&(name, value)| name == "priv_none" && value == None)
.count(), 1);
assert_eq!(extensions.iter_private()
.filter(|&(name, value)| name == "priv_none" && value == None)
.count(), 1);
assert_eq!(extensions.private().count(), 2);
}
}