File tree Expand file tree Collapse file tree 2 files changed +107
-0
lines changed Expand file tree Collapse file tree 2 files changed +107
-0
lines changed Original file line number Diff line number Diff line change 1+ use std:: pin:: Pin ;
2+
3+ use pin_project_lite:: pin_project;
4+
5+ use crate :: stream:: Stream ;
6+ use crate :: task:: { Context , Poll } ;
7+
8+ pin_project ! {
9+ /// A stream that will repeatedly yield the same list of elements
10+ pub struct Cycle <S , T > {
11+ #[ pin]
12+ source: S ,
13+ index: usize ,
14+ buffer: Vec <T >,
15+ state: CycleState ,
16+ }
17+ }
18+
19+ #[ derive( Eq , PartialEq ) ]
20+ enum CycleState {
21+ FromStream ,
22+ FromBuffer ,
23+ }
24+
25+ impl < S > Cycle < S , S :: Item >
26+ where
27+ S : Stream ,
28+ S :: Item : Clone ,
29+ {
30+ pub fn new ( source : S ) -> Cycle < S , S :: Item > {
31+ Cycle {
32+ source,
33+ index : 0 ,
34+ buffer : Vec :: new ( ) ,
35+ state : CycleState :: FromStream ,
36+ }
37+ }
38+ }
39+
40+ impl < S > Stream for Cycle < S , S :: Item >
41+ where
42+ S : Stream ,
43+ S :: Item : Clone ,
44+ {
45+ type Item = S :: Item ;
46+
47+ fn poll_next ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
48+ let this = self . project ( ) ;
49+
50+ let mut next;
51+ if * this. state == CycleState :: FromStream {
52+ next = futures_core:: ready!( this. source. poll_next( cx) ) ;
53+
54+ if let Some ( val) = next {
55+ this. buffer . push ( val. clone ( ) ) ;
56+ next = Some ( val)
57+ } else {
58+ * this. state = CycleState :: FromBuffer ;
59+ next = this. buffer . get ( * this. index ) . cloned ( ) ;
60+ }
61+ } else {
62+ let mut index = * this. index ;
63+ if index == this. buffer . len ( ) {
64+ index = 0
65+ }
66+ next = Some ( this. buffer [ index] . clone ( ) ) ;
67+
68+ * this. index = index + 1 ;
69+ }
70+
71+ Poll :: Ready ( next)
72+ }
73+ }
Original file line number Diff line number Diff line change @@ -27,6 +27,7 @@ mod chain;
2727mod cloned;
2828mod cmp;
2929mod copied;
30+ mod cycle;
3031mod enumerate;
3132mod eq;
3233mod filter;
@@ -66,6 +67,7 @@ mod zip;
6667use all:: AllFuture ;
6768use any:: AnyFuture ;
6869use cmp:: CmpFuture ;
70+ use cycle:: Cycle ;
6971use enumerate:: Enumerate ;
7072use eq:: EqFuture ;
7173use filter_map:: FilterMap ;
@@ -448,6 +450,38 @@ extension_trait! {
448450 Copied :: new( self )
449451 }
450452
453+ #[ doc = r#"
454+ Creates a stream that yields the provided values infinitely and in order.
455+
456+ # Examples
457+
458+ Basic usage:
459+
460+ ```
461+ # async_std::task::block_on(async {
462+ #
463+ use async_std::prelude::*;
464+ use async_std::stream;
465+
466+ let mut s = stream::once(7).cycle();
467+
468+ assert_eq!(s.next().await, Some(7));
469+ assert_eq!(s.next().await, Some(7));
470+ assert_eq!(s.next().await, Some(7));
471+ assert_eq!(s.next().await, Some(7));
472+ assert_eq!(s.next().await, Some(7));
473+ #
474+ # })
475+ ```
476+ "# ]
477+ fn cycle( self ) -> Cycle <Self , Self :: Item >
478+ where
479+ Self : Sized ,
480+ Self :: Item : Clone ,
481+ {
482+ Cycle :: new( self )
483+ }
484+
451485 #[ doc = r#"
452486 Creates a stream that gives the current element's count as well as the next value.
453487
You can’t perform that action at this time.
0 commit comments