Async Entity Component System based on the ideas of specs (https://github.com/amethyst/specs)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
6.0 KiB

  1. use std::cmp;
  2. use std::mem::transmute;
  3. use futures::{
  4. future::{BoxFuture, Future, FutureExt},
  5. join,
  6. };
  7. use tokio::task::spawn;
  8. use crate::core::{Consumer, Executor, Folder, IndexedProducer, Producer, Reducer};
  9. pub struct Tokio {
  10. splits: usize,
  11. }
  12. impl Tokio {
  13. pub fn new(splits: usize) -> Self {
  14. Self { splits }
  15. }
  16. }
  17. impl Default for Tokio {
  18. fn default() -> Self {
  19. Self {
  20. splits: 2 * num_cpus::get(),
  21. }
  22. }
  23. }
  24. impl<'a, T1, T2, T3> Executor<'a, T1, T2, T3> for Tokio
  25. where
  26. T1: Send + 'a,
  27. T2: Send + 'a,
  28. T3: Send + 'a,
  29. {
  30. type Result = BoxFuture<'a, T1>;
  31. type Inner = Tokio;
  32. fn exec<P, C, R>(self, producer: P, consumer: C) -> Self::Result
  33. where
  34. P: Producer + 'a,
  35. C: Consumer<P::Item, Result = T1, Reducer = R> + 'a,
  36. R: Reducer<T1> + Send + 'a,
  37. {
  38. let splits = producer.splits().unwrap_or(self.splits);
  39. let splitter = Splitter::new(splits);
  40. exec(splitter, producer, consumer)
  41. }
  42. fn exec_indexed<P, C, R>(self, producer: P, consumer: C) -> Self::Result
  43. where
  44. P: IndexedProducer + 'a,
  45. C: Consumer<P::Item, Result = T1, Reducer = R> + 'a,
  46. R: Reducer<T1> + Send + 'a,
  47. {
  48. let splits = producer.splits().unwrap_or(self.splits);
  49. let splitter = IndexedSplitter::new(
  50. splits,
  51. producer.len(),
  52. producer.min_len(),
  53. producer.max_len(),
  54. );
  55. exec_indexed(splitter, producer, consumer)
  56. }
  57. fn split(self) -> (Self, Self) {
  58. let mut left = self;
  59. let right = Self {
  60. splits: left.splits / 2,
  61. };
  62. left.splits -= right.splits;
  63. (left, right)
  64. }
  65. fn join<R>(left: Self::Result, right: Self::Result, reducer: R) -> Self::Result
  66. where
  67. R: Reducer<T1> + Send + 'a,
  68. T1: 'a,
  69. {
  70. async move {
  71. let left = left.await;
  72. let right = right.await;
  73. reducer.reduce(left, right)
  74. }
  75. .boxed()
  76. }
  77. fn into_inner(self) -> Self::Inner {
  78. self
  79. }
  80. fn map<O>(
  81. inner: <Self::Inner as Executor<'a, T2, T3, ()>>::Result,
  82. operation: O,
  83. ) -> Self::Result
  84. where
  85. O: Fn(T2) -> T1 + Send + 'a,
  86. {
  87. async move {
  88. let value = inner.await;
  89. operation(value)
  90. }
  91. .boxed()
  92. }
  93. }
  94. fn exec<'a, P, C>(mut splitter: Splitter, producer: P, consumer: C) -> BoxFuture<'a, C::Result>
  95. where
  96. P: Producer + 'a,
  97. C: Consumer<P::Item> + 'a,
  98. C::Reducer: Send,
  99. {
  100. async move {
  101. if consumer.is_full() {
  102. consumer.into_folder().complete()
  103. } else if splitter.try_split() {
  104. match producer.split() {
  105. (left_producer, Some(right_producer)) => {
  106. let (left_consumer, right_consumer, reducer) = consumer.split();
  107. let left = run_as_task(exec(splitter, left_producer, left_consumer));
  108. let right = run_as_task(exec(splitter, right_producer, right_consumer));
  109. let (left_result, right_result) = join!(left, right);
  110. reducer.reduce(left_result, right_result)
  111. }
  112. (producer, None) => producer.fold_with(consumer.into_folder()).complete(),
  113. }
  114. } else {
  115. producer.fold_with(consumer.into_folder()).complete()
  116. }
  117. }
  118. .boxed()
  119. }
  120. fn exec_indexed<'a, P, C>(
  121. mut splitter: IndexedSplitter,
  122. producer: P,
  123. consumer: C,
  124. ) -> BoxFuture<'a, C::Result>
  125. where
  126. P: IndexedProducer + 'a,
  127. C: Consumer<P::Item> + 'a,
  128. C::Reducer: Send,
  129. {
  130. async move {
  131. if consumer.is_full() {
  132. consumer.into_folder().complete()
  133. } else {
  134. let len = producer.len();
  135. if splitter.try_split(len) {
  136. let mid = len / 2;
  137. let (left_producer, right_producer) = producer.split_at(mid);
  138. let (left_consumer, right_consumer, reducer) = consumer.split_at(mid);
  139. let left = run_as_task(exec_indexed(splitter, left_producer, left_consumer));
  140. let right = run_as_task(exec_indexed(splitter, right_producer, right_consumer));
  141. let (left_result, right_result) = join!(left, right);
  142. reducer.reduce(left_result, right_result)
  143. } else {
  144. producer.fold_with(consumer.into_folder()).complete()
  145. }
  146. }
  147. }
  148. .boxed()
  149. }
  150. async fn run_as_task<'a, T, F>(f: F) -> T
  151. where
  152. T: Send + 'a,
  153. F: Future<Output = T> + Send + 'a,
  154. {
  155. struct Pointer<T>(*mut T);
  156. unsafe impl<T> Send for Pointer<T> {}
  157. let mut result = None;
  158. let r = Pointer(&mut result as *mut _);
  159. let task: BoxFuture<'a, ()> = async move {
  160. unsafe {
  161. *r.0 = Some(f.await);
  162. }
  163. }
  164. .boxed();
  165. let task: BoxFuture<'static, ()> = unsafe { transmute(task) };
  166. spawn(task).await.expect("Error in tokio executor");
  167. result.unwrap()
  168. }
  169. #[derive(Clone, Copy)]
  170. struct Splitter {
  171. splits: usize,
  172. }
  173. impl Splitter {
  174. #[inline]
  175. fn new(splits: usize) -> Self {
  176. Self { splits }
  177. }
  178. #[inline]
  179. fn try_split(&mut self) -> bool {
  180. if self.splits > 0 {
  181. self.splits /= 2;
  182. true
  183. } else {
  184. false
  185. }
  186. }
  187. }
  188. #[derive(Clone, Copy)]
  189. struct IndexedSplitter {
  190. inner: Splitter,
  191. min: usize,
  192. }
  193. impl IndexedSplitter {
  194. #[inline]
  195. fn new(splits: usize, len: usize, min: Option<usize>, max: Option<usize>) -> Self {
  196. let min = min.unwrap_or_default();
  197. let mut ret = Self {
  198. inner: Splitter::new(splits),
  199. min: cmp::max(min, 1),
  200. };
  201. if let Some(max) = max {
  202. let min_splits = len / cmp::max(max, 1);
  203. if min_splits > ret.inner.splits {
  204. ret.inner.splits = min_splits;
  205. }
  206. }
  207. ret
  208. }
  209. #[inline]
  210. fn try_split(&mut self, len: usize) -> bool {
  211. len / 2 >= self.min && self.inner.try_split()
  212. }
  213. }