spire_core/dataset/
data.rs1use std::fmt;
2use std::future::Future;
3use std::sync::Arc;
4
5use futures::future::BoxFuture;
6use futures::{FutureExt, Stream, stream};
7
8use crate::Result;
9use crate::dataset::Dataset;
10
11pub const READ_BATCH: usize = 1024;
13
14pub struct Data<T> {
16 inner: Arc<dyn DynDataset<T>>,
17}
18
19impl<T: Send + 'static> Data<T> {
20 #[must_use]
22 pub fn new(dataset: impl Dataset<T>) -> Self {
23 Self {
24 inner: Arc::new(dataset),
25 }
26 }
27
28 pub async fn write(&self, item: T) -> Result<()> {
34 self.inner.write(item).await
35 }
36
37 pub async fn write_all(&self, items: impl IntoIterator<Item = T>) -> Result<()> {
43 for item in items {
44 self.inner.write(item).await?;
45 }
46 Ok(())
47 }
48
49 pub async fn read(&self) -> Result<Option<T>> {
55 self.inner.read().await
56 }
57
58 pub async fn read_batch(&self, max: usize) -> Result<Vec<T>> {
64 self.inner.read_batch(max).await
65 }
66
67 pub async fn read_all(&self) -> Result<Vec<T>> {
74 let mut items = Vec::with_capacity(self.size_hint().unwrap_or_default());
75 loop {
76 let batch = self.inner.read_batch(READ_BATCH).await?;
77 let last = batch.len() < READ_BATCH;
78 items.extend(batch);
79 if last {
80 return Ok(items);
81 }
82 }
83 }
84
85 pub fn into_stream(self) -> impl Stream<Item = Result<T>> + Send {
90 stream::try_unfold(self, |data| async move {
91 let item = data.read().await?;
92 Ok(item.map(|item| (item, data)))
93 })
94 }
95
96 pub fn into_batches(self, max: usize) -> impl Stream<Item = Result<Vec<T>>> + Send {
99 let max = max.max(1);
100 stream::try_unfold((self, false), move |(data, drained)| async move {
101 if drained {
102 return Ok(None);
103 }
104 let batch = data.read_batch(max).await?;
105 if batch.is_empty() {
106 return Ok(None);
107 }
108 let drained = batch.len() < max;
109 Ok(Some((batch, (data, drained))))
110 })
111 }
112
113 #[must_use]
115 pub fn size_hint(&self) -> Option<usize> {
116 self.inner.size_hint()
117 }
118}
119
120impl<T> Clone for Data<T> {
121 fn clone(&self) -> Self {
122 Self {
123 inner: self.inner.clone(),
124 }
125 }
126}
127
128impl<T> fmt::Debug for Data<T> {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 f.debug_struct("Data")
131 .field("type", &std::any::type_name::<T>())
132 .finish_non_exhaustive()
133 }
134}
135
136impl<T: Send + 'static> Dataset<T> for Data<T> {
137 fn write(&self, item: T) -> impl Future<Output = Result<()>> + Send {
138 self.inner.write(item)
139 }
140
141 fn read(&self) -> impl Future<Output = Result<Option<T>>> + Send {
142 self.inner.read()
143 }
144
145 fn read_batch(&self, max: usize) -> impl Future<Output = Result<Vec<T>>> + Send {
146 self.inner.read_batch(max)
147 }
148
149 fn size_hint(&self) -> Option<usize> {
150 self.inner.size_hint()
151 }
152}
153
154trait DynDataset<T>: Send + Sync + 'static {
156 fn write(&self, item: T) -> BoxFuture<'_, Result<()>>;
157 fn read(&self) -> BoxFuture<'_, Result<Option<T>>>;
158 fn read_batch(&self, max: usize) -> BoxFuture<'_, Result<Vec<T>>>;
159 fn size_hint(&self) -> Option<usize>;
160}
161
162impl<T, D> DynDataset<T> for D
163where
164 T: Send + 'static,
165 D: Dataset<T>,
166{
167 fn write(&self, item: T) -> BoxFuture<'_, Result<()>> {
168 Dataset::write(self, item).boxed()
169 }
170
171 fn read(&self) -> BoxFuture<'_, Result<Option<T>>> {
172 Dataset::read(self).boxed()
173 }
174
175 fn read_batch(&self, max: usize) -> BoxFuture<'_, Result<Vec<T>>> {
176 Dataset::read_batch(self, max).boxed()
177 }
178
179 fn size_hint(&self) -> Option<usize> {
180 Dataset::size_hint(self)
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use futures::TryStreamExt;
187
188 use super::*;
189 use crate::dataset::InMemDataset;
190
191 #[tokio::test]
192 async fn batch_and_stream() {
193 let data = Data::new(InMemDataset::new());
194 data.write_all([1, 2, 3]).await.unwrap();
195 assert_eq!(data.size_hint(), Some(3));
196 assert_eq!(data.read().await.unwrap(), Some(1));
197 assert_eq!(
198 data.clone()
199 .into_stream()
200 .try_collect::<Vec<_>>()
201 .await
202 .unwrap(),
203 [2, 3]
204 );
205 assert_eq!(data.read_all().await.unwrap(), Vec::<i32>::new());
206 }
207
208 #[tokio::test]
209 async fn batches_stream_until_the_dataset_is_empty() {
210 let data = Data::new((1..=5).collect::<InMemDataset<u32>>());
211 let batches: Vec<Vec<u32>> = data.clone().into_batches(2).try_collect().await.unwrap();
212 assert_eq!(batches, [vec![1, 2], vec![3, 4], vec![5]]);
213
214 data.write_all([6, 7]).await.unwrap();
216 let batches: Vec<Vec<u32>> = data.clone().into_batches(2).try_collect().await.unwrap();
217 assert_eq!(batches, [vec![6, 7]]);
218 let batches: Vec<Vec<u32>> = data.into_batches(2).try_collect().await.unwrap();
219 assert_eq!(batches, Vec::<Vec<u32>>::new());
220 }
221}