From 37a4b30d08f23126a0554aee9ff9713a9b06e1b6 Mon Sep 17 00:00:00 2001
From: David <dvdplm@gmail.com>
Date: Thu, 12 Jul 2018 17:43:18 +0200
Subject: [PATCH] environmental! handles generics (#307)

* Teach environmental! about generics

* whitespace
---
 substrate/substrate/environmental/src/lib.rs | 43 ++++++++++++++++----
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/substrate/substrate/environmental/src/lib.rs b/substrate/substrate/environmental/src/lib.rs
index 86e1100eccc..ff94c0c1ebb 100644
--- a/substrate/substrate/environmental/src/lib.rs
+++ b/substrate/substrate/environmental/src/lib.rs
@@ -190,33 +190,36 @@ macro_rules! environmental {
 			}
 		}
 	};
-	($name:ident : trait $t:ident) => {
-		#[allow(non_camel_case_types)]
+	($name:ident : trait @$t:ident [$($args:ty,)*]) => {
+		#[allow(non_camel_case_types, dead_code)]
 		struct $name { __private_field: () }
 
-		thread_local_impl!(static GLOBAL: $crate::imp::RefCell<Option<*mut ($t + 'static)>>
+		thread_local_impl!(static GLOBAL: $crate::imp::RefCell<Option<*mut ($t<$($args),*> + 'static)>>
 			= $crate::imp::RefCell::new(None));
 
 		impl $name {
-			#[allow(unused_imports)]
+		#[allow(unused_imports)]
 
 			pub fn using<R, F: FnOnce() -> R>(
-				protected: &mut $t,
+				protected: &mut $t<$($args),*>,
 				f: F
 			) -> R {
 				let lifetime_extended = unsafe {
-					$crate::imp::transmute::<&mut $t, &mut ($t + 'static)>(protected)
+					$crate::imp::transmute::<&mut $t<$($args),*>, &mut ($t<$($args),*> + 'static)>(protected)
 				};
 				$crate::using(&GLOBAL, lifetime_extended, f)
 			}
 
-			pub fn with<R, F: for<'a> FnOnce(&'a mut ($t + 'a)) -> R>(
+			pub fn with<R, F: for<'a> FnOnce(&'a mut ($t<$($args),*> + 'a)) -> R>(
 				f: F
 			) -> Option<R> {
 				$crate::with(&GLOBAL, |x| f(x))
 			}
 		}
-	}
+	};
+	($name:ident : trait $t:ident <>) => { environmental! { $name : trait @$t [] } };
+	($name:ident : trait $t:ident < $($args:ty),* $(,)* >) => { environmental! { $name : trait @$t [$($args,)*] } };
+	($name:ident : trait $t:ident) => { environmental! { $name : trait @$t [] } };
 }
 
 #[cfg(test)]
@@ -322,4 +325,28 @@ mod tests {
 
 		assert_eq!(got_sum, 15);
 	}
+
+	#[test]
+	fn use_generic_trait() {
+		trait Plus { fn plus42() -> usize; }
+		struct ConcretePlus;
+		impl Plus for ConcretePlus {
+			fn plus42() -> usize { 42 }
+		}
+		trait Multiplier<T: Plus> { fn mul_and_add(&self) -> usize; }
+		impl<'a, P: Plus> Multiplier<P> for &'a [usize] {
+			fn mul_and_add(&self) -> usize {
+				self.iter().fold(1, |a, c| a * c) + P::plus42()
+			}
+		}
+
+		let numbers = vec![1, 2, 3];
+		let mut numbers = &numbers[..];
+		let out = foo::using(&mut numbers, || {
+			foo::with(|x| x.mul_and_add() )
+		}).unwrap();
+
+		assert_eq!(out, 6 + 42);
+		environmental!(foo: trait Multiplier<ConcretePlus>);
+	}
 }
-- 
GitLab