1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'dart:ui';
6library;
7
8import 'dart:collection';
9
10// COMMON SIGNATURES
11
12/// Signature for callbacks that report that an underlying value has changed.
13///
14/// See also:
15///
16/// * [ValueSetter], for callbacks that report that a value has been set.
17typedef ValueChanged<T> = void Function(T value);
18
19/// Signature for callbacks that report that a value has been set.
20///
21/// This is the same signature as [ValueChanged], but is used when the
22/// callback is called even if the underlying value has not changed.
23/// For example, service extensions use this callback because they
24/// call the callback whenever the extension is called with a
25/// value, regardless of whether the given value is new or not.
26///
27/// See also:
28///
29/// * [ValueGetter], the getter equivalent of this signature.
30/// * [AsyncValueSetter], an asynchronous version of this signature.
31typedef ValueSetter<T> = void Function(T value);
32
33/// Signature for callbacks that are to report a value on demand.
34///
35/// See also:
36///
37/// * [ValueSetter], the setter equivalent of this signature.
38/// * [AsyncValueGetter], an asynchronous version of this signature.
39typedef ValueGetter<T> = T Function();
40
41/// Signature for callbacks that filter an iterable.
42typedef IterableFilter<T> = Iterable<T> Function(Iterable<T> input);
43
44/// Signature of callbacks that have no arguments and return no data, but that
45/// return a [Future] to indicate when their work is complete.
46///
47/// See also:
48///
49/// * [VoidCallback], a synchronous version of this signature.
50/// * [AsyncValueGetter], a signature for asynchronous getters.
51/// * [AsyncValueSetter], a signature for asynchronous setters.
52typedef AsyncCallback = Future<void> Function();
53
54/// Signature for callbacks that report that a value has been set and return a
55/// [Future] that completes when the value has been saved.
56///
57/// See also:
58///
59/// * [ValueSetter], a synchronous version of this signature.
60/// * [AsyncValueGetter], the getter equivalent of this signature.
61typedef AsyncValueSetter<T> = Future<void> Function(T value);
62
63/// Signature for callbacks that are to asynchronously report a value on demand.
64///
65/// See also:
66///
67/// * [ValueGetter], a synchronous version of this signature.
68/// * [AsyncValueSetter], the setter equivalent of this signature.
69typedef AsyncValueGetter<T> = Future<T> Function();
70
71// LAZY CACHING ITERATOR
72
73/// A lazy caching version of [Iterable].
74///
75/// This iterable is efficient in the following ways:
76///
77/// * It will not walk the given iterator more than you ask for.
78///
79/// * If you use it twice (e.g. you check [isNotEmpty], then
80/// use [single]), it will only walk the given iterator
81/// once. This caching will even work efficiently if you are
82/// running two side-by-side iterators on the same iterable.
83///
84/// * [toList] uses its EfficientLength variant to create its
85/// list quickly.
86///
87/// It is inefficient in the following ways:
88///
89/// * The first iteration through has caching overhead.
90///
91/// * It requires more memory than a non-caching iterator.
92///
93/// * The [length] and [toList] properties immediately pre-cache the
94/// entire list. Using these fields therefore loses the laziness of
95/// the iterable. However, it still gets cached.
96///
97/// The caching behavior is propagated to the iterators that are
98/// created by [map], [where], [expand], [take], [takeWhile], [skip],
99/// and [skipWhile], and is used by the built-in methods that use an
100/// iterator like [isNotEmpty] and [single].
101///
102/// Because a CachingIterable only walks the underlying data once, it
103/// cannot be used multiple times with the underlying data changing
104/// between each use. You must create a new iterable each time. This
105/// also applies to any iterables derived from this one, e.g. as
106/// returned by `where`.
107class CachingIterable<E> extends IterableBase<E> {
108 /// Creates a [CachingIterable] using the given [Iterator] as the source of
109 /// data. The iterator must not throw exceptions.
110 ///
111 /// Since the argument is an [Iterator], not an [Iterable], it is
112 /// guaranteed that the underlying data set will only be walked
113 /// once. If you have an [Iterable], you can pass its [iterator]
114 /// field as the argument to this constructor.
115 ///
116 /// You can this with an existing `sync*` function as follows:
117 ///
118 /// ```dart
119 /// Iterable<int> range(int start, int end) sync* {
120 /// for (int index = start; index <= end; index += 1) {
121 /// yield index;
122 /// }
123 /// }
124 ///
125 /// Iterable<int> i = CachingIterable<int>(range(1, 5).iterator);
126 /// print(i.length); // walks the list
127 /// print(i.length); // efficient
128 /// ```
129 ///
130 /// Beware that this will eagerly evaluate the `range` iterable, and because
131 /// of that it would be better to just implement `range` as something that
132 /// returns a `List` to begin with if possible.
133 CachingIterable(this._prefillIterator);
134
135 final Iterator<E> _prefillIterator;
136 final List<E> _results = <E>[];
137
138 @override
139 Iterator<E> get iterator {
140 return _LazyListIterator<E>(this);
141 }
142
143 @override
144 Iterable<T> map<T>(T Function(E e) toElement) {
145 return CachingIterable<T>(super.map<T>(toElement).iterator);
146 }
147
148 @override
149 Iterable<E> where(bool Function(E element) test) {
150 return CachingIterable<E>(super.where(test).iterator);
151 }
152
153 @override
154 Iterable<T> expand<T>(Iterable<T> Function(E element) toElements) {
155 return CachingIterable<T>(super.expand<T>(toElements).iterator);
156 }
157
158 @override
159 Iterable<E> take(int count) {
160 return CachingIterable<E>(super.take(count).iterator);
161 }
162
163 @override
164 Iterable<E> takeWhile(bool Function(E value) test) {
165 return CachingIterable<E>(super.takeWhile(test).iterator);
166 }
167
168 @override
169 Iterable<E> skip(int count) {
170 return CachingIterable<E>(super.skip(count).iterator);
171 }
172
173 @override
174 Iterable<E> skipWhile(bool Function(E value) test) {
175 return CachingIterable<E>(super.skipWhile(test).iterator);
176 }
177
178 @override
179 int get length {
180 _precacheEntireList();
181 return _results.length;
182 }
183
184 @override
185 List<E> toList({ bool growable = true }) {
186 _precacheEntireList();
187 return List<E>.of(_results, growable: growable);
188 }
189
190 void _precacheEntireList() {
191 while (_fillNext()) { }
192 }
193
194 bool _fillNext() {
195 if (!_prefillIterator.moveNext()) {
196 return false;
197 }
198 _results.add(_prefillIterator.current);
199 return true;
200 }
201}
202
203class _LazyListIterator<E> implements Iterator<E> {
204 _LazyListIterator(this._owner) : _index = -1;
205
206 final CachingIterable<E> _owner;
207 int _index;
208
209 @override
210 E get current {
211 assert(_index >= 0); // called "current" before "moveNext()"
212 if (_index < 0 || _index == _owner._results.length) {
213 throw StateError('current can not be call after moveNext has returned false');
214 }
215 return _owner._results[_index];
216 }
217
218 @override
219 bool moveNext() {
220 if (_index >= _owner._results.length) {
221 return false;
222 }
223 _index += 1;
224 if (_index == _owner._results.length) {
225 return _owner._fillNext();
226 }
227 return true;
228 }
229}
230
231/// A factory interface that also reports the type of the created objects.
232class Factory<T> {
233 /// Creates a new factory.
234 const Factory(this.constructor);
235
236 /// Creates a new object of type T.
237 final ValueGetter<T> constructor;
238
239 /// The type of the objects created by this factory.
240 Type get type => T;
241
242 @override
243 String toString() {
244 return 'Factory(type: $type)';
245 }
246}
247
248/// Linearly interpolate between two `Duration`s.
249Duration lerpDuration(Duration a, Duration b, double t) {
250 return Duration(
251 microseconds: (a.inMicroseconds + (b.inMicroseconds - a.inMicroseconds) * t).round(),
252 );
253}
254