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.

320 lines
7.0 KiB

  1. use std::sync::{
  2. atomic::{AtomicUsize, Ordering},
  3. Arc,
  4. };
  5. use crate::{Consumer, Driver, Executor, Folder, ParallelIterator, Reducer, WithSetup};
  6. #[derive(Copy, Clone, Eq, PartialEq)]
  7. pub enum FindMatch {
  8. Any,
  9. First,
  10. Last,
  11. }
  12. /* Find */
  13. pub struct Find<X, O> {
  14. iterator: X,
  15. operation: O,
  16. find_match: FindMatch,
  17. }
  18. impl<X, O> Find<X, O> {
  19. pub fn new(iterator: X, operation: O, find_match: FindMatch) -> Self {
  20. Self {
  21. iterator,
  22. operation,
  23. find_match,
  24. }
  25. }
  26. }
  27. impl<'a, X, O> Driver<'a, Option<X::Item>> for Find<X, O>
  28. where
  29. X: ParallelIterator<'a>,
  30. O: Fn(&X::Item) -> bool + Clone + Send + 'a,
  31. {
  32. fn exec_with<E>(self, executor: E) -> E::Result
  33. where
  34. E: Executor<'a, Option<X::Item>>,
  35. {
  36. let consumer = FindConsumer {
  37. operation: self.operation,
  38. found: Arc::new(AtomicUsize::new(0)),
  39. lower_bound: 1,
  40. upper_bound: usize::max_value(),
  41. find_match: self.find_match,
  42. };
  43. self.iterator.drive(executor, consumer)
  44. }
  45. }
  46. /* FindMap */
  47. pub struct FindMap<X, O> {
  48. iterator: X,
  49. operation: O,
  50. find_match: FindMatch,
  51. }
  52. impl<X, O> FindMap<X, O> {
  53. pub fn new(iterator: X, operation: O, find_match: FindMatch) -> Self {
  54. Self {
  55. iterator,
  56. operation,
  57. find_match,
  58. }
  59. }
  60. }
  61. impl<'a, X, O, T> Driver<'a, Option<T>> for FindMap<X, O>
  62. where
  63. X: ParallelIterator<'a>,
  64. O: Fn(X::Item) -> Option<T> + Clone + Send + 'a,
  65. T: Send + 'a,
  66. {
  67. fn exec_with<E>(self, executor: E) -> E::Result
  68. where
  69. E: Executor<'a, Option<T>>,
  70. {
  71. Find::new(
  72. self.iterator.filter_map(self.operation),
  73. |_: &T| true,
  74. self.find_match,
  75. )
  76. .exec_with(executor)
  77. }
  78. }
  79. /* Any */
  80. pub struct Any<X, O> {
  81. iterator: X,
  82. operation: O,
  83. }
  84. impl<X, O> Any<X, O> {
  85. pub fn new(iterator: X, operation: O) -> Self {
  86. Self {
  87. iterator,
  88. operation,
  89. }
  90. }
  91. }
  92. impl<'a, X, O> Driver<'a, bool, Option<bool>> for Any<X, O>
  93. where
  94. X: ParallelIterator<'a>,
  95. O: Fn(X::Item) -> bool + Clone + Send + 'a,
  96. {
  97. fn exec_with<E>(self, executor: E) -> E::Result
  98. where
  99. E: Executor<'a, bool, Option<bool>>,
  100. {
  101. let executor = executor.into_inner();
  102. let ret = Find::new(
  103. self.iterator.map(self.operation),
  104. bool::clone,
  105. FindMatch::Any,
  106. )
  107. .exec_with(executor);
  108. E::map(ret, |x| x.is_some())
  109. }
  110. }
  111. /* All */
  112. pub struct All<X, O> {
  113. iterator: X,
  114. operation: O,
  115. }
  116. impl<X, O> All<X, O> {
  117. pub fn new(iterator: X, operation: O) -> Self {
  118. Self {
  119. iterator,
  120. operation,
  121. }
  122. }
  123. }
  124. impl<'a, X, O> Driver<'a, bool, Option<bool>> for All<X, O>
  125. where
  126. X: ParallelIterator<'a>,
  127. O: Fn(X::Item) -> bool + Clone + Send + 'a,
  128. {
  129. fn exec_with<E>(self, executor: E) -> E::Result
  130. where
  131. E: Executor<'a, bool, Option<bool>>,
  132. {
  133. let executor = executor.into_inner();
  134. let ret = Find::new(
  135. self.iterator.map(self.operation),
  136. |x: &bool| !x,
  137. FindMatch::Any,
  138. )
  139. .exec_with(executor);
  140. E::map(ret, |x| x.is_none())
  141. }
  142. }
  143. /* FindConsumer */
  144. struct FindConsumer<O> {
  145. operation: O,
  146. found: Arc<AtomicUsize>,
  147. lower_bound: usize,
  148. upper_bound: usize,
  149. find_match: FindMatch,
  150. }
  151. impl<O> WithSetup for FindConsumer<O> {}
  152. impl<O, T> Consumer<T> for FindConsumer<O>
  153. where
  154. O: Fn(&T) -> bool + Clone + Send,
  155. T: Send,
  156. {
  157. type Folder = FindFolder<O, T>;
  158. type Reducer = FindReducer;
  159. type Result = Option<T>;
  160. fn split(self) -> (Self, Self, Self::Reducer) {
  161. let FindConsumer {
  162. operation,
  163. found,
  164. lower_bound,
  165. upper_bound,
  166. find_match,
  167. } = self;
  168. let mid = lower_bound + (upper_bound - lower_bound) / 2;
  169. (
  170. Self {
  171. operation: operation.clone(),
  172. found: found.clone(),
  173. lower_bound,
  174. upper_bound: mid,
  175. find_match,
  176. },
  177. Self {
  178. operation,
  179. found,
  180. lower_bound: mid,
  181. upper_bound,
  182. find_match,
  183. },
  184. FindReducer {
  185. find_match: self.find_match,
  186. },
  187. )
  188. }
  189. fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) {
  190. self.split()
  191. }
  192. fn into_folder(self) -> Self::Folder {
  193. FindFolder {
  194. operation: self.operation,
  195. found: self.found,
  196. item: None,
  197. find_match: self.find_match,
  198. lower_bound: self.lower_bound,
  199. upper_bound: self.upper_bound,
  200. }
  201. }
  202. fn is_full(&self) -> bool {
  203. self.found.load(Ordering::Relaxed) > 0
  204. }
  205. }
  206. /* FindFolder */
  207. struct FindFolder<O, T> {
  208. operation: O,
  209. found: Arc<AtomicUsize>,
  210. item: Option<T>,
  211. lower_bound: usize,
  212. upper_bound: usize,
  213. find_match: FindMatch,
  214. }
  215. impl<O, T> Folder<T> for FindFolder<O, T>
  216. where
  217. O: Fn(&T) -> bool + Clone,
  218. {
  219. type Result = Option<T>;
  220. fn consume(mut self, item: T) -> Self {
  221. match self.find_match {
  222. FindMatch::First if self.item.is_some() => return self,
  223. FindMatch::Any if self.item.is_some() => return self,
  224. _ => (),
  225. }
  226. if (self.operation)(&item) {
  227. let mut found = self.found.load(Ordering::Relaxed);
  228. loop {
  229. let boundary = match self.find_match {
  230. FindMatch::Any if found > 0 => return self,
  231. FindMatch::First if found != 0 && found < self.lower_bound => return self,
  232. FindMatch::Last if found != 0 && found > self.upper_bound => return self,
  233. FindMatch::Any => self.lower_bound,
  234. FindMatch::First => self.lower_bound,
  235. FindMatch::Last => self.upper_bound,
  236. };
  237. let ret = self.found.compare_exchange_weak(
  238. found,
  239. boundary,
  240. Ordering::Relaxed,
  241. Ordering::Relaxed,
  242. );
  243. match ret {
  244. Ok(_) => {
  245. self.item = Some(item);
  246. break;
  247. }
  248. Err(v) => found = v,
  249. }
  250. }
  251. }
  252. self
  253. }
  254. fn complete(self) -> Self::Result {
  255. self.item
  256. }
  257. fn is_full(&self) -> bool {
  258. self.found.load(Ordering::Relaxed) > 0
  259. }
  260. }
  261. /* FindReducer */
  262. struct FindReducer {
  263. find_match: FindMatch,
  264. }
  265. impl<T> Reducer<Option<T>> for FindReducer {
  266. fn reduce(self, left: Option<T>, right: Option<T>) -> Option<T> {
  267. match self.find_match {
  268. FindMatch::First => left.or(right),
  269. FindMatch::Any => left.or(right),
  270. FindMatch::Last => right.or(left),
  271. }
  272. }
  273. }