Modify GetToken::token.

Change it to accept an iterator of items that can be converted to
`String`s rather than an iterator of items that can be referenced as
`&str`s.

Primarily this allows it to be called with a larger variety of inputs.
For example ::std::env::args().skip(1) can now be passed directly to
token, where before it would first need to be collected into a vector.

Since all implementations unconditionally collected the iterator into a
vector this shouldn't have any negative impact on performance and should
actually reduce the number of allocations in some uses.

It simplifies the signature since the lifetime bounds are no longer
required.
This commit is contained in:
Glenn Griffin
2019-08-08 14:21:21 -07:00
parent 460af32922
commit 2b18f3679e
6 changed files with 32 additions and 36 deletions

View File

@@ -85,13 +85,13 @@ impl<
self.inner.lock().unwrap().application_secret()
}
fn token<'b, I, T>(
fn token<I, T>(
&mut self,
scopes: I,
) -> Box<dyn Future<Item = Token, Error = RequestError> + Send>
where
T: AsRef<str> + Ord + 'b,
I: Iterator<Item = &'b T>,
T: Into<String>,
I: IntoIterator<Item = T>,
{
let (scope_key, scopes) = hash_scopes(scopes);
let store = self.store.clone();

View File

@@ -44,15 +44,15 @@ impl<
C: hyper::client::connect::Connect + Sync + 'static,
> GetToken for DeviceFlow<FD, C>
{
fn token<'b, I, T>(
fn token<I, T>(
&mut self,
scopes: I,
) -> Box<dyn Future<Item = Token, Error = RequestError> + Send>
where
T: AsRef<str> + Ord + 'b,
I: Iterator<Item = &'b T>,
T: Into<String>,
I: IntoIterator<Item = T>,
{
self.retrieve_device_token(Vec::from_iter(scopes.map(|s| s.as_ref().to_string())))
self.retrieve_device_token(Vec::from_iter(scopes.into_iter().map(Into::into)))
}
fn api_key(&mut self) -> Option<String> {
None
@@ -413,7 +413,7 @@ mod tests {
.create();
let fut = flow
.token(vec!["https://www.googleapis.com/scope/1"].iter())
.token(vec!["https://www.googleapis.com/scope/1"])
.then(|token| {
let token = token.unwrap();
assert_eq!("accesstoken", token.access_token);
@@ -445,7 +445,7 @@ mod tests {
.create();
let fut = flow
.token(vec!["https://www.googleapis.com/scope/1"].iter())
.token(vec!["https://www.googleapis.com/scope/1"])
.then(|token| {
assert!(token.is_err());
assert!(format!("{}", token.unwrap_err()).contains("invalid_client_id"));
@@ -476,7 +476,7 @@ mod tests {
.create();
let fut = flow
.token(vec!["https://www.googleapis.com/scope/1"].iter())
.token(vec!["https://www.googleapis.com/scope/1"])
.then(|token| {
assert!(token.is_err());
assert!(format!("{}", token.unwrap_err()).contains("Access denied by user"));

View File

@@ -61,15 +61,15 @@ where
impl<FD: FlowDelegate + 'static + Send + Clone, C: hyper::client::connect::Connect + 'static>
GetToken for InstalledFlow<FD, C>
{
fn token<'b, I, T>(
fn token<I, T>(
&mut self,
scopes: I,
) -> Box<dyn Future<Item = Token, Error = RequestError> + Send>
where
T: AsRef<str> + Ord + 'b,
I: Iterator<Item = &'b T>,
T: Into<String>,
I: IntoIterator<Item = T>,
{
Box::new(self.obtain_token(scopes.into_iter().map(|s| s.as_ref().to_string()).collect()))
Box::new(self.obtain_token(scopes.into_iter().map(Into::into).collect()))
}
fn api_key(&mut self) -> Option<String> {
None
@@ -625,7 +625,7 @@ mod tests {
.create();
let fut = inf
.token(vec!["https://googleapis.com/some/scope"].iter())
.token(vec!["https://googleapis.com/some/scope"])
.and_then(|tok| {
assert_eq!("accesstoken", tok.access_token);
assert_eq!("refreshtoken", tok.refresh_token);
@@ -653,7 +653,7 @@ mod tests {
.create();
let fut = inf
.token(vec!["https://googleapis.com/some/scope"].iter())
.token(vec!["https://googleapis.com/some/scope"])
.and_then(|tok| {
assert_eq!("accesstoken", tok.access_token);
assert_eq!("refreshtoken", tok.refresh_token);
@@ -675,7 +675,7 @@ mod tests {
.create();
let fut = inf
.token(vec!["https://googleapis.com/some/scope"].iter())
.token(vec!["https://googleapis.com/some/scope"])
.then(|tokr| {
assert!(tokr.is_err());
assert!(format!("{}", tokr.unwrap_err()).contains("invalid_code"));

View File

@@ -315,13 +315,13 @@ impl<C: 'static> GetToken for ServiceAccountAccess<C>
where
C: hyper::client::connect::Connect,
{
fn token<'b, I, T>(
fn token<I, T>(
&mut self,
scopes: I,
) -> Box<dyn Future<Item = Token, Error = RequestError> + Send>
where
T: AsRef<str> + Ord + 'b,
I: Iterator<Item = &'b T>,
T: Into<String>,
I: IntoIterator<Item = T>,
{
let (hash, scps0) = hash_scopes(scopes);
let cache = self.cache.clone();
@@ -443,7 +443,7 @@ mod tests {
.create();
let mut acc = ServiceAccountAccess::new(key.clone(), client.clone());
let fut = acc
.token(vec!["https://www.googleapis.com/auth/pubsub"].iter())
.token(vec!["https://www.googleapis.com/auth/pubsub"])
.and_then(|tok| {
assert!(tok.access_token.contains("ya29.c.ElouBywiys0Ly"));
assert_eq!(Some(3600), tok.expires_in);
@@ -463,7 +463,7 @@ mod tests {
.is_some());
// Test that token is in cache (otherwise mock will tell us)
let fut = acc
.token(vec!["https://www.googleapis.com/auth/pubsub"].iter())
.token(vec!["https://www.googleapis.com/auth/pubsub"])
.and_then(|tok| {
assert!(tok.access_token.contains("ya29.c.ElouBywiys0Ly"));
assert_eq!(Some(3600), tok.expires_in);
@@ -482,7 +482,7 @@ mod tests {
.create();
let mut acc = ServiceAccountAccess::new(key.clone(), client.clone());
let fut = acc
.token(vec!["https://www.googleapis.com/auth/pubsub"].iter())
.token(vec!["https://www.googleapis.com/auth/pubsub"])
.then(|result| {
assert!(result.is_err());
Ok(()) as Result<(), ()>
@@ -509,7 +509,7 @@ mod tests {
let mut acc = ServiceAccountAccess::new(key, client);
println!(
"{:?}",
acc.token(vec!["https://www.googleapis.com/auth/pubsub"].iter())
acc.token(vec!["https://www.googleapis.com/auth/pubsub"])
.wait()
);
}

View File

@@ -35,19 +35,15 @@ pub trait TokenStorage {
}
/// Calculate a hash value describing the scopes, and return a sorted Vec of the scopes.
pub fn hash_scopes<'a, I, T>(scopes: I) -> (u64, Vec<String>)
pub fn hash_scopes<I, T>(scopes: I) -> (u64, Vec<String>)
where
T: AsRef<str> + Ord + 'a,
I: IntoIterator<Item = &'a T>,
T: Into<String>,
I: IntoIterator<Item = T>,
{
let mut sv: Vec<&str> = scopes
.into_iter()
.map(|s| s.as_ref())
.collect::<Vec<&str>>();
let mut sv: Vec<String> = scopes.into_iter().map(Into::into).collect();
sv.sort();
let mut sh = DefaultHasher::new();
&sv.hash(&mut sh);
let sv = sv.iter().map(|s| s.to_string()).collect();
sv.hash(&mut sh);
(sh.finish(), sv)
}

View File

@@ -240,13 +240,13 @@ impl FromStr for Scheme {
/// The `api_key()` method is an alternative in case there are no scopes or
/// if no user is involved.
pub trait GetToken {
fn token<'b, I, T>(
fn token<I, T>(
&mut self,
scopes: I,
) -> Box<dyn Future<Item = Token, Error = RequestError> + Send>
where
T: AsRef<str> + Ord + 'b,
I: Iterator<Item = &'b T>;
T: Into<String>,
I: IntoIterator<Item = T>;
fn api_key(&mut self) -> Option<String>;